Merge branch 'bug/JAL-3003epsWithSelection' into trialMerge
[jalview.git] / src / jalview / gui / SeqCanvas.java
index 928ce41..dd87128 100755 (executable)
@@ -45,7 +45,7 @@ import java.beans.PropertyChangeEvent;
 import java.util.Iterator;
 import java.util.List;
 
-import javax.swing.JComponent;
+import javax.swing.JPanel;
 
 /**
  * The Swing component on which the alignment sequences, and annotations (if
@@ -53,7 +53,7 @@ import javax.swing.JComponent;
  * Wrapped mode, but not the scale above in Unwrapped mode.
  * 
  */
-public class SeqCanvas extends JComponent implements ViewportListenerI
+public class SeqCanvas extends JPanel implements ViewportListenerI
 {
   private static final String ZEROS = "0000000000";
 
@@ -88,7 +88,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
   private int wrappedVisibleWidths; // number of wrapped widths displayed
 
-  private Graphics2D gg;
+  // Don't do this! Graphics handles are supposed to be transient
+  //private Graphics2D gg;
 
   /**
    * Creates a new SeqCanvas object.
@@ -195,7 +196,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     int yPos = ypos + charHeight;
     int startX = startx;
     int endX = endx;
-
+    
     if (av.hasHiddenColumns())
     {
       HiddenColumns hiddenColumns = av.getAlignment().getHiddenColumns();
@@ -231,6 +232,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
         }
       }
 
+      
       /*
        * white fill the space for the scale
        */
@@ -255,6 +257,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
         g.drawString(valueAsString, xOffset, y);
       }
     }
+
   }
 
   /**
@@ -277,7 +280,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
    */
   public void fastPaint(int horizontal, int vertical)
   {
-    if (fastpainting || gg == null || img == null)
+    if (fastpainting  || img == null)
     {
       return;
     }
@@ -297,6 +300,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       int transX = 0;
       int transY = 0;
       
+      Graphics gg = img.getGraphics();
       gg.copyArea(horizontal * charWidth, vertical * charHeight,
               img.getWidth(), img.getHeight(), -horizontal * charWidth,
               -vertical * charHeight);
@@ -337,7 +341,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       gg.translate(transX, transY);
       drawPanel(gg, startRes, endRes, startSeq, endSeq, 0);
       gg.translate(-transX, -transY);
-
+      gg.dispose();
+      
       // Call repaint on alignment panel so that repaints from other alignment
       // panel components can be aggregated. Otherwise performance of the
       // overview window and others may be adversely affected.
@@ -351,23 +356,19 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   @Override
   public void paintComponent(Graphics g)
   {
-    super.paintComponent(g);    
-    
+    super.paintComponent(g);
+
     int charHeight = av.getCharHeight();
     int charWidth = av.getCharWidth();
-    
+
     ViewportRanges ranges = av.getRanges();
-    
+
     int width = getWidth();
     int height = getHeight();
-    
+
     width -= (width % charWidth);
     height -= (height % charHeight);
-    
-    drawSelectionGroup((Graphics2D) g,
-            ranges.getStartRes(), ranges.getEndRes(),
-            ranges.getStartSeq(), ranges.getEndSeq());
-    
+
     if ((img != null) && (fastPaint
             || (getVisibleRect().width != g.getClipBounds().width)
             || (getVisibleRect().height != g.getClipBounds().height)))
@@ -389,19 +390,20 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
               || height != img.getHeight())
       {
         img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
-        gg = (Graphics2D) img.getGraphics();
-        gg.setFont(av.getFont());
       }
-    
+      
+      Graphics2D gg = (Graphics2D) img.getGraphics();
+      gg.setFont(av.getFont());
+
       if (av.antiAlias)
       {
         gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                 RenderingHints.VALUE_ANTIALIAS_ON);
       }
-    
+
       gg.setColor(Color.white);
       gg.fillRect(0, 0, img.getWidth(), img.getHeight());
-    
+
       if (av.getWrapAlignment())
       {
         drawWrappedPanel(gg, getWidth(), getHeight(), ranges.getStartRes());
@@ -563,7 +565,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     calculateWrappedGeometry(canvasWidth, canvasHeight);
 
     /*
-     * draw one width at a time (including any scales or annotation shown),
+     * draw one width at a time (excluding any scales or annotation shown),
      * until we have run out of either alignment or vertical space available
      */
     int ypos = wrappedSpaceAboveAlignment;
@@ -614,7 +616,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
      */
     wrappedRepeatHeightPx = wrappedSpaceAboveAlignment;
     // add sequences
-    wrappedRepeatHeightPx += av.getRanges().getViewportHeight()
+    wrappedRepeatHeightPx += av.getAlignment().getHeight()
             * charHeight;
     // add annotations panel height if shown
     wrappedRepeatHeightPx += getAnnotationHeight();
@@ -678,12 +680,25 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     int xOffset = labelWidthWest
             + ((startColumn - ranges.getStartRes()) % viewportWidth)
             * charWidth;
+
+    // BH 2018 note: I have switched to using Graphics.create() here because it is 
+    // more reliable (and simpler) to reset. The difference seems to be that SwingJS 
+    // automatically sets a clipping region on an image to be the image dimensions, whereas
+    // Java sets no clip for an image. (A bug? Go figure!)
+    // Since we are using an off-screen BufferedImage here, the result is that g.getClip()
+    // returns non-null in JavaScript but not Java. 
+    //
+    // Anyway, this works and, I suggest, is better design anyway. 
+    // 
+    // Graphics g = gg.create();
+    // mc 30/08/18 undone because gnu.jpdf.PDFGraphics doesn't handle
+    // get/setTransform
+
     g.translate(xOffset, 0);
 
     // When printing we have an extra clipped region,
     // the Printable page which we need to account for here
     Shape clip = g.getClip();
-
     if (clip == null)
     {
       g.setClip(0, 0, viewportWidth * charWidth, canvasHeight);
@@ -694,6 +709,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
               viewportWidth * charWidth, (int) clip.getBounds().getHeight());
     }
 
+
     /*
      * white fill the region to be drawn (so incremental fast paint doesn't
      * scribble over an existing image)
@@ -719,8 +735,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
               startColumn, endx + 1);
       g.translate(0, -cHeight - ypos - 3);
     }
-    g.setClip(clip);
+    // g.dispose();
     g.translate(-xOffset, 0);
+//    g.setClip(clip);
   }
 
   /**
@@ -735,6 +752,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     int charWidth = av.getCharWidth();
 
     g.setFont(av.getFont());
+
     g.setColor(Color.black);
 
     int ypos = wrappedSpaceAboveAlignment;
@@ -756,6 +774,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       if (av.getScaleRightWrapped())
       {
         int x = labelWidthWest + viewportWidth * charWidth;
+        
         g.translate(x, 0);
         drawVerticalScale(g, startCol, endColumn, ypos, false);
         g.translate(-x, 0);
@@ -1094,23 +1113,17 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       do
       {
         g.setColor(group.getOutlineColour());
-
         drawPartialGroupOutline(g, group, startRes, endRes, startSeq,
                 endSeq, offset);
 
         groupIndex++;
-
         if (groupIndex >= av.getAlignment().getGroups().size())
         {
           break;
         }
-
         group = av.getAlignment().getGroups().get(groupIndex);
-
       } while (groupIndex < av.getAlignment().getGroups().size());
-
     }
-
   }
 
   /**
@@ -1456,20 +1469,42 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
    * 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. This method does _not_ set the 'fastPaint' flag,
+   * so allows the next repaint to update the whole display.
+   * 
+   * @param results
+   * @return
+   */
+  public boolean highlightSearchResults(SearchResultsI results)
+  {
+    return highlightSearchResults(results, false);
+
+  }
+  
+  /**
+   * 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).
+   * Optionally, set the 'fastPaint' flag for a faster redraw if only the
+   * highlighted regions are modified. This speeds up highlighting across linked
+   * alignments.
+   * <p>
+   * Currently fastPaint is not implemented for scrolled 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
-   * @param noFastPaint
+   * @param doFastPaint
+   *          if true, sets a flag so the next repaint only redraws the modified
+   *          image
    * @return
    */
   public boolean highlightSearchResults(SearchResultsI results,
-          boolean noFastPaint)
+          boolean doFastPaint)
   {
     if (fastpainting)
     {
@@ -1478,7 +1513,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     boolean wrapped = av.getWrapAlignment();
     try
     {
-      fastPaint = !noFastPaint;
+      fastPaint = doFastPaint;
       fastpainting = fastPaint;
 
       /*
@@ -1535,7 +1570,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
    */
   protected boolean drawMappedPositions(SearchResultsI results)
   {
-    if ((results == null) || (gg == null)) // JAL-2784 check gg is not null
+    if ((results == null) || (img == null)) // JAL-2784 check gg is not null
     {
       return false;
     }
@@ -1607,9 +1642,11 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       }
       int transX = (firstCol - ranges.getStartRes()) * av.getCharWidth();
       int transY = (firstSeq - ranges.getStartSeq()) * av.getCharHeight();
+      Graphics gg = img.getGraphics();
       gg.translate(transX, transY);
       drawPanel(gg, firstCol, lastCol, firstSeq, lastSeq, 0);
       gg.translate(-transX, -transY);
+      gg.dispose();
     }
 
     return matchFound;
@@ -1730,7 +1767,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       return;
     }
 
-    if (fastpainting || gg == null)
+    if (fastpainting || img == null)
     {
       return;
     }
@@ -1740,6 +1777,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
     try
     {
+      
+      Graphics gg = img.getGraphics();
+      
       calculateWrappedGeometry(getWidth(), getHeight());
 
       /*
@@ -1768,6 +1808,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
        */
       drawWrappedDecorators(gg, ranges.getStartRes());
 
+      gg.dispose();
+      
       repaint();
     } finally
     {
@@ -1791,6 +1833,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       return;
     }
 
+    Graphics gg = img.getGraphics();
+    
     ViewportRanges ranges = av.getRanges();
     int viewportWidth = ranges.getViewportWidth();
     int charWidth = av.getCharWidth();
@@ -1817,6 +1861,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       /*
        * white fill first to erase annotations
        */
+      
+      
       gg.translate(xOffset, 0);
       gg.setColor(Color.white);
       gg.fillRect(labelWidthWest, ypos,
@@ -1824,6 +1870,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       gg.translate(-xOffset, 0);
 
       drawWrappedWidth(gg, ypos, startRes, endRes, canvasHeight);
+      
     }
 
     /*
@@ -1867,7 +1914,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       gg.setColor(Color.white);
       gg.fillRect(0, canvasHeight - heightBelow, getWidth(), heightBelow);
     }
-  }
+    gg.dispose();
+ }
 
   /**
    * Shifts the visible alignment by the specified number of columns - left if
@@ -1883,6 +1931,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     {
       return;
     }
+
+    Graphics gg = img.getGraphics();
+
     int charWidth = av.getCharWidth();
 
     int canvasHeight = getHeight();
@@ -1949,11 +2000,11 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
                   * charWidth, heightToCopy, widthToCopy,
                   -wrappedRepeatHeightPx);
         }
-
         y += wrappedRepeatHeightPx;
         xpos += viewportWidth;
       }
     }
+    gg.dispose();
   }
 
   
@@ -1969,7 +2020,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
    */
   protected boolean drawMappedPositionsWrapped(SearchResultsI results)
   {
-    if ((results == null) || (gg == null)) // JAL-2784 check gg is not null
+    if ((results == null) || (img == null)) // JAL-2784 check gg is not null
     {
       return false;
     }
@@ -2004,6 +2055,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
     int gapHeight = charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
 
+    
+    Graphics gg = img.getGraphics();
+
     for (int seqNo = ranges.getStartSeq(); seqNo <= ranges
             .getEndSeq(); seqNo++)
     {
@@ -2074,6 +2128,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       }
     }
   
+    gg.dispose();
+
     return matchFound;
   }