Skip to content
Snippets Groups Projects
JamView.java 45.4 KiB
Newer Older
  • Learn to ignore specific revisions
  •     combo.setEditable(false);
    
        combo.addItemListener(new ItemListener()
        {
          public void itemStateChanged(ItemEvent e)
          {
            laststart = -1;
            lastend = -1;
            setZoomLevel(JamView.this.nbasesInView);
          }
        });
        gc.fill = GridBagConstraints.NONE;
        gc.anchor = GridBagConstraints.NORTHWEST;
        topPanel.add(combo, gc);
    
    
    tjc's avatar
    tjc committed
        checkBoxSingle = new JCheckBox("Single Reads");
        checkBoxSingle.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            repaint();
          }
        });
    
        topPanel.add(checkBoxSingle, gc);
    
    tjc's avatar
    tjc committed
        checkBoxSNPs = new JCheckBox("SNPs");
        checkBoxSNPs.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
    
            if (checkBoxSNPs.isSelected() && bases == null)
    
            {
              JOptionPane.showMessageDialog(null,
    
                  "No reference sequence supplied to identify SNPs.", "SNPs",
                  JOptionPane.INFORMATION_MESSAGE);
    
    tjc's avatar
    tjc committed
            repaint();
          }
        });
    
        topPanel.add(checkBoxSNPs, gc);
    
        
        checkBoxStackView = new JCheckBox("Stack");
        checkBoxStackView.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            laststart = -1;
            lastend = -1;
            repaint();
          }
        });
        topPanel.add(checkBoxStackView, gc);
    
        if(feature_display == null)
    
    tjc's avatar
    tjc committed
        {
    
          final JTextField baseText = new JTextField(10);
          JButton goTo = new JButton("GoTo:");
          goTo.addActionListener(new ActionListener()
    
    tjc's avatar
    tjc committed
          {
    
            public void actionPerformed(ActionEvent e)
    
    tjc's avatar
    tjc committed
            {
    
              try
              {
                int basePosition = Integer.parseInt(baseText.getText());
                goToBasePosition(basePosition);
              }
              catch (NumberFormatException nfe)
              {
                JOptionPane.showMessageDialog(JamView.this,
                    "Expecting a base number!", "Number Format",
                    JOptionPane.WARNING_MESSAGE);
              }
    
    tjc's avatar
    tjc committed
            }
    
          });
          topPanel.add(goTo, gc);
          topPanel.add(baseText, gc);
    
    
          JButton zoomIn = new JButton("-");
          Insets ins = new Insets(1,1,1,1);
    
          zoomIn.setMargin(ins);
    
          zoomIn.addActionListener(new ActionListener()
    
    tjc's avatar
    tjc committed
          {
    
            public void actionPerformed(ActionEvent e)
            {
              int startBase = getBaseAtStartOfView();
              setZoomLevel((int) (JamView.this.nbasesInView * 1.1));
              goToBasePosition(startBase);
            }
          });
          topPanel.add(zoomIn, gc);
    
    
          JButton zoomOut = new JButton("+");
          zoomOut.setMargin(ins);
    
          zoomOut.addActionListener(new ActionListener()
    
    tjc's avatar
    tjc committed
          {
    
            public void actionPerformed(ActionEvent e)
            {
              if (showBaseAlignment)
                return;
              int startBase = getBaseAtStartOfView();
              setZoomLevel((int) (JamView.this.nbasesInView * .9));
              goToBasePosition(startBase);
            }
          });
          topPanel.add(zoomOut, gc);
        }
    
        
        topPanel.add(buttonAutoHide, gc);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        mainPanel.setPreferredSize(new Dimension(900, 400));
    
    tjc's avatar
    tjc committed
        
        jspView = new JScrollPane(this, 
            JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
    
    tjc's avatar
    tjc committed
            JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    
        setDisplay(1, nbasesInView, null);
        mainPanel.setLayout(new BorderLayout());
    
    
        mainPanel.add(topPanel, BorderLayout.NORTH);
    
        mainPanel.add(jspView, BorderLayout.CENTER);
    
    tjc's avatar
    tjc committed
    
        jspView.getVerticalScrollBar().setValue(
            jspView.getVerticalScrollBar().getMaximum());
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        if(feature_display == null)
    
    tjc's avatar
    tjc committed
        {
    
          addKeyListener(new KeyAdapter()
    
    tjc's avatar
    tjc committed
          {
    
            public void keyPressed(final KeyEvent event)
    
    tjc's avatar
    tjc committed
            {
    
              switch (event.getKeyCode())
              {
    
    tjc's avatar
    tjc committed
              case KeyEvent.VK_UP:
    
    tjc's avatar
    tjc committed
                int startBase = getBaseAtStartOfView();
    
                setZoomLevel((int) (JamView.this.nbasesInView * 1.1));
    
    tjc's avatar
    tjc committed
                goToBasePosition(startBase);
    
    tjc's avatar
    tjc committed
                break;
              case KeyEvent.VK_DOWN:
    
                if (showBaseAlignment)
                  break;
    
    tjc's avatar
    tjc committed
                startBase = getBaseAtStartOfView();
    
                setZoomLevel((int) (JamView.this.nbasesInView * .9));
    
    tjc's avatar
    tjc committed
                goToBasePosition(startBase);
    
    tjc's avatar
    tjc committed
                break;
              default:
                break;
    
    tjc's avatar
    tjc committed
            }
    
        addMouseListener(new PopupListener());
    
    tjc's avatar
    tjc committed
        setFocusable(true);
        requestFocusInWindow();
    
        addFocusListener(new FocusListener()
    
    tjc's avatar
    tjc committed
        {
    
          public void focusGained(FocusEvent fe){}
          public void focusLost(FocusEvent fe){}
    
    tjc's avatar
    tjc committed
        });
    
      }
      
      /**
       * Check to see if this component is contained by the display
       * (FeatureDisplay) component.
       * @return
       */
      private boolean containsComponent(JPanel topPanel, JPanel mainPanel)
      {
        Component[] c = mainPanel.getComponents();
        for(int i=0; i<c.length; i++)
    
          if(c[i].equals(topPanel))
            return true;
        }
        
        return false;
    
      }
      
      public void setVisible(boolean visible)
      {
        super.setVisible(visible);
        mainPanel.setVisible(visible);
    
    tjc's avatar
    tjc committed
      }
      
    
    tjc's avatar
    tjc committed
      private int getBaseAtStartOfView()
      {
        String refName = (String) combo.getSelectedItem();
        int seqLength = seqLengths.get(refName);
        double x = jspView.getViewport().getViewRect().getX();
    
        return (int) (getMaxBasesInPanel(seqLength) * ( x / getWidth())) + 1;
    
    tjc's avatar
    tjc committed
      }
      
      /**
       * Set the panel size based on the number of bases visible
       * and repaint.
       * @param nbasesInView
       */
    
    tjc's avatar
    tjc committed
      private void setZoomLevel(final int nbasesInView)
      {
        this.nbasesInView = nbasesInView;
    
    tjc's avatar
    tjc committed
    
    
        //System.out.println("setZoomLevel "+nbasesInView+"  "+getBaseAtStartOfView());
    
    tjc's avatar
    tjc committed
        String refName = (String) combo.getSelectedItem();
        int seqLength = seqLengths.get(refName);
    
    tjc's avatar
    tjc committed
        float pixPerBase = getPixPerBaseByBasesInView(); 
    
        if(pixPerBase*3 > ALIGNMENT_PIX_PER_BASE)
    
    tjc's avatar
    tjc committed
        {
          pixPerBase = ALIGNMENT_PIX_PER_BASE;
          checkBoxSingle.setVisible(false);
          jspView.getVerticalScrollBar().setValue(0);
          jspView.setColumnHeaderView(ruler);
          showBaseAlignment = true;
        }
        else if(jspView != null)
        {
          checkBoxSingle.setVisible(true);
          jspView.setColumnHeaderView(null);
          showBaseAlignment = false;
        }
        
        Dimension d = new Dimension();
    
        d.setSize((getMaxBasesInPanel(seqLength)*pixPerBase), 800.d);
    
    tjc's avatar
    tjc committed
        setPreferredSize(d);
    
    tjc's avatar
    tjc committed
        revalidate();
    
    tjc's avatar
    tjc committed
      }
      
      /**
       * Set the ViewPort so it starts at the given base position.
       * @param base
       */
    
    tjc's avatar
    tjc committed
      private void goToBasePosition(int base)
    
    tjc's avatar
    tjc committed
      {
        Point p = jspView.getViewport().getViewPosition();
    
    tjc's avatar
    tjc committed
        String refName = (String) combo.getSelectedItem();
        int seqLength = seqLengths.get(refName);
    
    tjc's avatar
    tjc committed
        
    
    tjc's avatar
    tjc committed
        float width = (float) getPreferredSize().getWidth();
    
    tjc's avatar
    tjc committed
        
    
        p.x = Math.round(width*((float)(base-1)/(getMaxBasesInPanel(seqLength))));
        //System.out.println("goToBasePosition "+base);
    
    tjc's avatar
    tjc committed
        jspView.getViewport().setViewPosition(p);
      }
    
    tjc's avatar
    tjc committed
      /**
    
       * Set the start and end base positions to display.
       * @param start
       * @param end
       * @param event
    
    tjc's avatar
    tjc committed
       */
    
      public void setDisplay(int start,
                             int end,
                             DisplayAdjustmentEvent event)
    
    tjc's avatar
    tjc committed
      {
    
        this.startBase = start;
        this.endBase   = end;
    
    tjc's avatar
    tjc committed
        this.nbasesInView = end-start+1;
    
    tjc's avatar
    tjc committed
        String refName = (String) combo.getSelectedItem();
        int seqLength = seqLengths.get(refName);
    
    tjc's avatar
    tjc committed
        float pixPerBase;
        if(jspView.getViewport().getViewRect().width > 0)
    
          pixPerBase = this.getPixPerBaseByWidth(); // getPixPerBaseByBasesInView();
    
    tjc's avatar
    tjc committed
        else
        {
          if(feature_display == null)
            pixPerBase = 1000.f/(float)(end-start+1);
          else
            pixPerBase = feature_display.getWidth()/(float)(end-start+1);
        }
    
        if(pixPerBase*3 > ALIGNMENT_PIX_PER_BASE)
    
    tjc's avatar
    tjc committed
        {
    
    tjc's avatar
    tjc committed
          pixPerBase = ALIGNMENT_PIX_PER_BASE;
    
    tjc's avatar
    tjc committed
          checkBoxSingle.setVisible(false);
    
    tjc's avatar
    tjc committed
          jspView.getVerticalScrollBar().setValue(0);
    
    tjc's avatar
    tjc committed
          jspView.setColumnHeaderView(ruler);
    
          showBaseAlignment = true;
    
    tjc's avatar
    tjc committed
        }
    
    tjc's avatar
    tjc committed
        else if(jspView != null)
    
    tjc's avatar
    tjc committed
        {
          checkBoxSingle.setVisible(true);
    
    tjc's avatar
    tjc committed
          jspView.setColumnHeaderView(null);
    
          showBaseAlignment = false;
    
    tjc's avatar
    tjc committed
        }
    
    tjc's avatar
    tjc committed
        Dimension d = new Dimension();
    
        d.setSize((getMaxBasesInPanel(seqLength)*pixPerBase), 800.d);
        
        //System.out.println("setDisplay() "+d.getWidth());
    
    tjc's avatar
    tjc committed
        setPreferredSize(d);
    
        goToBasePosition(startBase);
        
    
    tjc's avatar
    tjc committed
        if(event == null)
        {
          this.startBase = -1;
          this.endBase   = -1;
        }
    
    tjc's avatar
    tjc committed
      /**
       * Return an Artemis entry from a file 
       * @param entryFileName
       * @param entryGroup
       * @return
       * @throws NoSequenceException
       */
      private Entry getEntry(final String entryFileName, final EntryGroup entryGroup) 
                       throws NoSequenceException
      {
        final Document entry_document = DocumentFactory.makeDocument(entryFileName);
        final EntryInformation artemis_entry_information =
          Options.getArtemisEntryInformation();
        
    
        //System.out.println(entryFileName);
    
    tjc's avatar
    tjc committed
        final uk.ac.sanger.artemis.io.Entry new_embl_entry =
          EntryFileDialog.getEntryFromFile(null, entry_document,
                                           artemis_entry_information,
                                           false);
    
        if(new_embl_entry == null)  // the read failed
          return null;
    
        Entry entry = null;
        try
        {
          if(entryGroup.getSequenceEntry() != null)
            bases = entryGroup.getSequenceEntry().getBases();
    
    tjc's avatar
    tjc committed
          
    
    tjc's avatar
    tjc committed
          if(bases == null)
    
    tjc's avatar
    tjc committed
          {
    
    tjc's avatar
    tjc committed
            entry = new Entry(new_embl_entry);
    
    tjc's avatar
    tjc committed
            bases = entry.getBases();
          }
    
    tjc's avatar
    tjc committed
          else
            entry = new Entry(bases,new_embl_entry);
          
          entryGroup.add(entry);
        } 
        catch(OutOfRangeException e) 
        {
          new MessageDialog(null, "read failed: one of the features in " +
              entryFileName + " has an out of range " +
                            "location: " + e.getMessage());
        }
        return entry;
      }
    
      
      private boolean isShowScale()
      {
        return showScale;
      }
    
      public void setShowScale(boolean showScale)
      {
        this.showScale = showScale;
      }
      
      public JScrollPane getJspView()
      {
        return jspView;
      }
      
      public void setBases(Bases bases)
      {
        this.bases = bases;
      }
      
      /**
       * Remove JScrollPane border
       */
      public void removeBorder()
      {
        Border empty = new EmptyBorder(0,0,0,0);
        jspView.setBorder(empty);
      }
      
      /**
       *  Handle a mouse drag event on the drawing canvas.
       **/
    
      private void handleCanvasMouseDragOrClick(final MouseEvent event)
    
        if(!showBaseAlignment || event.isShiftDown()) 
    
    tjc's avatar
    tjc committed
    
    
        String refName = (String) combo.getSelectedItem();
        int seqLength = seqLengths.get(refName);
    
        float pixPerBase = ((float)getWidth())/(float)(seqLength);    
        int start = (int) Math.round(event.getPoint().getX()/pixPerBase);
        if(start < 1)
          start = 1;
        if(start > seqLength)
          start = seqLength;
    
        MarkerRange drag_range;
        try
    
          drag_range = new MarkerRange (bases.getForwardStrand(), start, start);
          getSelection().setMarkerRange(drag_range);
          repaint();
    
        catch (OutOfRangeException e)
    
          e.printStackTrace();
    
        }
      }
      
      private Selection getSelection()
      {
        return selection;
      }
      
    
    tjc's avatar
    tjc committed
      private class Ruler extends JPanel
    
    tjc's avatar
    tjc committed
      {
    
    tjc's avatar
    tjc committed
        private static final long serialVersionUID = 1L;
    
    tjc's avatar
    tjc committed
        int start;
        int end;
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        public Ruler()
        {
          super();
          setPreferredSize(new Dimension(getPreferredSize().width, 15));
          setBackground(Color.white);
          setFont(getFont().deriveFont(11.f));
        }
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        public void paintComponent(Graphics g)
        {
          super.paintComponent(g);
          Graphics2D g2 = (Graphics2D)g;
          drawBaseScale(g2, start, end, 12);
        }
    
    tjc's avatar
    tjc committed
    
        private void drawBaseScale(Graphics2D g2, int start, int end, int ypos)
        {
          int startMark = (((int)(start/10))*10)+1;
    
          for(int i=startMark; i<end; i+=10)
          {
    
    tjc's avatar
    tjc committed
            int xpos = (i-start)*ALIGNMENT_PIX_PER_BASE;
    
    tjc's avatar
    tjc committed
            g2.drawString(Integer.toString(i), xpos, ypos);
            
            xpos+=(ALIGNMENT_PIX_PER_BASE/2);
            g2.drawLine(xpos, ypos+1, xpos, ypos+5);
          }
        }
    
    tjc's avatar
    tjc committed
      }
      
    
      /**
      * Popup menu listener
      */
      class PopupListener extends MouseAdapter
      {
        public void mouseClicked(MouseEvent e)
        {
          JamView.this.requestFocus();
    
          handleCanvasMouseDragOrClick(e);
    
        }
        
        public void mousePressed(MouseEvent e)
        {
          maybeShowPopup(e);
        }
    
        public void mouseReleased(MouseEvent e)
        {
          maybeShowPopup(e);
        }
    
        private void maybeShowPopup(MouseEvent e)
        {
          if(e.isPopupTrigger())
            popup.show(e.getComponent(),
                    e.getX(), e.getY());
        }
      }
     
      
    
    tjc's avatar
    tjc committed
      class SAMRecordComparator implements Comparator<Object>
    
    tjc's avatar
    tjc committed
      {
        public int compare(Object o1, Object o2) 
        {
    
    tjc's avatar
    tjc committed
          SAMRecord pr1 = (SAMRecord) o1;
          SAMRecord pr2 = (SAMRecord) o2;
    
    tjc's avatar
    tjc committed
          
    
    tjc's avatar
    tjc committed
          int cmp = pr1.getReadName().compareTo(pr2.getReadName());
          if(cmp == 0)
          {
            if(pr1.getAlignmentStart() < pr2.getAlignmentStart())
              return -1;
            else
              return 1;
    
    tjc's avatar
    tjc committed
          return cmp;
    
    tjc's avatar
    tjc committed
        }
      }
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
      public Dimension getPreferredScrollableViewportSize()
      {
        return getPreferredSize();
      }
    
      public int getScrollableBlockIncrement(Rectangle visibleRect,
          int orientation, int direction)
      {
        if (orientation == SwingConstants.HORIZONTAL)
          return visibleRect.width - maxUnitIncrement;
        else 
          return visibleRect.height - maxUnitIncrement;
      }
    
      public boolean getScrollableTracksViewportHeight()
      {
        return false;
      }
    
      public boolean getScrollableTracksViewportWidth()
      {
        return false;
      }
    
      public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
                                            int direction)
      {
      //Get the current position.
        int currentPosition = 0;
        if (orientation == SwingConstants.HORIZONTAL) 
            currentPosition = visibleRect.x;
        else 
            currentPosition = visibleRect.y;
    
        //Return the number of pixels between currentPosition
        //and the nearest tick mark in the indicated direction.
        if (direction < 0)
        {
          int newPosition = currentPosition -
                            (currentPosition / maxUnitIncrement)
                             * maxUnitIncrement;
          return (newPosition == 0) ? maxUnitIncrement : newPosition;
        } 
        else 
        {
          return ((currentPosition / maxUnitIncrement) + 1)
                  * maxUnitIncrement
                  - currentPosition;
        }
      }
    
    tjc's avatar
    tjc committed
      
    
      /**
       * Artemis event notification
       */
      public void displayAdjustmentValueChanged(DisplayAdjustmentEvent event)
      {
    
    tjc's avatar
    tjc committed
        if(event.getType() == DisplayAdjustmentEvent.SCALE_ADJUST_EVENT)
        {
    
    tjc's avatar
    tjc committed
          laststart = -1;
          lastend = -1;
          this.startBase = event.getStart();
          this.endBase   = event.getEnd();
          
    
          //int width = event.getEnd()-event.getStart()+1;
          int width = feature_display.getMaxVisibleBases();
    
          //System.out.println("displayAdjustmentValueChanged() "+event.getStart()+".."+event.getEnd()+"  +width");
    
    tjc's avatar
    tjc committed
    
          setZoomLevel(width);
          goToBasePosition(event.getStart());
    
    tjc's avatar
    tjc committed
          setDisplay(event.getStart(), event.getEnd(), event);
    
    tjc's avatar
    tjc committed
          repaint();
    
    tjc's avatar
    tjc committed
        }
        else
        {
          setDisplay(event.getStart(), event.getEnd(), event);
    
    tjc's avatar
    tjc committed
          repaint();
    
    tjc's avatar
    tjc committed
        }
    
    tjc's avatar
    tjc committed
      public static void main(String[] args)
      {
        String bam = args[0];
    
    tjc's avatar
    tjc committed
        int nbasesInView = 1000;
    
    tjc's avatar
    tjc committed
        String reference = null;
        
    
    tjc's avatar
    tjc committed
        for(int i=0;i<args.length; i++)
        {
          if(args[i].equals("-a"))
            bam = args[++i];
          else if(args[i].equals("-r"))
            reference = args[++i];
          else if(args[i].equals("-v"))
            nbasesInView = Integer.parseInt(args[++i]);
          else if(args[i].equals("-s"))
            System.setProperty("samtoolDir", args[++i]);
          else if(args[i].startsWith("-h"))
          { 
            System.out.println("-h\t show help");
            
            System.out.println("-a\t BAM/SAM file to display");
            System.out.println("-r\t reference file (optional)");
            System.out.println("-v\t number of bases to display in the view (optional)");
    
            /*System.out.println("-s\t samtool directory");*/
    
    tjc's avatar
    tjc committed
    
            System.exit(0);
          }
        }
    
    
    tjc's avatar
    tjc committed
        final JamView view = new JamView(bam, reference, nbasesInView);
    
    tjc's avatar
    tjc committed
        JFrame frame = new JFrame("JAM");
    
    tjc's avatar
    tjc committed
        
        frame.addWindowFocusListener(new WindowFocusListener()
        {
          public void windowGainedFocus(WindowEvent e)
          {
            view.requestFocus();
          }
          public void windowLostFocus(WindowEvent e){}
        });
        
    
        view.addJamToPanel((JPanel)frame.getContentPane(), false, null);
    
    tjc's avatar
    tjc committed
        frame.pack();
    
    tjc's avatar
    tjc committed
        view.jspView.getVerticalScrollBar().setValue(
            view.jspView.getVerticalScrollBar().getMaximum());
    
        frame.setVisible(true);
    
    tjc's avatar
    tjc committed
      }
    
    
      public void selectionChanged(SelectionChangeEvent event)
      {
        repaint();
      }
    
    tjc's avatar
    tjc committed
    }