Skip to content
Snippets Groups Projects
BamView.java 98.1 KiB
Newer Older
        int width  = block.getLength()*ALIGNMENT_PIX_PER_BASE;
        Color col1 = g2.getColor();
        g2.setColor(Color.red);
        g2.drawRect(xstart, ypos-BASE_HEIGHT, width, BASE_HEIGHT);        
        if(i < blocks.size()-1)
        {
          int nextStart = 
            (blocks.get(i+1).getReferenceStart() + offset - refSeqStart)*ALIGNMENT_PIX_PER_BASE;
          g2.drawLine(xstart+width, ypos-(BASE_HEIGHT/2), nextStart, ypos-(BASE_HEIGHT/2));
        }
        
        g2.setColor(col1);
      }
      else if(i < blocks.size()-1)
      {
        refPos =  block.getReferenceStart() + offset - refSeqStart;
        int xstart = refPos*ALIGNMENT_PIX_PER_BASE;
        int width  = block.getLength()*ALIGNMENT_PIX_PER_BASE;
        int nextStart = 
          (blocks.get(i+1).getReferenceStart() + offset - refSeqStart)*ALIGNMENT_PIX_PER_BASE;
        g2.drawLine(xstart+width, ypos-(BASE_HEIGHT/2), nextStart, ypos-(BASE_HEIGHT/2));
      }
tjc's avatar
tjc committed
    }
    if(lastMousePoint != null && blocks.size() > 0)
      refPos = blocks.get(0).getReferenceStart()+offset-refSeqStart;
tjc's avatar
tjc committed
      int xstart = refPos*ALIGNMENT_PIX_PER_BASE;
      
      refPos = blocks.get(blocks.size()-1).getReferenceStart()+
               blocks.get(blocks.size()-1).getLength()+offset-refSeqStart;
tjc's avatar
tjc committed
      int xend   = (refPos+len)*ALIGNMENT_PIX_PER_BASE;

      if(lastMousePoint.getY() > ypos-11 && lastMousePoint.getY() < ypos)
      if(lastMousePoint.getX() > xstart &&
         lastMousePoint.getX() < xend)
      {
        mouseOverSAMRecord = samRecord;
        if(insertions != null)
          mouseOverInsertion = insertions.get((int)lastMousePoint.getX());
tjc's avatar
tjc committed
  }
  
  /**
   * Colour bases on their mapping quality.
   * @param g2
   * @param baseQuality
   */
  private void setColourByBaseQuality(Graphics2D g2, byte baseQuality)
  {
    if (baseQuality < 10)
      g2.setColor(Color.blue);
    else if (baseQuality < 20)
      g2.setColor(DARK_GREEN);
    else if (baseQuality < 30)
      g2.setColor(DARK_ORANGE);
tjc's avatar
tjc committed
  /**
   * Draw zoomed-out view.
   * @param g2
   * @param seqLength
   * @param pixPerBase
   * @param start
   * @param end
   */
tjc's avatar
tjc committed
  private void drawLineView(Graphics2D g2, int seqLength, float pixPerBase, int start, int end)
  {
    drawSelectionRange(g2, pixPerBase,start, end);
tjc's avatar
tjc committed
    if(isShowScale())
tjc's avatar
tjc committed
      drawScale(g2, start, end, pixPerBase, getHeight());
tjc's avatar
tjc committed
    
    Stroke stroke =
      new BasicStroke (1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
    g2.setStroke(stroke);
    
    int scaleHeight;
    if(isShowScale())
      scaleHeight = 15;
    else
      scaleHeight = 0;
tjc's avatar
tjc committed
    
    int baseAtStartOfView = getBaseAtStartOfView();
    Rectangle r = jspView.getViewport().getViewRect();
tjc's avatar
tjc committed
    for(int i=0; i<readsInView.size(); i++)
    {
tjc's avatar
tjc committed
      SAMRecord samRecord = readsInView.get(i);
      SAMRecord samNextRecord = null;      
tjc's avatar
tjc committed

tjc's avatar
tjc committed
      if( !samRecord.getReadPairedFlag() ||  // read is not paired in sequencing
tjc's avatar
tjc committed
          samRecord.getMateUnmappedFlag() )  // mate is unmapped
tjc's avatar
tjc committed
      {
tjc's avatar
tjc committed
        if(isSingle)
tjc's avatar
tjc committed
        {
          int ypos = getYPos(scaleHeight, samRecord.getReadString().length()); // (getHeight() - scaleHeight) - samRecord.getReadString().length();
          if(ypos > r.getMaxY() || ypos < r.getMinY())
tjc's avatar
tjc committed
          g2.setColor(Color.black);
          drawRead(g2, samRecord, pixPerBase, ypos, baseAtStartOfView);
tjc's avatar
tjc committed
        }
tjc's avatar
tjc committed
        continue;
tjc's avatar
tjc committed
      }
tjc's avatar
tjc committed

      int ypos = getYPos(scaleHeight, Math.abs(samRecord.getInferredInsertSize()));
      if( (ypos > r.getMaxY() || ypos < r.getMinY()) && ypos > 0 )
tjc's avatar
tjc committed
      if(i < readsInView.size()-1)
      {
tjc's avatar
tjc committed
        samNextRecord = readsInView.get(++i);
tjc's avatar
tjc committed

tjc's avatar
tjc committed
        if(samRecord.getReadName().equals(samNextRecord.getReadName()))
tjc's avatar
tjc committed
        { 
          // draw connection between paired reads
tjc's avatar
tjc committed
          if(samRecord.getAlignmentEnd() < samNextRecord.getAlignmentStart() && 
              (samNextRecord.getAlignmentStart()-samRecord.getAlignmentEnd())*pixPerBase > 2.f)
tjc's avatar
tjc committed
          {
            g2.setColor(Color.LIGHT_GRAY);
tjc's avatar
tjc committed
                   (int)((samRecord.getAlignmentEnd()-getBaseAtStartOfView())*pixPerBase), 
                   (int)((samNextRecord.getAlignmentStart()-getBaseAtStartOfView())*pixPerBase), ypos);
tjc's avatar
tjc committed
          }
tjc's avatar
tjc committed
          
          if(colourByCoverageColour.isSelected())
            g2.setColor(getColourByCoverageColour(samRecord));
          else if( samRecord.getReadNegativeStrandFlag() && // strand of the query (1 for reverse)
tjc's avatar
tjc committed
              samNextRecord.getReadNegativeStrandFlag() )
            g2.setColor(Color.red);
          else
            g2.setColor(Color.blue);
          drawRead(g2, samRecord, pixPerBase, ypos, baseAtStartOfView);
          drawRead(g2, samNextRecord, pixPerBase, ypos, baseAtStartOfView);
tjc's avatar
tjc committed
        }
        else
tjc's avatar
tjc committed
        {
          drawLoneRead(g2, samRecord, ypos, pixPerBase, baseAtStartOfView, scaleHeight);
tjc's avatar
tjc committed
          i--;
tjc's avatar
tjc committed
        }
      }
      else
      {
        drawLoneRead(g2, samRecord, ypos, pixPerBase, baseAtStartOfView, scaleHeight);
tjc's avatar
tjc committed
      }
tjc's avatar
tjc committed
    }
tjc's avatar
tjc committed
    drawYScale(g2, scaleHeight);
tjc's avatar
tjc committed
  }
  
  private int getYPos(int scaleHeight, int size)
  {
    int ypos;
    
    if(!logScale)
      ypos = (getHeight() - scaleHeight) - size;
    else
    {
      int logInfSize = (int)( Math.log(size) * 100);
      ypos = (getHeight() - scaleHeight) - logInfSize;
    }
    
    return ypos;
  }
  /**
   * Draw the reads as lines in vertical stacks. The reads are colour 
   * coded as follows:
   * 
   * blue  - reads are unique and are paired with a mapped mate
   * black - reads are unique and are not paired or have an unmapped mate
   * green - reads are duplicates
   * 
   * @param g2
   * @param seqLength
   * @param pixPerBase
   * @param start
   * @param end
   */
  private void drawStackView(Graphics2D g2, 
                             int seqLength, 
                             float pixPerBase, 
                             int start, 
                             int end)
  {
    drawSelectionRange(g2, pixPerBase,start, end);
    if(isShowScale())
tjc's avatar
tjc committed
      drawScale(g2, start, end, pixPerBase, getHeight());
    BasicStroke stroke = new BasicStroke(
        1.3f,
        BasicStroke.CAP_BUTT, 
        BasicStroke.JOIN_MITER);
    g2.setStroke(stroke);
    
    int scaleHeight;
    if(isShowScale())
      scaleHeight = 15;
    else
      scaleHeight = 0;
    
    int ypos = (getHeight() - scaleHeight);
    int ydiff = 2;
    if(isOrientation)
      ydiff= 4;
    int baseAtStartOfView = getBaseAtStartOfView();
    g2.setColor(Color.blue);
    Rectangle r = jspView.getViewport().getViewRect();
    for(int i=0; i<readsInView.size(); i++)
    {
      SAMRecord samRecord = readsInView.get(i);
      int offset = getSequenceOffset(samRecord.getReferenceName());
      int recordStart = samRecord.getAlignmentStart()+offset;
      int recordEnd = samRecord.getAlignmentEnd()+offset;
      if(colourByCoverageColour.isSelected() ||
         lstStart != recordStart || lstEnd != recordEnd)
        if(colourByCoverageColour.isSelected())
          g2.setColor(getColourByCoverageColour(samRecord));
        else if (!samRecord.getReadPairedFlag() ||   // read is not paired in sequencing
                  samRecord.getMateUnmappedFlag() )  // mate is unmapped )  // mate is unmapped 
          g2.setColor(Color.black);
        else
          g2.setColor(Color.blue);
        
        if(maxEnd < recordStart)
        {
          ypos = (getHeight() - scaleHeight)-ydiff;
          ypos = ypos-ydiff;
        g2.setColor(DARK_GREEN);
      if(ypos > r.getMaxY() || ypos < r.getMinY())
        continue;
      drawRead(g2, samRecord, pixPerBase, ypos, baseAtStartOfView);
tjc's avatar
tjc committed
  /**
   * Draw the reads as lines in vertical stacks. The reads are colour 
   * coded as follows:
   * 
   * blue  - reads are unique and are paired with a mapped mate
   * black - reads are unique and are not paired or have an unmapped mate
   * green - reads are duplicates
   * 
   * @param g2
   * @param seqLength
   * @param pixPerBase
   * @param start
   * @param end
   */
  private void drawStrandStackView(Graphics2D g2, 
                                   int seqLength, 
                                   float pixPerBase, 
                                   int start, 
                                   int end)
  {
    drawSelectionRange(g2, pixPerBase,start, end);   
    BasicStroke stroke = new BasicStroke(
        1.3f,
        BasicStroke.CAP_BUTT, 
        BasicStroke.JOIN_MITER);
    
    int scaleHeight = 15;
    drawScale(g2, start, end, pixPerBase, ((getHeight()+scaleHeight)/2));

    int ymid = (getHeight()/ 2);
    int ydiff = 2;
    if(isOrientation)
      ydiff= 4;
tjc's avatar
tjc committed
    // positive strand    
    drawStrand(g2, false, scaleHeight, ymid-(scaleHeight/2), -ydiff, pixPerBase, stroke);
tjc's avatar
tjc committed
    
    // negative strand
    drawStrand(g2, true, scaleHeight, ymid+(scaleHeight/2), ydiff, pixPerBase, stroke);
tjc's avatar
tjc committed
  }
  
  private void drawStrand(Graphics2D g2, 
                          boolean isStrandNegative, 
                          int scaleHeight,
                          int ymid,
                          int ystep,
                          float pixPerBase,
                          Stroke stroke)
  {
    int ypos = (getHeight() - scaleHeight);
    int maxEnd = 0;
    int lstStart = 0;
    int lstEnd = 0;
    int baseAtStartOfView = getBaseAtStartOfView();
tjc's avatar
tjc committed
    g2.setColor(Color.blue);
    Rectangle r = jspView.getViewport().getViewRect();
tjc's avatar
tjc committed
    
    for(int i=0; i<readsInView.size(); i++)
    {
      SAMRecord samRecord = readsInView.get(i);
      
      if( samRecord.getReadNegativeStrandFlag() == isStrandNegative )
      {
        int offset = getSequenceOffset(samRecord.getReferenceName());
        int recordStart = samRecord.getAlignmentStart()+offset;
        int recordEnd   = samRecord.getAlignmentEnd()+offset;
      
        if(colourByCoverageColour.isSelected() ||
            lstStart != recordStart || lstEnd != recordEnd)
tjc's avatar
tjc committed
        { 
          if(colourByCoverageColour.isSelected())
            g2.setColor(getColourByCoverageColour(samRecord));
          else if (!samRecord.getReadPairedFlag() ||   // read is not paired in sequencing
                    samRecord.getMateUnmappedFlag() )  // mate is unmapped 
tjc's avatar
tjc committed
            g2.setColor(Color.black);
          else
            g2.setColor(Color.blue);
        
          if(maxEnd < recordStart)
          {
            ypos = ymid + ystep;
            maxEnd = recordEnd+2;
          }
          else
            ypos = ypos + ystep;
        }
        else
          g2.setColor(DARK_GREEN);
tjc's avatar
tjc committed

        lstStart = recordStart;
        lstEnd   = recordEnd;
        if(ypos > r.getMaxY() || ypos < r.getMinY())
          continue;
        drawRead(g2, samRecord, pixPerBase, ypos, baseAtStartOfView);
tjc's avatar
tjc committed
      }
    }
  }
  
  /**
   * Draw the reads as lines in vertical stacks. The reads are colour 
   * coded as follows:
   * 
   * blue  - reads are unique and are paired with a mapped mate
   * black - reads are unique and are not paired or have an unmapped mate
   * green - reads are duplicates
   * 
   * @param g2
   * @param seqLength
   * @param pixPerBase
   * @param start
   * @param end
   */
  private void drawPairedStackView(Graphics2D g2, 
                                   int seqLength, 
                                   float pixPerBase, 
                                   int start, 
                                   int end)
  {
    drawSelectionRange(g2, pixPerBase,start, end);
    if(isShowScale())
tjc's avatar
tjc committed
      drawScale(g2, start, end, pixPerBase, getHeight());
    
    Vector<PairedRead> pairedReads = new Vector<PairedRead>();
    for(int i=0; i<readsInView.size(); i++)
    {
      SAMRecord samRecord = readsInView.get(i);

      if( !samRecord.getReadPairedFlag() ||  // read is not paired in sequencing
          samRecord.getMateUnmappedFlag() )  // mate is unmapped
        continue;

      SAMRecord samNextRecord = null;      
      if(i < readsInView.size()-1)
      {
        samNextRecord = readsInView.get(++i);
        PairedRead pr = new PairedRead();
        if(samRecord.getReadName().equals(samNextRecord.getReadName()))
        { 
          if(samRecord.getAlignmentStart() < samNextRecord.getAlignmentStart())
          {
            pr.sam1 = samRecord;
            pr.sam2 = samNextRecord;
          }
          else
          {
            pr.sam2 = samRecord;
            pr.sam1 = samNextRecord;
          }
          
        }
        else
        {
          --i;
          pr.sam1 = samRecord;
          pr.sam2 = null;
        }
        pairedReads.add(pr);
      }
    }
    Collections.sort(pairedReads, new PairedReadComparator());
    
    Stroke originalStroke = new BasicStroke (1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND); 
    Stroke stroke =
            new BasicStroke (1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
    g2.setStroke(stroke);
    
    int scaleHeight;
    if(isShowScale())
      scaleHeight = 15;
    else
      scaleHeight = 0;
    
    int ydiff = 3;
    if(isOrientation)
      ydiff= 5;
    int ypos = getHeight() - scaleHeight - ydiff;
    int baseAtStartOfView = getBaseAtStartOfView();
    Rectangle r = jspView.getViewport().getViewRect();
    
    for(int i=0; i<pairedReads.size(); i++)
    {
      PairedRead pr = pairedReads.get(i);
      
      if(pr.sam1.getAlignmentStart() > lastEnd)
      {
        ypos = getHeight() - scaleHeight - ydiff;
        
        if(pr.sam2 != null)
        {  
          lastEnd = pr.sam2.getAlignmentEnd();
        }
        else
          lastEnd = pr.sam1.getAlignmentEnd();
      }
      else
        ypos = ypos - ydiff;
      if(ypos > r.getMaxY() || ypos < r.getMinY())
      g2.setStroke(originalStroke);
      g2.setColor(Color.LIGHT_GRAY);
      
      if(pr.sam2 != null)
      {
        int offset1 = getSequenceOffset(pr.sam1.getReferenceName());
        int offset2 = getSequenceOffset(pr.sam2.getReferenceName());
        drawTranslucentJointedLine(g2, 
                (int)((pr.sam1.getAlignmentEnd()+offset1-getBaseAtStartOfView())*pixPerBase),
                (int)((pr.sam2.getAlignmentStart()+offset2-getBaseAtStartOfView())*pixPerBase), ypos);
        if(!pr.sam1.getMateUnmappedFlag() &&
            pr.sam1.getMateReferenceName().equals(pr.sam1.getReferenceName()))
        {
          int prStart;
          
          if(pr.sam1.getAlignmentStart() > pr.sam1.getMateAlignmentStart())
            prStart = pr.sam1.getAlignmentEnd();
          else
            prStart = pr.sam1.getAlignmentStart();
          
          int offset = getSequenceOffset(pr.sam1.getReferenceName());
          drawTranslucentJointedLine(g2, 
              (int)( (prStart+offset-getBaseAtStartOfView())*pixPerBase),
              (int)( (pr.sam1.getMateAlignmentStart()+offset-getBaseAtStartOfView())*pixPerBase), ypos);
      if(colourByCoverageColour.isSelected())
        g2.setColor(getColourByCoverageColour(pr.sam1));
      else if( pr.sam1.getReadNegativeStrandFlag() && // strand of the query (1 for reverse)
          ( pr.sam2 != null && pr.sam2.getReadNegativeStrandFlag() ) )
        g2.setColor(Color.red);
      else
        g2.setColor(Color.blue);
      drawRead(g2, pr.sam1, pixPerBase, ypos, baseAtStartOfView);
        drawRead(g2, pr.sam2, pixPerBase, ypos, baseAtStartOfView);
  /**
   * Draw the read coverage.
   * @param g2
   * @param start
   * @param end
   * @param pixPerBase
   */
  private void drawCoverage(Graphics2D g2, int start, int end, float pixPerBase)
  {
    int scaleHeight = 0;
    if(isShowScale())
    {
      drawScale(g2, start, end, pixPerBase, getHeight());
      scaleHeight = 15;
    }

    int hgt = jspView.getVisibleRect().height-scaleHeight;
    g2.translate(0, getHeight()-hgt-scaleHeight);
    coverageView.draw(g2, getWidth(), hgt);
    coverageView.drawMax(g2);  
  }
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
   */
tjc's avatar
tjc committed
  private void drawLoneRead(Graphics2D g2, SAMRecord samRecord, int ypos, 
      float pixPerBase, int baseAtStartOfView, int scaleHeight)
tjc's avatar
tjc committed
  {
    boolean offTheTop = false;
tjc's avatar
tjc committed
    int offset = getSequenceOffset(samRecord.getReferenceName());
    int thisStart = samRecord.getAlignmentStart()+offset;
    int thisEnd   = thisStart + samRecord.getReadString().length() -1;
tjc's avatar
tjc committed
    
    if(ypos <= 0)
    {
      offTheTop = true;
      ypos = samRecord.getReadString().length();
    }
tjc's avatar
tjc committed
    if(samRecord.getInferredInsertSize() == 0)
    {
      offTheTop = true;
      ypos = getHeight() - scaleHeight - 5;
    }
tjc's avatar
tjc committed
    if(samRecord.getInferredInsertSize() != 0 &&
      Math.abs(samRecord.getMateAlignmentStart()-samRecord.getAlignmentEnd())*pixPerBase > 2.f)
tjc's avatar
tjc committed
    {
      g2.setColor(Color.LIGHT_GRAY);
      
      if(samRecord.getAlignmentEnd() < samRecord.getMateAlignmentStart())
      {
tjc's avatar
tjc committed
        int nextStart = 
          (int)((samRecord.getMateAlignmentStart()-getBaseAtStartOfView()+offset)*pixPerBase);
        drawTranslucentLine(g2, 
          (int)((thisEnd-getBaseAtStartOfView())*pixPerBase), nextStart, ypos);
tjc's avatar
tjc committed
      }
      else
      {
tjc's avatar
tjc committed
        int nextStart = 
            (int)((samRecord.getMateAlignmentStart()-getBaseAtStartOfView()+offset)*pixPerBase);
        drawTranslucentLine(g2, 
            (int)((thisStart-getBaseAtStartOfView())*pixPerBase), nextStart, ypos);
tjc's avatar
tjc committed
      }
    }
    
    if(colourByCoverageColour.isSelected())
      g2.setColor(getColourByCoverageColour(samRecord));
    else if(offTheTop)
      g2.setColor(DARK_ORANGE); 
    else if(samRecord.getReadNegativeStrandFlag() &&
            samRecord.getMateNegativeStrandFlag()) // strand of the query (1 for reverse)
tjc's avatar
tjc committed
      g2.setColor(Color.red);
    else
      g2.setColor(Color.blue);
    drawRead(g2, samRecord, pixPerBase, ypos, baseAtStartOfView);
tjc's avatar
tjc committed
    
tjc's avatar
tjc committed
    if (isSNPs)
tjc's avatar
tjc committed
      showSNPsOnReads(g2, samRecord, pixPerBase, ypos, offset);
tjc's avatar
tjc committed
  }
tjc's avatar
tjc committed

tjc's avatar
tjc committed
  
tjc's avatar
tjc committed
  private void drawScale(Graphics2D g2, int start, int end, float pixPerBase, int ypos)
tjc's avatar
tjc committed
  {
    g2.setColor(Color.black);
tjc's avatar
tjc committed
    g2.drawLine( 0, ypos-14,
                 (int)((end - getBaseAtStartOfView())*pixPerBase),   ypos-14);
tjc's avatar
tjc committed
    int interval = end-start;
    
    if(interval > 256000)
tjc's avatar
tjc committed
      drawTicks(g2, start, end, pixPerBase, 512000, ypos);
tjc's avatar
tjc committed
    else if(interval > 64000)
tjc's avatar
tjc committed
      drawTicks(g2, start, end, pixPerBase, 12800, ypos);
tjc's avatar
tjc committed
    else if(interval > 16000)
tjc's avatar
tjc committed
      drawTicks(g2, start, end, pixPerBase, 3200, ypos);
tjc's avatar
tjc committed
    else if(interval > 4000)
tjc's avatar
tjc committed
      drawTicks(g2, start, end, pixPerBase, 800, ypos);
tjc's avatar
tjc committed
    else if(interval > 1000)
tjc's avatar
tjc committed
      drawTicks(g2, start, end, pixPerBase, 400, ypos);
tjc's avatar
tjc committed
    else
tjc's avatar
tjc committed
      drawTicks(g2, start, end, pixPerBase, 100, ypos);
tjc's avatar
tjc committed
  }
  
tjc's avatar
tjc committed
  private void drawTicks(Graphics2D g2, int start, int end, float pixPerBase, int division, int ypos)
tjc's avatar
tjc committed
  {
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);
tjc's avatar
tjc committed
    float x;
tjc's avatar
tjc committed
    if(sm > start)
tjc's avatar
tjc committed
    {
      x = (sm-getBaseAtStartOfView())*pixPerBase;
tjc's avatar
tjc committed
      g2.drawLine((int)x, ypos-14,(int)x, ypos-12);
tjc's avatar
tjc committed
    }
tjc's avatar
tjc committed
    
    for(int m=markStart; m<end; m+=division)
    {
tjc's avatar
tjc committed
      x = (m-getBaseAtStartOfView())*pixPerBase;
tjc's avatar
tjc committed
      g2.drawString(Integer.toString(m), x, ypos-1);
      g2.drawLine((int)x, ypos-14,(int)x, ypos-11);
tjc's avatar
tjc committed
      
      sm = m+(division/2);
      
      if(sm < end)
tjc's avatar
tjc committed
      {
        x = (sm-getBaseAtStartOfView())*pixPerBase;
tjc's avatar
tjc committed
        g2.drawLine((int)x, ypos-14,(int)x, ypos-12);
tjc's avatar
tjc committed
      }
tjc's avatar
tjc committed
      
      if(m == 1)
        m = 0;
  /**
   * Draw a y-scale for inferred size (isize) of reads.
   * @param g2
   * @param xScaleHeight
   */
tjc's avatar
tjc committed
  private void drawYScale(Graphics2D g2, int xScaleHeight)
  {
    g2.setColor(Color.black);
    int maxY = getPreferredSize().height-xScaleHeight;
    if(logScale)
    {
      int start = 10;
      int count = 0;
      int ypos = getYPos(xScaleHeight, start);
      
      while(ypos > 0 && count < 15 && start > 1)
      {
        g2.drawLine(0, ypos, 2, ypos);
        g2.drawString(Integer.toString(start), 3, ypos);
        start = start*5;
        ypos = getYPos(xScaleHeight, start);
        count++;
      }
      return;
    }
    
    for(int i=100; i<maxY; i+=100)
    {
      int ypos = getHeight()-i-xScaleHeight;
tjc's avatar
tjc committed
      g2.drawLine(0, ypos, 2, ypos);
      g2.drawString(Integer.toString(i), 3, ypos);
  /**
   * Draw a given read.
   * @param g2
   * @param thisRead
   * @param pixPerBase
   * @param ypos
   * @param baseAtStartOfView
tjc's avatar
tjc committed
  private void drawRead(Graphics2D g2, SAMRecord thisRead,
		                float pixPerBase,
		                int ypos,
		                int baseAtStartOfView)
tjc's avatar
tjc committed
  {
tjc's avatar
tjc committed
    int offset = getSequenceOffset(thisRead.getReferenceName());

    int thisStart = thisRead.getAlignmentStart()+offset-baseAtStartOfView;
    int thisEnd   = thisRead.getAlignmentEnd()+offset-baseAtStartOfView;
    
    if(highlightSAMRecord != null && 
       highlightSAMRecord.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 = thisRead;
      }
    }
    
tjc's avatar
tjc committed
    if (isSNPs)
tjc's avatar
tjc committed
      showSNPsOnReads(g2, thisRead, pixPerBase, ypos, offset);
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)
  {
    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.setColor(Color.pink);
        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.
   * @param g2
   * @param thisRead
   * @param pixPerBase
   * @param ypos
   */
  private void showSNPsOnReads(Graphics2D g2, SAMRecord thisRead,
tjc's avatar
tjc committed
                               float pixPerBase, int ypos, int offset)
tjc's avatar
tjc committed
  {
    int thisStart = thisRead.getAlignmentStart();
    int thisEnd   = thisRead.getAlignmentEnd();
    
    // use alignment blocks of the contiguous alignment of
    // subsets of read bases to a reference sequence
    List<AlignmentBlock> blocks = thisRead.getAlignmentBlocks();
tjc's avatar
tjc committed
    try
tjc's avatar
tjc committed
    {
tjc's avatar
tjc committed
      char[] refSeq = bases.getSubSequenceC(
tjc's avatar
tjc committed
          new Range(thisStart+offset, thisEnd+offset), Bases.FORWARD);
tjc's avatar
tjc committed
      byte[] readSeq = thisRead.getReadBases();
tjc's avatar
tjc committed

tjc's avatar
tjc committed
      Color col = g2.getColor();
      g2.setColor(Color.red);
      offset = offset - getBaseAtStartOfView();
      for(int i=0; i<blocks.size(); i++)
tjc's avatar
tjc committed
      {
        AlignmentBlock block = blocks.get(i);
        for(int j=0; j<block.getLength(); j++)
tjc's avatar
tjc committed
        {
          int readPos = block.getReadStart()-1+j;
          int refPos  = block.getReferenceStart()+j;

          if (Character.toUpperCase(refSeq[refPos-thisStart]) != readSeq[readPos])
          {
            g2.drawLine((int) ((refPos+offset) * pixPerBase), ypos + 2,
                        (int) ((refPos+offset) * pixPerBase), ypos - 2);
tjc's avatar
tjc committed
        }
tjc's avatar
tjc committed
      }
tjc's avatar
tjc committed
      g2.setColor(col);
    }
    catch (OutOfRangeException e)
    {
      e.printStackTrace();
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();
        }
      });
      bottomPanel.add(scrollBar, BorderLayout.SOUTH);
    }

    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 int thisBamIndex)
  {
    File f = new File(bamList.get(thisBamIndex));
    final JCheckBoxMenuItem cbBam = new JCheckBoxMenuItem(
                                     f.getName(), true);
    bamFilesMenu.add(cbBam);
    cbBam.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        if(cbBam.isSelected())
          hideBamList.remove(new Integer(thisBamIndex));
        else
          hideBamList.add(new Integer(thisBamIndex));
        laststart = -1;
        repaint();
      } 
    });
  }
tjc's avatar
tjc committed

  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");
        List<String> bamFiles = bamFileSelection.getFiles(".*\\.bam$");
        int count = bamList.size();
       
        bamList.addAll(bamFileSelection.getFiles(".*\\.bam$"));
        
        for(int i=0; i<bamFiles.size(); i++)
          addToViewMenu(i+count);
tjc's avatar
tjc committed
        laststart = -1;