Skip to content
Snippets Groups Projects
JamView.java 22.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • tjc's avatar
    tjc committed
    /* JamView
     *
     * created: 2009
     *
     * This file is part of Artemis
     *
     * Copyright(C) 2009  Genome Research Limited
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * as published by the Free Software Foundation; either version 2
     * of the License, or(at your option) any later version.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program; if not, write to the Free Software
     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     *
     */
    
    tjc's avatar
    tjc committed
    package uk.ac.sanger.artemis.components.alignment;
    
    import java.awt.BasicStroke;
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    
    tjc's avatar
    tjc committed
    import java.awt.FontMetrics;
    
    tjc's avatar
    tjc committed
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    
    tjc's avatar
    tjc committed
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    
    tjc's avatar
    tjc committed
    import java.awt.Point;
    
    tjc's avatar
    tjc committed
    import java.awt.Rectangle;
    
    tjc's avatar
    tjc committed
    import java.awt.Stroke;
    
    tjc's avatar
    tjc committed
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    tjc's avatar
    tjc committed
    import java.awt.event.FocusEvent;
    import java.awt.event.FocusListener;
    import java.awt.event.ItemEvent;
    import java.awt.event.ItemListener;
    import java.awt.event.KeyAdapter;
    import java.awt.event.KeyEvent;
    
    tjc's avatar
    tjc committed
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    
    tjc's avatar
    tjc committed
    import java.awt.event.WindowEvent;
    import java.awt.event.WindowFocusListener;
    
    tjc's avatar
    tjc committed
    import java.io.BufferedReader;
    
    tjc's avatar
    tjc committed
    import java.io.File;
    
    tjc's avatar
    tjc committed
    import java.io.IOException;
    import java.io.StringReader;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.Hashtable;
    import java.util.List;
    import java.util.Vector;
    
    
    tjc's avatar
    tjc committed
    import javax.swing.JCheckBox;
    
    tjc's avatar
    tjc committed
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    
    tjc's avatar
    tjc committed
    import javax.swing.JOptionPane;
    
    tjc's avatar
    tjc committed
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    
    tjc's avatar
    tjc committed
    import javax.swing.Scrollable;
    import javax.swing.SwingConstants;
    import javax.swing.UIManager;
    
    tjc's avatar
    tjc committed
    
    import uk.ac.sanger.artemis.Entry;
    import uk.ac.sanger.artemis.EntryGroup;
    import uk.ac.sanger.artemis.Options;
    import uk.ac.sanger.artemis.SimpleEntryGroup;
    import uk.ac.sanger.artemis.components.EntryFileDialog;
    import uk.ac.sanger.artemis.components.MessageDialog;
    import uk.ac.sanger.artemis.io.EntryInformation;
    import uk.ac.sanger.artemis.sequence.Bases;
    import uk.ac.sanger.artemis.sequence.NoSequenceException;
    import uk.ac.sanger.artemis.util.Document;
    import uk.ac.sanger.artemis.util.DocumentFactory;
    import uk.ac.sanger.artemis.util.OutOfRangeException;
    
    public class JamView extends JPanel
    
    tjc's avatar
    tjc committed
                         implements Scrollable
    
    tjc's avatar
    tjc committed
    {
      private static final long serialVersionUID = 1L;
      private List<Read> readsInView;
      private Hashtable<String, Integer> seqLengths = new Hashtable<String, Integer>();
      private Vector<String> seqNames = new Vector<String>();
      private String bam;
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
      private EntryGroup entryGroup;
      private JScrollPane jspView;
      private JComboBox combo;
    
    tjc's avatar
    tjc committed
      private JCheckBox checkBoxSingle;
    
    tjc's avatar
    tjc committed
      private int nbasesInView;
    
    tjc's avatar
    tjc committed
      private int laststart;
      private int lastend;
      private int maxUnitIncrement = 4;
      private int ALIGNMENT_PIX_PER_BASE;
    
    
    tjc's avatar
    tjc committed
     
      public JamView(String bam, 
                     String reference,
                     int nbasesInView)
      {
        super();
        setBackground(Color.white);
        this.bam = bam;
        this.nbasesInView = nbasesInView;
        
        if(reference != null)
        {
          entryGroup = new SimpleEntryGroup();
          try
          {
            getEntry(reference,entryGroup);
          }
          catch (NoSequenceException e)
          {
            e.printStackTrace();
          }
        }
    
    tjc's avatar
    tjc committed
        
    
    tjc's avatar
    tjc committed
        readHeader();
    
    tjc's avatar
    tjc committed
        
    
    tjc's avatar
    tjc committed
        // set font size
        setFont(getFont().deriveFont(12.f));
    
    tjc's avatar
    tjc committed
        final javax.swing.plaf.FontUIResource font_ui_resource =
    
    tjc's avatar
    tjc committed
          new javax.swing.plaf.FontUIResource(getFont());
       //  Options.getOptions().getFontUIResource();
    
    tjc's avatar
    tjc committed
    
        java.util.Enumeration keys = UIManager.getDefaults().keys();
        while(keys.hasMoreElements()) 
        {
          Object key = keys.nextElement();
          Object value = UIManager.get(key);
          if(value instanceof javax.swing.plaf.FontUIResource) 
            UIManager.put(key, font_ui_resource);
        }
        FontMetrics fm  = getFontMetrics(getFont());
    
    tjc's avatar
    tjc committed
        ALIGNMENT_PIX_PER_BASE  = (int) (fm.stringWidth("A")*1.1);
    
    tjc's avatar
    tjc committed
      }
      
    
    tjc's avatar
    tjc committed
      /**
       * Read the BAM/SAM header
       */
    
    tjc's avatar
    tjc committed
      private void readHeader()
      {
    
    tjc's avatar
    tjc committed
        String samtoolCmd = "";
        if(System.getProperty("samtoolDir") != null)
          samtoolCmd = System.getProperty("samtoolDir");
        String cmd[] = { samtoolCmd+File.separator+"samtools",  
    
    tjc's avatar
    tjc committed
    			     "view", "-H", bam };
    	
    
    tjc's avatar
    tjc committed
        RunSamTools samtools = new RunSamTools(cmd, null, null, null);
    
    tjc's avatar
    tjc committed
    	
        if(samtools.getProcessStderr() != null)
          System.out.println(samtools.getProcessStderr());
     
        String header = samtools.getProcessStdout();
        
        StringReader samReader = new StringReader(header);
    	BufferedReader buff = new BufferedReader(samReader);
        
    	String line;
    	try 
    	{
    	  while((line = buff.readLine()) != null)
    	  {
    	    if(line.indexOf("LN:") > -1)
    	    {
    	      String parts[] = line.split("\t");
    	      String name = "";
    	      int seqLength = 0;
    	      for(int i=0; i<parts.length; i++)
    	      {
    	        if(parts[i].startsWith("LN:"))
    	          seqLength = Integer.parseInt( parts[i].substring(3) );
    	        else if(parts[i].startsWith("SN:"))
    	          name = parts[i].substring(3);
    	      }
    	      seqLengths.put(name, seqLength);
    	      seqNames.add(name);
    	    }
    	  }
    	} 
    	catch (IOException e) 
    	{
    	  e.printStackTrace();
    	}
      }
      
    
    tjc's avatar
    tjc committed
      /**
       * Read data from BAM/SAM file for a region.
       * @param start
       * @param end
       * @param pair_sort
       */
      private void readFromBam(int start, int end)
    
    tjc's avatar
    tjc committed
      {
        String refName = (String) combo.getSelectedItem();
    
    tjc's avatar
    tjc committed
        
        String samtoolCmd = "";
        if(System.getProperty("samtoolDir") != null)
          samtoolCmd = System.getProperty("samtoolDir");
    
    tjc's avatar
    tjc committed
        
    
    tjc's avatar
    tjc committed
    	String cmd[] = { samtoolCmd+File.separator+"samtools",  
    
    tjc's avatar
    tjc committed
    				     "view", 
    				     bam, refName+":"+start+"-"+end };
    
    tjc's avatar
    tjc committed
    		
    	for(int i=0; i<cmd.length;i++)
    	  System.out.print(cmd[i]+" ");
    	System.out.println();
    
    tjc's avatar
    tjc committed
    	
        if(readsInView == null)
          readsInView = new Vector<Read>();
        else
          readsInView.clear();
    	RunSamTools samtools = new RunSamTools(cmd, null, null, readsInView);
    
    tjc's avatar
    tjc committed
    		
    	if(samtools.getProcessStderr() != null)
          System.out.println(samtools.getProcessStderr());
    	    
    
    tjc's avatar
    tjc committed
    	samtools.waitForStdout();
    
    tjc's avatar
    tjc committed
      }
      
      /**
       * Override
       */
      public void paintComponent(Graphics g)
      {
    	super.paintComponent(g);
    	Graphics2D g2 = (Graphics2D)g;
    
    	String refName = (String) combo.getSelectedItem();
        int seqLength = seqLengths.get(refName);
    
    	float pixPerBase = ((float)getWidth())/(float)(seqLength);
    	
    
    tjc's avatar
    tjc committed
        double x = jspView.getViewport().getViewRect().getX();
        int start = (int) (seqLength * ( (float)x / (float)getWidth()));
        int end   = (int) (start + ((float)jspView.getViewport().getWidth() / 
                                    (float)pixPerBase));
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        if(laststart != start ||
    
    tjc's avatar
    tjc committed
           lastend   != end)
        {
          try
          {
            readFromBam(start, end);      
            if(pixPerBase < ALIGNMENT_PIX_PER_BASE)
              Collections.sort(readsInView, new ReadComparator());
          }
          catch(OutOfMemoryError ome)
          {
            JOptionPane.showMessageDialog(this, "Out of Memory");
            return;
          }
        }
    
    tjc's avatar
    tjc committed
        
        laststart = start;
        lastend   = end;
    
    tjc's avatar
    tjc committed
    	if(pixPerBase >= ALIGNMENT_PIX_PER_BASE)
    	  drawBaseAlignment(g2, seqLength, pixPerBase, start, end);
    	else
          drawLineView(g2, seqLength, pixPerBase, start, end);
      }
      
      private void drawBaseAlignment(Graphics2D g2, int seqLength, 
                                     float pixPerBase, int start, int end)
      {
        FontMetrics fm =  getFontMetrics(getFont());
        int ypos = fm.getHeight();
    
    tjc's avatar
    tjc committed
        
    
    tjc's avatar
    tjc committed
        drawBaseScale(g2, start, end, ypos);
    
    tjc's avatar
    tjc committed
        boolean draw[] = new boolean[readsInView.size()];
        for(int i=0; i<readsInView.size(); i++)
          draw[i] = false;
        
    
    tjc's avatar
    tjc committed
        ypos+=6;
        
    
    tjc's avatar
    tjc committed
        for(int i=0; i<readsInView.size(); i++)
        {
          if (!draw[i])
          {
            Read thisRead = readsInView.get(i);
    
    tjc's avatar
    tjc committed
            ypos+=10;
    
    tjc's avatar
    tjc committed
    
            drawSequence(g2, thisRead, pixPerBase, ypos);
            draw[i] = true;
            
            int thisEnd = thisRead.pos+thisRead.seq.length();
            for(int j=i+1; j<readsInView.size(); j++)
            {
              if (!draw[j])
              {
                Read nextRead = readsInView.get(j);
                if(nextRead.pos > thisEnd+1)
                {
                  drawSequence(g2, nextRead, pixPerBase, ypos);
                  draw[j] = true;
    
    tjc's avatar
    tjc committed
                  thisEnd = nextRead.pos+nextRead.seq.length();
    
    tjc's avatar
    tjc committed
                }
              }
            }
          }
        }
    
    tjc's avatar
    tjc committed
        
        if(ypos > getHeight())
        {
          setPreferredSize(new Dimension(getWidth(), ypos));
          revalidate();
        }
    
    tjc's avatar
    tjc committed
      }
      
    
    tjc's avatar
    tjc committed
      /**
       * Draw the query sequence
       * @param g2
       * @param read
       * @param pixPerBase
       * @param ypos
       */
    
    tjc's avatar
    tjc committed
      private void drawSequence(Graphics2D g2, Read read, float pixPerBase, int ypos)
      {
        if ((read.flag & 0x0001) != 0x0001 || 
            (read.flag & 0x0008) == 0x0008)
          g2.setColor(Color.black);
        else
          g2.setColor(Color.blue);
        
        int xpos;
        
        for(int i=0;i<read.seq.length(); i++)
        {
          xpos = ((read.pos-1) + i)*ALIGNMENT_PIX_PER_BASE;
          g2.drawString(read.seq.substring(i, i+1), xpos, ypos);
        }
        
      }
      
    
    tjc's avatar
    tjc committed
      private void drawLineView(Graphics2D g2, int seqLength, float pixPerBase, int start, int end)
      {   
    
    tjc's avatar
    tjc committed
        drawScale(g2, start, end, pixPerBase);
        
        Stroke originalStroke = g2.getStroke();
        Stroke stroke =
    
    tjc's avatar
    tjc committed
                new BasicStroke (1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
    
    tjc's avatar
    tjc committed
        int scaleHeight = 15;
        
        for(int i=0; i<readsInView.size(); i++)
        {
    
    tjc's avatar
    tjc committed
          Read thisRead = readsInView.get(i);
    
    tjc's avatar
    tjc committed
          Read nextRead = null;      
    
          if( (thisRead.flag & 0x0001) != 0x0001 || // read is not paired in sequencing
              (thisRead.flag & 0x0008) == 0x0008 )  // mate is unmapped 
          {
            if(checkBoxSingle.isSelected())
            {
              System.out.println("HERE "+thisRead.qname+
                  "\t\t pos "+thisRead.pos+"\tseq length "+thisRead.seq.length()+
                  "\tisize "+thisRead.isize);
              int ypos = (getHeight() - scaleHeight) - thisRead.seq.length();
              g2.setColor(Color.orange);
              drawRead(g2, thisRead, pixPerBase, stroke, ypos);
            }
    
    tjc's avatar
    tjc committed
            continue;
    
    tjc's avatar
    tjc committed
          }
    
    tjc's avatar
    tjc committed
          
    
    tjc's avatar
    tjc committed
          int ypos = (getHeight() - scaleHeight) - ( Math.abs(thisRead.isize) );
    
    tjc's avatar
    tjc committed
          if(i < readsInView.size()-1)
          {
    
    tjc's avatar
    tjc committed
            nextRead = readsInView.get(++i);
            
    
    tjc's avatar
    tjc committed
            if(thisRead.qname.equals(nextRead.qname))
            {
    
    tjc's avatar
    tjc committed
              if( (thisRead.flag & 0x0010) == 0x0010 && // strand of the query (1 for reverse)
    
    tjc's avatar
    tjc committed
                  (nextRead.flag & 0x0010) == 0x0010 )
                g2.setColor(Color.red);
              else
                g2.setColor(Color.blue);
    
    tjc's avatar
    tjc committed
     
              int thisEnd = drawRead(g2, thisRead, pixPerBase, stroke, ypos)[1];
              int nextStart = drawRead(g2, nextRead, pixPerBase, stroke, ypos)[0];
    
    tjc's avatar
    tjc committed
              
    
    tjc's avatar
    tjc committed
              if(thisEnd < nextStart && (nextStart-thisEnd)*pixPerBase > 2.f)
              {
                g2.setStroke(originalStroke);
                g2.setColor(Color.LIGHT_GRAY);
                g2.drawLine((int)(thisEnd*pixPerBase), ypos, (int)(nextStart*pixPerBase), ypos);
              }
    
    tjc's avatar
    tjc committed
            }
            else
    
    tjc's avatar
    tjc committed
            {
              drawLoneRead(g2, thisRead, ypos, pixPerBase, originalStroke, stroke);
    
    tjc's avatar
    tjc committed
              i--;
    
    tjc's avatar
    tjc committed
            }
          }
          else
          {
            drawLoneRead(g2, thisRead, ypos, pixPerBase, originalStroke, stroke);
    
    tjc's avatar
    tjc committed
          }
    
    tjc's avatar
    tjc committed
        }
    
    tjc's avatar
    tjc committed
      }
      
    
    tjc's avatar
    tjc committed
      /**
       * Draw a read that apparently has a read mate that is not in view.
       * @param g2
       * @param thisRead
       * @param ypos
       * @param pixPerBase
       * @param originalStroke
       * @param stroke
       */
      private void drawLoneRead(Graphics2D g2, Read thisRead, int ypos, 
          float pixPerBase, Stroke originalStroke, Stroke stroke)
      {
        boolean drawLine = true;
        g2.setColor(Color.blue); 
        if(ypos <= 0)
        {
          ypos = thisRead.seq.length();
          drawLine = false;
          g2.setColor(Color.orange); 
        }
    
        int thisEnd = drawRead(g2, thisRead, pixPerBase, stroke, ypos)[1];
        if(drawLine)
        {
          g2.setStroke(originalStroke);
          g2.setColor(Color.LIGHT_GRAY);
          int nextStart = (int) ((thisRead.mpos-1)*pixPerBase);
          g2.drawLine((int)(thisEnd*pixPerBase), ypos, nextStart, ypos);
        }
      }
      
    
    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)
        {
          int xpos = (i-1)*ALIGNMENT_PIX_PER_BASE;
          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
      
      private void drawScale(Graphics2D g2, int start, int end, float pixPerBase)
      {
        g2.setColor(Color.black);
    
    tjc's avatar
    tjc committed
        g2.drawLine( (int)(start*pixPerBase), getHeight()-14,
                     (int)(end*pixPerBase),   getHeight()-14);
    
    tjc's avatar
    tjc committed
        int interval = end-start;
        
        if(interval > 256000)
          drawTicks(g2, start, end, pixPerBase, 512000);
        else if(interval > 64000)
          drawTicks(g2, start, end, pixPerBase, 12800);
        else if(interval > 16000)
          drawTicks(g2, start, end, pixPerBase, 3200);
        else if(interval > 4000)
          drawTicks(g2, start, end, pixPerBase, 800);
        else if(interval > 1000)
          drawTicks(g2, start, end, pixPerBase, 200);
    
    tjc's avatar
    tjc committed
        else
          drawTicks(g2, start, end, pixPerBase, 50);
    
    tjc's avatar
    tjc committed
      }
      
      private void drawTicks(Graphics2D g2, int start, int end, float pixPerBase, int division)
      {
    
    tjc's avatar
    tjc committed
        int markStart = (Math.round(start/division)*division);
        
        if(markStart < 1)
          markStart = 1;
        
    
    tjc's avatar
    tjc committed
        int sm = markStart-(division/2);
        
        if(sm > start)
          g2.drawLine((int)(sm*pixPerBase), getHeight()-14,(int)(sm*pixPerBase), getHeight()-12);
        
        for(int m=markStart; m<end; m+=division)
        {
          g2.drawString(Integer.toString(m), m*pixPerBase, getHeight()-1);
          g2.drawLine((int)(m*pixPerBase), getHeight()-14,(int)(m*pixPerBase), getHeight()-11);
          
          sm = m+(division/2);
          
          if(sm < end)
            g2.drawLine((int)(sm*pixPerBase), getHeight()-14,(int)(sm*pixPerBase), getHeight()-12);
    
    tjc's avatar
    tjc committed
          
          if(m == 1)
            m = 0;
    
    tjc's avatar
    tjc committed
        }
      }
      
    
    tjc's avatar
    tjc committed
      private int[] drawRead(Graphics2D g2, Read read,
    
    tjc's avatar
    tjc committed
    		               float pixPerBase, Stroke stroke, int ypos)
    
    tjc's avatar
    tjc committed
      {
    
    tjc's avatar
    tjc committed
        int thisStart = read.pos-1;
        int thisEnd   = thisStart + read.seq.length();
    
    tjc's avatar
    tjc committed
        g2.setStroke(stroke);
    
    tjc's avatar
    tjc committed
        g2.drawLine((int)(thisStart*pixPerBase), ypos, (int)(thisEnd*pixPerBase), ypos);
        return new int[] { thisStart, thisEnd };
    
    tjc's avatar
    tjc committed
      }
      
    
    tjc's avatar
    tjc committed
      public void addToPanel(final JPanel panel)
    
    tjc's avatar
    tjc committed
      {
    
    tjc's avatar
    tjc committed
        JPanel topPanel = new JPanel(new GridBagLayout());
        GridBagConstraints gc = new GridBagConstraints();
        
    
    tjc's avatar
    tjc committed
        combo = new JComboBox(seqNames);
        combo.setEditable(false);
        combo.addItemListener(new ItemListener()
        {
          public void itemStateChanged(ItemEvent e)
          {
    
    tjc's avatar
    tjc committed
            laststart = -1;
            lastend   = -1;
    
    tjc's avatar
    tjc committed
            setZoomLevel(JamView.this.nbasesInView);
          }
        });
    
    tjc's avatar
    tjc committed
        gc.fill = GridBagConstraints.NONE;
        gc.anchor = GridBagConstraints.FIRST_LINE_START;
        topPanel.add(combo, gc);
    
    tjc's avatar
    tjc committed
        
    
    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
        panel.setPreferredSize(new Dimension(1000,500));
    
    tjc's avatar
    tjc committed
        setLength(nbasesInView);
        
    
    tjc's avatar
    tjc committed
        jspView = new JScrollPane(this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
    
    tjc's avatar
    tjc committed
                                        JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
            
        panel.setLayout(new BorderLayout());
    
    tjc's avatar
    tjc committed
        panel.add(topPanel, BorderLayout.NORTH);
    
    tjc's avatar
    tjc committed
        panel.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
        addMouseListener(new MouseAdapter()
        {
          public void mouseClicked(MouseEvent e)
          {
            JamView.this.requestFocus();
          }
        });
        
    
    tjc's avatar
    tjc committed
        addKeyListener(new KeyAdapter()
        {
          public void keyPressed(final KeyEvent event)
          {
            switch(event.getKeyCode())
            {
              case KeyEvent.VK_UP:
    
    tjc's avatar
    tjc committed
                int startBase = getBaseAtStartOfView();
    
    tjc's avatar
    tjc committed
                setZoomLevel( (int) (JamView.this.nbasesInView*1.1) );
    
    tjc's avatar
    tjc committed
                setViewToBasePosition(startBase);
    
    tjc's avatar
    tjc committed
                repaint();
                break;
              case KeyEvent.VK_DOWN:
    
    tjc's avatar
    tjc committed
                startBase = getBaseAtStartOfView();
    
    tjc's avatar
    tjc committed
                setZoomLevel( (int) (JamView.this.nbasesInView*.9) );
    
    tjc's avatar
    tjc committed
                setViewToBasePosition(startBase);
    
    tjc's avatar
    tjc committed
                repaint();
                break;
              default:
                break;
            }
          }
        });
        
    
    tjc's avatar
    tjc committed
        setFocusable(true);
        requestFocusInWindow();
    
    tjc's avatar
    tjc committed
        addFocusListener(new FocusListener() 
        {
          public void focusGained(FocusEvent fe) {}
          public void focusLost(FocusEvent fe) {}
        });
      }
      
    
    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) (seqLength * ( x / getWidth()));
      }
      
      /**
       * 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;
        setLength(this.nbasesInView);
        revalidate();
        repaint();
    
    tjc's avatar
    tjc committed
      }
      
      /**
       * Set the ViewPort so it starts at the given base position.
       * @param base
       */
      private void setViewToBasePosition(int base)
      {
        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
        p.x = (int) ((getPreferredSize().width)*(((float)base)/(float)seqLength));
    
    tjc's avatar
    tjc committed
        jspView.getViewport().setViewPosition(p);
      }
    
    
    tjc's avatar
    tjc committed
      /**
       * Set the panel size based on the number of bases visible.
       * @param nbasesInView
       */
    
    tjc's avatar
    tjc committed
      private void setLength(int basesToShow)
      {
        String refName = (String) combo.getSelectedItem();
        int seqLength = seqLengths.get(refName);
    
    tjc's avatar
    tjc committed
        double pixPerBase = 1000.d/(double)(basesToShow);
        
        System.out.println(pixPerBase+"  "+ALIGNMENT_PIX_PER_BASE);
        if(pixPerBase > ALIGNMENT_PIX_PER_BASE)
    
    tjc's avatar
    tjc committed
        {
    
    tjc's avatar
    tjc committed
          pixPerBase = ALIGNMENT_PIX_PER_BASE;
    
    tjc's avatar
    tjc committed
          jspView.getVerticalScrollBar().setValue(0);
        }
    
    tjc's avatar
    tjc committed
        Dimension d = new Dimension();
        d.setSize((seqLength*pixPerBase), 800.d);
        setPreferredSize(d);
    
    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);
        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
        {
          Bases bases = null;
          if(entryGroup.getSequenceEntry() != null)
            bases = entryGroup.getSequenceEntry().getBases();
          if(bases == null)
            entry = new Entry(new_embl_entry);
          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;
      }
      
      class ReadComparator implements Comparator
      {
        public int compare(Object o1, Object o2) 
        {
          Read pr1 = (Read) o1;
          Read pr2 = (Read) o2;
          
          return pr1.qname.compareTo(pr2.qname);
        }
      }
    
    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
      
      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");
    
            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){}
        });
        
    
    tjc's avatar
    tjc committed
        view.addToPanel((JPanel)frame.getContentPane());
        frame.pack();
    
    tjc's avatar
    tjc committed
        view.jspView.getVerticalScrollBar().setValue(
            view.jspView.getVerticalScrollBar().getMaximum());
    
    tjc's avatar
    tjc committed
        frame.setVisible(true);
    
    tjc's avatar
    tjc committed
      }
    }