Merge remote-tracking branch 'origin/develop' into bug/JAL-2665-2.10.3
authorkiramt <k.mourao@dundee.ac.uk>
Mon, 28 Aug 2017 11:23:58 +0000 (12:23 +0100)
committerkiramt <k.mourao@dundee.ac.uk>
Mon, 28 Aug 2017 11:23:58 +0000 (12:23 +0100)
Conflicts:
src/jalview/gui/SeqCanvas.java

1  2 
src/jalview/datamodel/SequenceGroup.java
src/jalview/gui/AlignmentPanel.java
src/jalview/gui/SeqCanvas.java
src/jalview/gui/SeqPanel.java

Simple merge
@@@ -53,9 -52,11 +53,11 @@@ import javax.swing.JComponent
   */
  public class SeqCanvas extends JComponent implements ViewportListenerI
  {
+   private static String ZEROS = "0000000000";
    final FeatureRenderer fr;
  
 -  final SequenceRenderer sr;
 +  final SequenceRenderer seqRdr;
  
    BufferedImage img;
  
      }
    }
  
 -  AnnotationPanel annotations;
 +  /*
 +   * Draw a selection group over a wrapped alignment
 +   */
 +  private void drawWrappedSelection(Graphics2D g, SequenceGroup group,
 +          int canvasWidth,
 +          int canvasHeight, int startRes)
 +  {
 +    // height gap above each panel
 +    int hgap = charHeight;
 +    if (av.getScaleAboveWrapped())
 +    {
 +      hgap += charHeight;
 +    }
 +
-     int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / charWidth;
++    int cWidth = (canvasWidth - labelWidthEast - labelWidthWest)
++            / charWidth;
 +    int cHeight = av.getAlignment().getHeight() * charHeight;
 +
 +    int startx = startRes;
 +    int endx;
 +    int ypos = hgap; // vertical offset
 +    int maxwidth = av.getAlignment().getWidth();
 +
 +    if (av.hasHiddenColumns())
 +    {
 +      maxwidth = av.getAlignment().getHiddenColumns()
 +              .findColumnPosition(maxwidth);
 +    }
 +
 +    // chop the wrapped alignment extent up into panel-sized blocks and treat
 +    // each block as if it were a block from an unwrapped alignment
 +    while ((ypos <= canvasHeight) && (startx < maxwidth))
 +    {
 +      // set end value to be start + width, or maxwidth, whichever is smaller
 +      endx = startx + cWidth - 1;
 +
 +      if (endx > maxwidth)
 +      {
 +        endx = maxwidth;
 +      }
 +
-       g.translate(LABEL_WEST, 0);
++      g.translate(labelWidthWest, 0);
 +
 +      drawUnwrappedSelection(g, group, startx, endx, 0,
 +              av.getAlignment().getHeight() - 1,
 +              ypos);
 +
-       g.translate(-LABEL_WEST, 0);
++      g.translate(-labelWidthWest, 0);
 +
 +      // update vertical offset
 +      ypos += cHeight + getAnnotationHeight() + hgap;
 +
 +      // update horizontal offset
 +      startx += cWidth;
 +    }
 +  }
  
    int getAnnotationHeight()
    {
      return annotations.adjustPanelHeight();
    }
  
-   /*
-    * Draw an alignment panel for printing
++
+   /**
+    * Draws the visible region of the alignment on the graphics context. If there
+    * are hidden column markers in the visible region, then each sub-region
+    * between the markers is drawn separately, followed by the hidden column
+    * marker.
     * 
     * @param g1
 +   *          Graphics object to draw with
     * @param startRes
-    *          start residue of print area
+    *          offset of the first column in the visible region (0..)
     * @param endRes
-    *          end residue of print area
+    *          offset of the last column in the visible region (0..)
     * @param startSeq
-    *          start sequence of print area
+    *          offset of the first sequence in the visible region (0..)
     * @param endSeq
-    *          end sequence of print area
-    * @param offset
-    *          vertical offset
+    *          offset of the last sequence in the visible region (0..)
+    * @param yOffset
+    *          vertical offset at which to draw (for wrapped alignments)
     */
 -  public void drawPanel(Graphics g1, final int startRes, final int endRes,
 -          final int startSeq, final int endSeq, final int yOffset)
 +  private void drawPanel(Graphics g1, int startRes, int endRes,
-           int startSeq, int endSeq, int offset)
++          int startSeq, int endSeq, int yOffset)
++
    {
      updateViewport();
      if (!av.hasHiddenColumns())
  
    }
  
++
+   /**
+    * Draws a region of the visible alignment
+    * 
+    * @param g1
+    * @param startRes
+    *          offset of the first column in the visible region (0..)
+    * @param endRes
+    *          offset of the last column in the visible region (0..)
+    * @param startSeq
+    *          offset of the first sequence in the visible region (0..)
+    * @param endSeq
+    *          offset of the last sequence in the visible region (0..)
+    * @param yOffset
+    *          vertical offset at which to draw (for wrapped alignments)
+    */
    private void draw(Graphics g, int startRes, int endRes, int startSeq,
            int endSeq, int offset)
    {
  
            inGroup = false;
          }
 +      }
 +    }
  
 -        groupIndex++;
 +    if (inGroup)
 +    {
 +      sy = verticalOffset + ((i - startSeq) * charHeight);
 +      if (sx >= 0 && sx < visWidth)
 +      {
 +        g.drawLine(sx, oldY, sx, sy);
 +      }
  
 -        g.setStroke(new BasicStroke());
 +      if (sx + xwidth < visWidth)
 +      {
 +        g.drawLine(sx + xwidth, oldY, sx + xwidth, sy);
 +      }
  
 -        if (groupIndex >= av.getAlignment().getGroups().size())
 -        {
 -          break;
 -        }
 +      if (sx < 0)
 +      {
 +        xwidth += sx;
 +        sx = 0;
 +      }
  
 -        group = av.getAlignment().getGroups().get(groupIndex);
 +      if (sx + xwidth > visWidth)
 +      {
 +        xwidth = visWidth;
 +      }
 +      else if (sx + xwidth >= (endRes - startRes + 1) * charWidth)
 +      {
 +        xwidth = (endRes - startRes + 1) * charWidth;
 +      }
  
 -      } while (groupIndex < av.getAlignment().getGroups().size());
 +      if (top != -1)
 +      {
 +        g.drawLine(sx, top, sx + xwidth, top);
 +        top = -1;
 +      }
  
 -    }
 +      if (bottom != -1)
 +      {
 +        g.drawLine(sx, bottom - 1, sx + xwidth, bottom - 1);
 +        bottom = -1;
 +      }
  
 +      inGroup = false;
 +    }
    }
 -
 +  
    /**
-    * DOCUMENT ME!
+    * Highlights search results in the visible region by rendering as white text
+    * on a black background. Any previous highlighting is removed. Answers true
+    * if any highlight was left on the visible alignment (so status bar should be
+    * set to match), else false.
+    * <p>
+    * Currently fastPaint is not implemented for wrapped alignments. If a wrapped
+    * alignment had to be scrolled to show the highlighted region, then it should
+    * be fully redrawn, otherwise a fast paint can be performed. This argument
+    * could be removed if fast paint of scrolled wrapped alignment is coded in
+    * future (JAL-2609).
     * 
     * @param results
-    *          DOCUMENT ME!
+    * @param noFastPaint
+    * @return
     */
-   public void highlightSearchResults(SearchResultsI results)
+   public boolean highlightSearchResults(SearchResultsI results,
+           boolean noFastPaint)
    {
-     img = null;
+     if (fastpainting)
+     {
+       return false;
+     }
+     boolean wrapped = av.getWrapAlignment();
  
-     av.setSearchResults(results);
+     try
+     {
+       fastPaint = !noFastPaint;
+       fastpainting = fastPaint;
+       updateViewport();
+       /*
+        * to avoid redrawing the whole visible region, we instead
+        * redraw just the minimal regions to remove previous highlights
+        * and add new ones
+        */
+       SearchResultsI previous = av.getSearchResults();
+       av.setSearchResults(results);
+       boolean redrawn = false;
+       boolean drawn = false;
+       if (wrapped)
+       {
+         redrawn = drawMappedPositionsWrapped(previous);
+         drawn = drawMappedPositionsWrapped(results);
+         redrawn |= drawn;
+       }
+       else
+       {
+         redrawn = drawMappedPositions(previous);
+         drawn = drawMappedPositions(results);
+         redrawn |= drawn;
+       }
  
-     repaint();
+       /*
+        * if highlights were either removed or added, repaint
+        */
+       if (redrawn)
+       {
+         repaint();
+       }
+       /*
+        * return true only if highlights were added
+        */
+       return drawn;
+     } finally
+     {
+       fastpainting = false;
+     }
+   }
+   /**
+    * Redraws the minimal rectangle in the visible region (if any) that includes
+    * mapped positions of the given search results. Whether or not positions are
+    * highlighted depends on the SearchResults set on the Viewport. This allows
+    * this method to be called to either clear or set highlighting. Answers true
+    * if any positions were drawn (in which case a repaint is still required),
+    * else false.
+    * 
+    * @param results
+    * @return
+    */
+   protected boolean drawMappedPositions(SearchResultsI results)
+   {
+     if (results == null)
+     {
+       return false;
+     }
+     /*
+      * calculate the minimal rectangle to redraw that 
+      * includes both new and existing search results
+      */
+     int firstSeq = Integer.MAX_VALUE;
+     int lastSeq = -1;
+     int firstCol = Integer.MAX_VALUE;
+     int lastCol = -1;
+     boolean matchFound = false;
+     ViewportRanges ranges = av.getRanges();
+     int firstVisibleColumn = ranges.getStartRes();
+     int lastVisibleColumn = ranges.getEndRes();
+     AlignmentI alignment = av.getAlignment();
+     if (av.hasHiddenColumns())
+     {
+       firstVisibleColumn = alignment.getHiddenColumns()
+               .adjustForHiddenColumns(firstVisibleColumn);
+       lastVisibleColumn = alignment.getHiddenColumns()
+               .adjustForHiddenColumns(lastVisibleColumn);
+     }
+     for (int seqNo = ranges.getStartSeq(); seqNo <= ranges
+             .getEndSeq(); seqNo++)
+     {
+       SequenceI seq = alignment.getSequenceAt(seqNo);
+       int[] visibleResults = results.getResults(seq, firstVisibleColumn,
+               lastVisibleColumn);
+       if (visibleResults != null)
+       {
+         for (int i = 0; i < visibleResults.length - 1; i += 2)
+         {
+           int firstMatchedColumn = visibleResults[i];
+           int lastMatchedColumn = visibleResults[i + 1];
+           if (firstMatchedColumn <= lastVisibleColumn
+                   && lastMatchedColumn >= firstVisibleColumn)
+           {
+             /*
+              * found a search results match in the visible region - 
+              * remember the first and last sequence matched, and the first
+              * and last visible columns in the matched positions
+              */
+             matchFound = true;
+             firstSeq = Math.min(firstSeq, seqNo);
+             lastSeq = Math.max(lastSeq, seqNo);
+             firstMatchedColumn = Math.max(firstMatchedColumn,
+                     firstVisibleColumn);
+             lastMatchedColumn = Math.min(lastMatchedColumn,
+                     lastVisibleColumn);
+             firstCol = Math.min(firstCol, firstMatchedColumn);
+             lastCol = Math.max(lastCol, lastMatchedColumn);
+           }
+         }
+       }
+     }
+     if (matchFound)
+     {
+       if (av.hasHiddenColumns())
+       {
+         firstCol = alignment.getHiddenColumns()
+                 .findColumnPosition(firstCol);
+         lastCol = alignment.getHiddenColumns().findColumnPosition(lastCol);
+       }
+       int transX = (firstCol - ranges.getStartRes()) * av.getCharWidth();
+       int transY = (firstSeq - ranges.getStartSeq()) * av.getCharHeight();
+       gg.translate(transX, transY);
+       drawPanel(gg, firstCol, lastCol, firstSeq, lastSeq, 0);
+       gg.translate(-transX, -transY);
+     }
+     return matchFound;
    }
  
    @Override
Simple merge