Skip to content
Snippets Groups Projects
BamView.java 123 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
        int thisStart = thisRead.getAlignmentStart()+offset-baseAtStartOfView;
        int thisEnd   = thisRead.getAlignmentEnd()+offset-baseAtStartOfView;
    
           highlightSAMRecord.sam.getReadName().equals(thisRead.getReadName()))
    
           Stroke originalStroke = g2.getStroke();
           Stroke stroke =
    
             new BasicStroke (3.f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
    
           g2.setStroke(stroke);
    
           Color c = g2.getColor();
           g2.setColor(Color.black);
           g2.drawLine((int)( thisStart * pixPerBase), ypos,
                       (int)( thisEnd * pixPerBase), ypos);
           g2.setColor(c);
    
           g2.setStroke(originalStroke);
    
        if(thisRead.getCigar().getCigarElements().size() == 1)
    
          g2.drawLine((int)( thisStart * pixPerBase), ypos,
                      (int)( thisEnd * pixPerBase), ypos);
        else
        {
    
          List<AlignmentBlock> blocks = thisRead.getAlignmentBlocks();
    
          Color c = g2.getColor();
          int lastEnd = 0;
          for(int i=0; i<blocks.size(); i++)
          {
            AlignmentBlock block = blocks.get(i);
            int blockStart = block.getReferenceStart()+offset-baseAtStartOfView;
            int blockEnd = blockStart + block.getLength() - 1;
    
            g2.drawLine((int)( blockStart * pixPerBase), ypos,
                        (int)( blockEnd * pixPerBase), ypos);
            if(i > 0 && blockStart != lastEnd)
            {
              g2.setColor(Color.gray);
              g2.drawLine((int)( blockStart * pixPerBase), ypos,
                          (int)( lastEnd * pixPerBase), ypos);
              g2.setColor(c);
            }
            lastEnd = blockEnd;
          }
        }
    
        
        if(isOrientation)
          drawArrow(g2, thisRead, thisStart, thisEnd, pixPerBase, ypos);
    
    tjc's avatar
    tjc committed
    
    
        // test if the mouse is over this read
    
        if(lastMousePoint != null)
        {
          if(lastMousePoint.getY()+2 > ypos && lastMousePoint.getY()-2 < ypos)
          if(lastMousePoint.getX() > thisStart * pixPerBase &&
             lastMousePoint.getX() < thisEnd * pixPerBase)
          {
    
            mouseOverSAMRecord = bamViewRecord;
    
        if (isSNPs && snps != null)
          showSNPsOnReads(snps, g2, pixPerBase, ypos);
    
    tjc's avatar
    tjc committed
      }
      
    
      /**
       * Draw arrow on the read to indicate orientation.
       * @param g2
       * @param thisRead
       * @param thisStart
       * @param thisEnd
       * @param pixPerBase
       * @param ypos
       */
      private void drawArrow(Graphics2D g2,
                             SAMRecord thisRead, 
                             int thisStart, 
                             int thisEnd, 
                             float pixPerBase, 
                             int ypos)
      {
        if(thisRead.getReadNegativeStrandFlag())
        {
          int apos = ypos + 2;
          g2.drawLine((int)( (thisStart+5) * pixPerBase), apos,
                      (int)( thisStart * pixPerBase), ypos);
        }
        else
        {
          int apos = ypos - 2;
          g2.drawLine((int)( (thisEnd-5) * pixPerBase), apos,
                      (int)( thisEnd * pixPerBase), ypos);
        }  
      }
      
    
      /**
       * Highlight a selected range
       * @param g2
       * @param pixPerBase
       * @param start
       * @param end
       */
    
      private void drawSelectionRange(Graphics2D g2, float pixPerBase, int start, int end, Color c)
    
      {
        if(getSelection() != null)
        {
          Range selectedRange = getSelection().getSelectionRange();
    
          if(selectedRange != null)
          {
            int rangeStart = selectedRange.getStart();
            int rangeEnd   = selectedRange.getEnd();
            
            if(end < rangeStart || start > rangeEnd)
              return;
            
    
    tjc's avatar
    tjc committed
            int x = (int) (pixPerBase*(rangeStart-getBaseAtStartOfView()));
    
            int width = (int) (pixPerBase*(rangeEnd-rangeStart+1));
            
    
            g2.fillRect(x, 0, width, getHeight());
          }
        }
      }
      
    
      /**
       * Draw a translucent line
       * @param g2
       * @param start
       * @param end
       * @param ypos
       */
      private void drawTranslucentLine(Graphics2D g2, int start, int end, int ypos)
      {
        Composite origComposite = g2.getComposite();
        g2.setComposite(translucent);
        g2.drawLine(start, ypos, end, ypos);
        g2.setComposite(origComposite);
      }
      
      /**
       * Draw a translucent line
       * @param g2
       * @param start
       * @param end
       * @param ypos
       */
      private void drawTranslucentJointedLine(Graphics2D g2, int start, int end, int ypos)
      {
        Composite origComposite = g2.getComposite();
        g2.setComposite(translucent);
        
        int mid = (int) ((end-start)/2.f)+start;
        //g2.drawLine(start, ypos, end, ypos);
        g2.drawLine(start, ypos, mid, ypos-5);
        g2.drawLine(mid, ypos-5, end, ypos);
        g2.setComposite(origComposite);
      }
      
    
    tjc's avatar
    tjc committed
      /**
       * Display the SNPs for the given read.
    
    tjc's avatar
    tjc committed
       * @param g2
       * @param pixPerBase
       * @param ypos
       */
    
      private void showSNPsOnReads(final ArrayList<Integer> snps,
                                   final Graphics2D g2,
                                   float pixPerBase, int ypos)
    
    tjc's avatar
    tjc committed
      {
    
        g2.setColor(Color.red);
        for(int pos: snps)
          g2.drawLine((int) (pos * pixPerBase), ypos + 2,
                      (int) (pos * pixPerBase), ypos - 2);
      }
      
      
      /**
       * Get the SNP positions
       * @param samRecord
       */
      private ArrayList<Integer> getSNPs(final SAMRecord samRecord)
      {
        if(!isSNPs)  // return null if not displaying SNPs
          return null;
        int rbeg = samRecord.getAlignmentStart();
        int rend = samRecord.getAlignmentEnd();
        int offset = getSequenceOffset(samRecord.getReferenceName());
        ArrayList<Integer> snps = null;
    
        
        // use alignment blocks of the contiguous alignment of
        // subsets of read bases to a reference sequence
    
    tjc's avatar
    tjc committed
        try
    
    tjc's avatar
    tjc committed
        {
    
          final char[] refSeq = bases.getSubSequenceC(
              new Range(rbeg+offset, rend+offset), Bases.FORWARD);
          final byte[] readSeq = samRecord.getReadBases();
    
          offset = offset - getBaseAtStartOfView();
    
          final List<AlignmentBlock> blocks = samRecord.getAlignmentBlocks();
    
    tcarver's avatar
    tcarver committed
          for(AlignmentBlock block: blocks)
    
    tjc's avatar
    tjc committed
          {
    
            int readStart = block.getReadStart();
            int refStart  = block.getReferenceStart();
            int len = block.getLength();
            for(int j=0; j<len; j++)
    
    tjc's avatar
    tjc committed
            {
    
              int readPos = readStart-1+j;
              int refPos  = refStart+j;
              if (Character.toUpperCase(refSeq[refPos-rbeg]) != readSeq[readPos])
    
                if(snps == null)
                  snps = new ArrayList<Integer>();
                snps.add(refPos+offset);
    
    tjc's avatar
    tjc committed
            }
          }
    
    tjc's avatar
    tjc committed
        }
        catch (OutOfRangeException e)
        {
    
          System.err.println(samRecord.getReadName()+" "+e.getMessage());
    
    tjc's avatar
    tjc committed
        }
    
    tjc's avatar
    tjc committed
      }
      
    
      /**
       * Add the alignment view to the supplied <code>JPanel</code> in
       * a <code>JScrollPane</code>.
       * @param mainPanel  panel to add the alignment to
    
    tjc's avatar
    tjc committed
       * @param frame
    
       * @param autohide automatically hide the top panel containing the buttons
    
    tjc's avatar
    tjc committed
       * @param feature_display
    
    tjc's avatar
    tjc committed
      private void addBamToPanel(final JFrame frame)
    
    tjc's avatar
    tjc committed
      {
    
    tjc's avatar
    tjc committed
        final JComponent topPanel = bamTopPanel(frame);
    
    tjc's avatar
    tjc committed
        mainPanel.setPreferredSize(new Dimension(900, 400));
    
    tjc's avatar
    tjc committed
        
    
        setDisplay(1, nbasesInView, null);
        mainPanel.setLayout(new BorderLayout());
    
    tjc's avatar
    tjc committed
        if(topPanel instanceof JPanel)
          mainPanel.add(topPanel, BorderLayout.NORTH);
    
        mainPanel.add(jspView, BorderLayout.CENTER);
    
    tjc's avatar
    tjc committed
        JPanel bottomPanel = new JPanel(new BorderLayout());
        coveragePanel = new CoveragePanel(this);
        bottomPanel.add(coveragePanel, BorderLayout.CENTER);
    
    
    tjc's avatar
    tjc committed
        //
        snpPanel = new SnpPanel(this, bases);
        bottomPanel.add(snpPanel, BorderLayout.NORTH);
        
    
    tjc's avatar
    tjc committed
        if(feature_display == null)
        {
          scrollBar = new JScrollBar(JScrollBar.HORIZONTAL, 1, nbasesInView, 1,
              getMaxBasesInPanel(getSequenceLength()));
    
          scrollBar.setUnitIncrement(nbasesInView/20);
    
    tjc's avatar
    tjc committed
          scrollBar.addAdjustmentListener(new AdjustmentListener()
          {
            public void adjustmentValueChanged(AdjustmentEvent e)
            {
              repaint();
    
    
              if(isSNPplot)
                snpPanel.repaint();
              if(isCoverage)
                coveragePanel.repaint();
    
    tjc's avatar
    tjc committed
            }
          });
          bottomPanel.add(scrollBar, BorderLayout.SOUTH);
        }
    
          if(!isConcatSequences())
    
          {
            int seqLen = seqLengths.get((String) combo.getSelectedItem());
            int artemisSeqLen = feature_display.getSequenceLength();
            if(seqLen != artemisSeqLen)
            {
              int newIndex = -1;
              for(int i=0; i<seqNames.size(); i++)
              {
                if(seqLengths.get(seqNames.get(i)) == artemisSeqLen)
                {
                  // this looks like the correct sequence
                  combo.setSelectedIndex(i);
                  newIndex = i;
                }
              }
    
    
              if(!Options.isBlackBeltMode())
              {
                String label[] = {
                    "The length of the sequence loaded does not match the length of",
                    "the default reference sequence in the BAM ("+seqNames.get(0)+").",
                    (newIndex == -1 ? "" : "The length does match the reference "+
    
    tcarver's avatar
    tcarver committed
                        seqNames.get(newIndex)+" so this has been set as the default.") 
    
                };
                new NonModalDialog(frame, label);
              }
    
    tjc's avatar
    tjc committed
    
        mainPanel.add(bottomPanel, BorderLayout.SOUTH);
    
        coveragePanel.setPreferredSize(new Dimension(900, 100));
        coveragePanel.setVisible(false);
    
    tjc's avatar
    tjc committed
        snpPanel.setPreferredSize(new Dimension(900, 100));
        snpPanel.setVisible(false);
    
    
    tjc's avatar
    tjc committed
        mainPanel.revalidate();
    
    tjc's avatar
    tjc committed
        jspView.getVerticalScrollBar().setValue(
            jspView.getVerticalScrollBar().getMaximum());
    
      private void addToViewMenu(final short thisBamIndex)
    
        final File f = new File(bamList.get(thisBamIndex));
    
        final JCheckBoxMenuItem cbBam = new JCheckBoxMenuItem(
    
                                         f.getName(), 
                                         getImageIcon(getColourByCoverageColour(thisBamIndex)), 
                                         true);
    
        bamFilesMenu.add(cbBam);
    
    tcarver's avatar
    tcarver committed
        cbBam.addItemListener(new ItemListener() {
          public void itemStateChanged(ItemEvent e) {
    
            if(cbBam.isSelected())
              hideBamList.remove(new Integer(thisBamIndex));
            else
              hideBamList.add(new Integer(thisBamIndex));
            laststart = -1;
            repaint();
          } 
        });
      }
    
      /**
       * Refresh the colour of the icons used to identify the
       * BAM files.
       */
      protected void refreshColourOfBamMenu()
      {
        final Component cs[] = bamFilesMenu.getMenuComponents();
        for(Component c : cs)
        {
          if(c instanceof JCheckBoxMenuItem)
          {
            final JCheckBoxMenuItem cbBam = (JCheckBoxMenuItem) c;
    
    tcarver's avatar
    tcarver committed
            final Color col = getColorByJCheckBoxMenuItem(cbBam);
            if(col != null)
              cbBam.setIcon(getImageIcon(col));
    
    tcarver's avatar
    tcarver committed
      protected Color getColorByJCheckBoxMenuItem(JCheckBoxMenuItem cbBam)
      {
        final String bam = cbBam.getText();
    
        for(short i=0; i<bamList.size(); i++)
    
    tcarver's avatar
    tcarver committed
        {
          final File f = new File(bamList.get(i));
          if(f.getName().equals(bam))
            return getColourByCoverageColour(i);
        }
        return null;
      }
      
    
      /**
       * Create an icon of a box using the given colour.
       * @param c
       * @return
       */
    
    tcarver's avatar
    tcarver committed
      protected ImageIcon getImageIcon(Color c)
    
      {
        BufferedImage image = (BufferedImage)this.createImage(10, 10);
        Graphics2D g2 = image.createGraphics();
        g2.setColor(c);
        g2.fillRect(0, 0, 10, 10);
        return new ImageIcon(image);
      }
    
    
      private void createMenus(JComponent menu)
    
        final JMenuItem addBam = new JMenuItem("Add BAM ...");
    
        menu.add(addBam);
        addBam.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
    
            FileSelectionDialog bamFileSelection = new FileSelectionDialog(
                null, false, "BamView", "BAM");
    
    tcarver's avatar
    tcarver committed
            List<String> bamFiles = bamFileSelection.getFiles(BAM_SUFFIX);
    
            short count = (short) bamList.size();
    
    tcarver's avatar
    tcarver committed
            bamList.addAll(bamFileSelection.getFiles(BAM_SUFFIX));
    
            for(short i=0; i<bamFiles.size(); i++)
              addToViewMenu((short) (i+count));
    
    tjc's avatar
    tjc committed
            laststart = -1; 
    
            repaint();
          } 
        });
        
        bamFilesMenu.setFont(addBam.getFont());
    
    tcarver's avatar
    tcarver committed
        
        final JMenuItem groupBams = new JMenuItem("Group BAMs ...");
        final GroupBamFrame groupsFrame = new GroupBamFrame(this, bamFilesMenu);
        groupBams.addActionListener(new ActionListener(){
          public void actionPerformed(ActionEvent arg0)
          {
            groupsFrame.updateAndDisplay();
          }
        });
        bamFilesMenu.add(groupBams);
        bamFilesMenu.addSeparator();
    
        menu.add(bamFilesMenu);
    
        
        final JMenu analyse = new JMenu("Analyse");
        menu.add(analyse);
    
    tjc's avatar
    tjc committed
        final JMenuItem readCount = new JMenuItem("Read count of selected features ...");
    
        analyse.add(readCount);
    
        if(feature_display == null)
          readCount.setEnabled(false);
    
        readCount.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            FeatureVector features = feature_display.getSelection().getAllFeatures();
    
            JCheckBox overlap = new JCheckBox("Include all overlapping reads", true);
            overlap.setToolTipText("Include reads that partially overlap the feature");
            JCheckBox spliced = new JCheckBox("Introns included", true);
            Box yBox = Box.createVerticalBox();
            yBox.add(overlap);
            yBox.add(spliced);
    
    tcarver's avatar
    tcarver committed
            
            final ReadCountDialog opts = new ReadCountDialog(new JFrame(),
                "Read Count Options", feature_display, yBox);
            if(opts.getStatus() == -1)
              return;
            //JOptionPane.showMessageDialog(null, yBox, "Read Count Option", JOptionPane.INFORMATION_MESSAGE);
    
            new MappedReads(features, (String)combo.getSelectedItem(), samFileReaderHash, bamList,
    
                seqNames, offsetLengths, concatSequences, seqLengths, 
                samRecordFlagPredicate, samRecordMapQPredicate,
    
                !overlap.isSelected(), spliced.isSelected());
    
    tjc's avatar
    tjc committed
          } 
        });
        
        final JMenuItem rpkm = new JMenuItem("RPKM value of selected features ...");
        analyse.add(rpkm);
    
        if(feature_display == null)
          rpkm.setEnabled(false);
    
    tjc's avatar
    tjc committed
        rpkm.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
    
    tcarver's avatar
    tcarver committed
            final FeatureVector features = feature_display.getSelection().getAllFeatures();
    
    tjc's avatar
    tjc committed
            JCheckBox overlap = new JCheckBox("Include all overlapping reads", true);
            overlap.setToolTipText("Include reads that partially overlap the feature");
            JCheckBox spliced = new JCheckBox("Introns included", true);
    
            JCheckBox allRefSeqs = new JCheckBox("Use reads mapped to all reference sequences", false);
            
    
    tjc's avatar
    tjc committed
            Box yBox = Box.createVerticalBox();
            yBox.add(overlap);
            yBox.add(spliced);
    
            
            if(seqLengths.size() > 1)
              yBox.add(allRefSeqs);
    
    tcarver's avatar
    tcarver committed
         
            final ReadCountDialog opts = new ReadCountDialog(new JFrame(),
                "RPKM Options", feature_display, yBox);
            if(opts.getStatus() == -1)
              return;
    
    
    tjc's avatar
    tjc committed
            int seqlen = 0;
            if(feature_display != null)
              seqlen = feature_display.getSequenceLength();
            else if(bases != null)
              seqlen = bases.getLength();
    
            
            new MappedReads(features, (String)combo.getSelectedItem(),
                samFileReaderHash, bamList, seqNames, offsetLengths, concatSequences, 
    
                seqLengths, seqlen, samRecordFlagPredicate, samRecordMapQPredicate,
                !overlap.isSelected(), spliced.isSelected(), allRefSeqs.isSelected());
    
    tcarver's avatar
    tcarver committed
        
        
        
        final JMenuItem createFeatures = new JMenuItem("Create features from coverage peaks ...");
        analyse.add(createFeatures);
    
        if(feature_display == null)
          createFeatures.setEnabled(false);
    
    tcarver's avatar
    tcarver committed
        createFeatures.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            if(feature_display == null)
              return;
    
            new CreateFeatures(groupsFrame);
    
        for(short i=0; i<bamList.size(); i++)
    
          addToViewMenu(i);
        
        menu.add(new JSeparator());
        
    
        JMenu viewMenu = new JMenu("Views");
    
    tjc's avatar
    tjc committed
        cbStackView.setFont(viewMenu.getFont());
        cbIsizeStackView.setFont(viewMenu.getFont());
        cbPairedStackView.setFont(viewMenu.getFont());
        cbStrandStackView.setFont(viewMenu.getFont());
        cbCoverageView.setFont(viewMenu.getFont());
    
        cbCoverageStrandView.setFont(viewMenu.getFont());
    
    tjc's avatar
    tjc committed
        
        baseQualityColour.setFont(viewMenu.getFont());
        colourByCoverageColour.setFont(viewMenu.getFont());
        markInsertions.setFont(viewMenu.getFont());
    
        
        cbIsizeStackView.addActionListener(new ActionListener()
    
    tjc's avatar
    tjc committed
        {
          public void actionPerformed(ActionEvent e)
          {
            laststart = -1;
    
            logMenuItem.setEnabled(isIsizeStackView());
    
    tjc's avatar
    tjc committed
            repaint();
          }
        });
    
        viewMenu.add(cbIsizeStackView);
    
        cbStackView.addActionListener(new ActionListener()
    
    tjc's avatar
    tjc committed
        {
          public void actionPerformed(ActionEvent e)
          {
            laststart = -1;
    
            logMenuItem.setEnabled(isIsizeStackView());
    
    tjc's avatar
    tjc committed
            repaint();
          }
        });
    
        viewMenu.add(cbStackView);
    
        cbPairedStackView.addActionListener(new ActionListener()
    
        {
          public void actionPerformed(ActionEvent e)
          {
            laststart = -1;
    
            logMenuItem.setEnabled(isIsizeStackView());
    
        viewMenu.add(cbPairedStackView);
    
        cbStrandStackView.addActionListener(new ActionListener()
    
    tjc's avatar
    tjc committed
        {
          public void actionPerformed(ActionEvent e)
          {
            laststart = -1;
    
            if(isStrandStackView())
    
    tjc's avatar
    tjc committed
              setViewportMidPoint();
    
            logMenuItem.setEnabled(isIsizeStackView());
    
    tjc's avatar
    tjc committed
            repaint();
          }
        });
    
        viewMenu.add(cbStrandStackView);
        
        cbCoverageView.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            laststart = -1;
    
            logMenuItem.setEnabled(isIsizeStackView());
    
            if(cbCoverageView.isSelected())
            {
    
              coverageView.setPlotByStrand(false);
              setViewportBtm();
    
            repaint();
          }
        });
        viewMenu.add(cbCoverageView);
        
    
        cbCoverageStrandView.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            laststart = -1;
            logMenuItem.setEnabled(isIsizeStackView());
            if(cbCoverageStrandView.isSelected())
            {
              coverageView.setPlotByStrand(true);
              setViewportBtm();
            }
            repaint();
          }
        });
        viewMenu.add(cbCoverageStrandView);
        
    
        menu.add(viewMenu);
    
    tjc's avatar
    tjc committed
        final JCheckBoxMenuItem checkBoxSNPs = new JCheckBoxMenuItem("SNP marks");
    
        // 
        JMenu colourMenu = new JMenu("Colour By");
        colourMenu.add(colourByCoverageColour);
        
        baseQualityColour.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            if(baseQualityColour.isSelected())
            {
              checkBoxSNPs.setSelected(false);
              isSNPs = false;
            }
            repaint();
          }
        });
        colourMenu.add(baseQualityColour);
        menu.add(colourMenu);
        
        //
    
        JMenu showMenu = new JMenu("Show");
    
        JCheckBoxMenuItem checkBoxOrientation = new JCheckBoxMenuItem("Orientation");
        checkBoxOrientation.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            isOrientation = !isOrientation;
            repaint();
          }
        });
        showMenu.add(checkBoxOrientation);
        
    
        JCheckBoxMenuItem checkBoxSingle = new JCheckBoxMenuItem("Single Reads");
        checkBoxSingle.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            repaint();
            isSingle = !isSingle;
          }
        });
        showMenu.add(checkBoxSingle);
    
        checkBoxSNPs.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            if (isSNPs && bases == null)
            {
              JOptionPane.showMessageDialog(null,
                  "No reference sequence supplied to identify SNPs.", "SNPs",
                  JOptionPane.INFORMATION_MESSAGE);
            }
            isSNPs = !isSNPs;
            
            if(isSNPs)
              baseQualityColour.setSelected(false);
            repaint();
          }
        });
        showMenu.add(checkBoxSNPs);
    
        
        markInsertions.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            repaint();
          }
        });
        showMenu.add(markInsertions);
    
    tjc's avatar
    tjc committed
        menu.add(showMenu);
    
    tjc's avatar
    tjc committed
        //
        JMenu graphMenu = new JMenu("Graph");
    
        JCheckBoxMenuItem checkBoxCoverage = new JCheckBoxMenuItem("Coverage");
        checkBoxCoverage.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            isCoverage = !isCoverage;
            coveragePanel.setVisible(isCoverage);
    
    tjc's avatar
    tjc committed
            
    
            if( isCoverage && 
                !cbCoverageView.isSelected() && 
                !cbCoverageStrandView.isSelected() )
    
    tjc's avatar
    tjc committed
              laststart = -1;
    
            repaint();
          }
        });
    
    tjc's avatar
    tjc committed
        graphMenu.add(checkBoxCoverage);
        
        JCheckBoxMenuItem checkBoxSNP = new JCheckBoxMenuItem("SNP");
        checkBoxSNP.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            isSNPplot = !isSNPplot;
            snpPanel.setVisible(isSNPplot);
    
            laststart = -1;
    
    tjc's avatar
    tjc committed
            repaint();
          }
        });
        graphMenu.add(checkBoxSNP);
        menu.add(graphMenu);
        
    
        if(feature_display != null)
    
          final JCheckBoxMenuItem checkBoxSync =
            new JCheckBoxMenuItem("Asynchronous", asynchronous);
          checkBoxSync.addActionListener(new ActionListener()
    
            public void actionPerformed(ActionEvent e)
            {
              asynchronous = checkBoxSync.isSelected();
            }
          });
    
          menu.add(checkBoxSync);
    
        menu.add(new JSeparator());
    
        JMenu maxHeightMenu = new JMenu("BamView Height");
    
        menu.add(maxHeightMenu);
    
        final String hgts[] =
           {"500", "800", "1000", "1500", "2500", "5000", "50000"};
    
        
        ButtonGroup bgroup = new ButtonGroup();
        for(int i=0; i<hgts.length; i++)
        {
          final String hgt = hgts[i];
          final JCheckBoxMenuItem maxHeightMenuItem = new JCheckBoxMenuItem(hgt);
          bgroup.add(maxHeightMenuItem);
          maxHeightMenuItem.setSelected(hgts[i].equals(Integer.toString(maxHeight)));
          maxHeightMenu.add(maxHeightMenuItem);
          maxHeightMenuItem.addActionListener(new ActionListener()
          {
            public void actionPerformed(ActionEvent e)
            {
              if(maxHeightMenuItem.isSelected())
                maxHeight = Integer.parseInt(hgt);
              int start = getBaseAtStartOfView();
              setDisplay(start, nbasesInView+start, null);
            }
          });
        }
    
        menu.add(new JSeparator());
    
    tjc's avatar
    tjc committed
        logMenuItem.setFont(menu.getFont());
    
        menu.add(logMenuItem);
    
        logMenuItem.setEnabled(isIsizeStackView());
        
    
        logMenuItem.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            logScale = logMenuItem.isSelected();
            repaint();
          }
        });
        
    
    tjc's avatar
    tjc committed
        JMenuItem filter = new JMenuItem("Filter Reads ...");
    
        menu.add(filter);
        filter.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
    
    tjc's avatar
    tjc committed
            if(filterFrame == null)
              filterFrame = new SAMRecordFilter(BamView.this);
            else
              filterFrame.setVisible(true);
    
    tcarver's avatar
    tcarver committed
        
    
        JMenuItem maxReadCoverage = new JMenuItem("Read Coverage Threshold ...");
        menu.add(maxReadCoverage);
        maxReadCoverage.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            final TextFieldInt maxRead = new TextFieldInt();
            maxRead.setValue(MAX_COVERAGE);
            int status = JOptionPane.showConfirmDialog(null, maxRead, 
                "Read Coverage Threshold", JOptionPane.OK_CANCEL_OPTION);
            if(status == JOptionPane.OK_OPTION &&
               maxRead.getValue() != MAX_COVERAGE)
            {
              MAX_COVERAGE = maxRead.getValue();
              if(MAX_COVERAGE < 1)
                MAX_COVERAGE = Integer.MAX_VALUE;
              laststart = -1;
              repaint();
            }
          } 
        });
        
    
    tcarver's avatar
    tcarver committed
        JMenuItem readList = new JMenuItem("List Reads ...");
    
    tcarver's avatar
    tcarver committed
        menu.add(readList);
        readList.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
    
    tcarver's avatar
    tcarver committed
            new SAMRecordList(BamView.this);
    
    tcarver's avatar
    tcarver committed
          }
    
    tcarver's avatar
    tcarver committed
        });
    
    tjc's avatar
    tjc committed
        final JMenuItem bamSplitter = new JMenuItem("Clone window");
        bamSplitter.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
    
            BamView bamView = new BamView(new Vector<String>(bamList), 
                null, nbasesInView, entry_edit,
    
    tjc's avatar
    tjc committed
                feature_display, bases, (JPanel) mainPanel.getParent(), null);
            bamView.getJspView().getVerticalScrollBar().setValue(
                bamView.getJspView().getVerticalScrollBar().getMaximum());
    
            int start = getBaseAtStartOfView();
            setDisplay(start, nbasesInView+start, null);
            if(feature_display != null)
            {
              feature_display.addDisplayAdjustmentListener(bamView);
              feature_display.getSelection().addSelectionChangeListener(bamView);
            }
          } 
        });
        menu.add(new JSeparator());
        menu.add(bamSplitter);
    
    
        //
        JMenu coverageMenu = new JMenu("Coverage Options");
        coverageView.init(this, 0.f, 0, 0);
    
        coverageView.createMenus(coverageMenu);
    
        viewMenu.add(new JSeparator());
        viewMenu.add(coverageMenu);
    
    tjc's avatar
    tjc committed
      private JComponent bamTopPanel(final JFrame frame)
      {
        final JComponent topPanel;
    
    tjc's avatar
    tjc committed
        if(frame == null)
    
    tjc's avatar
    tjc committed
        {
          topPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
    
          if(feature_display != null)
            this.selection = feature_display.getSelection(); 
    
    tjc's avatar
    tjc committed
        }
        else
        { 
          topPanel = new JMenuBar();
          frame.setJMenuBar((JMenuBar)topPanel);
          
          JMenu fileMenu = new JMenu("File");
          topPanel.add(fileMenu);
    
          JMenuItem readBam = new JMenuItem("Open new BamView ...");
          fileMenu.add(readBam);
          readBam.addActionListener(new ActionListener()
          {
            public void actionPerformed(ActionEvent e)
            {
    
              String[] s = { "NEW-BAMVIEW" };
    
    tjc's avatar
    tjc committed
              BamView.main(s);
            } 
          });
          
          JMenuItem close = new JMenuItem("Close");
          fileMenu.add(close);
          close.addActionListener(new ActionListener()
          {
            public void actionPerformed(ActionEvent e)
            {
              BamView.this.setVisible(false);
              Component comp = BamView.this;
              
              while( !(comp instanceof JFrame) )
                comp = comp.getParent();
              ((JFrame)comp).dispose();
            } 
          });
          
          JMenuItem exit = new JMenuItem("Exit");
          fileMenu.add(new JSeparator());
          fileMenu.add(exit);
          exit.addActionListener(new ActionListener()
          {
            public void actionPerformed(ActionEvent e)
            {
              int status = JOptionPane.showConfirmDialog(BamView.this, 
                  "Exit BamView?", "Exit", 
                  JOptionPane.OK_CANCEL_OPTION);
              if(status != JOptionPane.OK_OPTION)
                return;
              System.exit(0);
            } 
          });
          
          addKeyListener(new KeyAdapter()
          {
            public void keyPressed(final KeyEvent event)
            {
              switch (event.getKeyCode())
              {
                case KeyEvent.VK_UP:
                  setZoomLevel((int) (BamView.this.nbasesInView * 1.1));
                  break;
                case KeyEvent.VK_DOWN:
                  if (showBaseAlignment)
                    break;
                  setZoomLevel((int) (BamView.this.nbasesInView * .9));
                  break;
                default:
                  break;
              }
            }
          });
        }
        
        if(seqNames.size() > 1)
        {
          int len = 0;
          for(int i=0; i<seqNames.size(); i++)
            len += seqLengths.get(seqNames.get(i));
          
          if(feature_display != null &&
             len == feature_display.getSequenceLength())
            concatSequences = true;
          else if(bases != null &&
              len == bases.getLength() )
            concatSequences = true;
        }
    
        // auto hide top panel
    
    tjc's avatar
    tjc committed
        final JCheckBox buttonAutoHide = new JCheckBox("Hide", (frame == null));
    
    tjc's avatar
    tjc committed
        buttonAutoHide.setToolTipText("Auto-Hide");
        final MouseMotionListener mouseMotionListener = new MouseMotionListener()
        {
          public void mouseDragged(MouseEvent event)
          {
            handleCanvasMouseDrag(event);
          }
          
          public void mouseMoved(MouseEvent e)
          {
            lastMousePoint = e.getPoint();
            
            int thisHgt = HEIGHT;
            if (thisHgt < 5)
              thisHgt = 15;
    
            int y = (int) (e.getY() - jspView.getViewport().getViewRect().getY());
            if (y < thisHgt)
            {
              topPanel.setVisible(true);
            }
            else
            {
              if (buttonAutoHide.isSelected())
                topPanel.setVisible(false);
            }
            mainPanel.repaint();
            mainPanel.revalidate();
          }
        };
        addMouseMotionListener(mouseMotionListener);
    
        combo = new JComboBox(seqNames);
    
        JTextComponent editor = (JTextComponent) combo.getEditor().getEditorComponent();
        editor.setDocument(new AutoCompleteComboDocument(combo));
        combo.setEditable(true);
    
    tjc's avatar
    tjc committed
        combo.setMaximumRowCount(20);
        
        combo.addItemListener(new ItemListener()
        {
          public void itemStateChanged(ItemEvent e)
          {
            laststart = -1;
            if(feature_display != null)
              setZoomLevel(feature_display.getMaxVisibleBases());
            else
              setZoomLevel(BamView.this.nbasesInView);
          }
        });
        topPanel.add(combo);
    
        if(feature_display == null)
        {
          final JTextField baseText = new JTextField(8);
          JButton goTo = new JButton("GoTo:");
          goTo.setToolTipText("Go to base position");
          goTo.addActionListener(new ActionListener()
          {
            public void actionPerformed(ActionEvent e)