JAL-2600 fast painting on resize
[jalview.git] / src / jalview / gui / AnnotationPanel.java
index 04590ba..e98b79e 100755 (executable)
@@ -23,12 +23,14 @@ package jalview.gui;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.AnnotationRenderer;
 import jalview.renderer.AwtRenderPanelI;
 import jalview.schemes.ResidueProperties;
 import jalview.util.Comparison;
 import jalview.util.MessageManager;
+import jalview.viewmodel.ViewportListenerI;
 
 import java.awt.AlphaComposite;
 import java.awt.Color;
@@ -49,12 +51,13 @@ import java.awt.event.MouseMotionListener;
 import java.awt.event.MouseWheelEvent;
 import java.awt.event.MouseWheelListener;
 import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeEvent;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 import javax.swing.JColorChooser;
 import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.Scrollable;
@@ -69,7 +72,7 @@ import javax.swing.ToolTipManager;
  */
 public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         MouseListener, MouseWheelListener, MouseMotionListener,
-        ActionListener, AdjustmentListener, Scrollable
+        ActionListener, AdjustmentListener, Scrollable, ViewportListenerI
 {
   String HELIX = MessageManager.getString("label.helix");
 
@@ -122,8 +125,6 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
   boolean mouseDragging = false;
 
-  boolean MAC = false;
-
   // for editing cursor
   int cursorX = 0;
 
@@ -141,9 +142,6 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
    */
   public AnnotationPanel(AlignmentPanel ap)
   {
-
-    MAC = jalview.util.Platform.isAMac();
-
     ToolTipManager.sharedInstance().registerComponent(this);
     ToolTipManager.sharedInstance().setInitialDelay(0);
     ToolTipManager.sharedInstance().setDismissDelay(10000);
@@ -160,6 +158,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     // and then set our own listener to consume all mousewheel events
     ap.annotationScroller.addMouseWheelListener(this);
     renderer = new AnnotationRenderer();
+
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   public AnnotationPanel(AlignViewport av)
@@ -176,11 +176,11 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       e.consume();
       if (e.getWheelRotation() > 0)
       {
-        ap.scrollRight(true);
+        av.getRanges().scrollRight(true);
       }
       else
       {
-        ap.scrollRight(false);
+        av.getRanges().scrollRight(false);
       }
     }
     else
@@ -295,7 +295,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     {
       for (int index : av.getColumnSelection().getSelected())
       {
-        if (av.getColumnSelection().isVisible(index))
+        if (av.getAlignment().getHiddenColumns().isVisible(index))
         {
           anot[index] = null;
         }
@@ -304,7 +304,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     else if (action.equals(LABEL))
     {
       String exMesg = collectAnnotVals(anot, LABEL);
-      String label = JOptionPane.showInputDialog(this,
+      String label = JvOptionPane.showInputDialog(this,
               MessageManager.getString("label.enter_label"), exMesg);
 
       if (label == null)
@@ -319,7 +319,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
       for (int index : av.getColumnSelection().getSelected())
       {
-        if (!av.getColumnSelection().isVisible(index))
+        if (!av.getAlignment().getHiddenColumns().isVisible(index))
         {
           continue;
         }
@@ -342,7 +342,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
       for (int index : av.getColumnSelection().getSelected())
       {
-        if (!av.getColumnSelection().isVisible(index))
+        if (!av.getAlignment().getHiddenColumns().isVisible(index))
         {
           continue;
         }
@@ -384,7 +384,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         aa[activeRow].hasIcons = true;
       }
 
-      String label = JOptionPane.showInputDialog(MessageManager
+      String label = JvOptionPane.showInputDialog(MessageManager
               .getString("label.enter_label_for_the_structure"), symbol);
 
       if (label == null)
@@ -402,7 +402,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       }
       for (int index : av.getColumnSelection().getSelected())
       {
-        if (!av.getColumnSelection().isVisible(index))
+        if (!av.getAlignment().getHiddenColumns().isVisible(index))
         {
           continue;
         }
@@ -445,21 +445,26 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     StringBuilder collatedInput = new StringBuilder(64);
     String last = "";
     ColumnSelection viscols = av.getColumnSelection();
-    // TODO: refactor and save av.getColumnSelection for efficiency
-    List<Integer> selected = viscols.getSelected();
+    HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+
+    /*
+     * the selection list (read-only view) is in selection order, not
+     * column order; make a copy so we can sort it
+     */
+    List<Integer> selected = new ArrayList<>(viscols.getSelected());
     Collections.sort(selected);
     for (int index : selected)
     {
       // always check for current display state - just in case
-      if (!viscols.isVisible(index))
+      if (!hidden.isVisible(index))
       {
         continue;
       }
       String tlabel = null;
       if (anots[index] != null)
       { // LML added stem code
-        if (type.equals(HELIX) || type.equals(SHEET)
-                || type.equals(STEM) || type.equals(LABEL))
+        if (type.equals(HELIX) || type.equals(SHEET) || type.equals(STEM)
+                || type.equals(LABEL))
         {
           tlabel = anots[index].description;
           if (tlabel == null || tlabel.length() < 1)
@@ -543,7 +548,6 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     }
 
     ap.getScalePanel().mousePressed(evt);
-
   }
 
   /**
@@ -607,6 +611,10 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     mouseDragging = false;
     ap.getScalePanel().mouseReleased(evt);
 
+    /*
+     * isPopupTrigger is set in mouseReleased on Windows
+     * (in mousePressed on Mac)
+     */
     if (evt.isPopupTrigger() && activeRow != -1)
     {
       showPopupMenu(evt.getY(), evt.getX());
@@ -705,11 +713,13 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       return;
     }
 
-    int column = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+    int column = (evt.getX() / av.getCharWidth())
+            + av.getRanges().getStartRes();
 
     if (av.hasHiddenColumns())
     {
-      column = av.getColumnSelection().adjustForHiddenColumns(column);
+      column = av.getAlignment().getHiddenColumns()
+              .adjustForHiddenColumns(column);
     }
 
     AlignmentAnnotation ann = aa[row];
@@ -811,8 +821,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       {
         text.append(", ")
                 .append(MessageManager.getString("label.sequence"))
-                .append(" ")
-                .append(seqIndex + 1);
+                .append(" ").append(seqIndex + 1);
         char residue = seqref.getCharAt(column);
         if (!Comparison.isGap(residue))
         {
@@ -903,7 +912,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         return;
       }
     }
-    imgWidth = (av.endRes - av.startRes + 1) * av.getCharWidth();
+    imgWidth = (av.getRanges().getEndRes() - av.getRanges().getStartRes() + 1)
+            * av.getCharWidth();
     if (imgWidth < 1)
     {
       return;
@@ -944,7 +954,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       imageFresh = true;
     }
 
-    drawComponent(gg, av.startRes, av.endRes + 1);
+    drawComponent(gg, av.getRanges().getStartRes(), av.getRanges()
+            .getEndRes() + 1);
     imageFresh = false;
     g.drawImage(image, 0, 0, this);
   }
@@ -960,7 +971,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
    * @param horizontal
    *          repaint with horizontal shift in alignment
    */
-  public void fastPaint(int horizontal)
+  public void fastPaint(int horizontal, boolean isresize)
   {
     if ((horizontal == 0) || gg == null
             || av.getAlignment().getAlignmentAnnotation() == null
@@ -970,22 +981,46 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       repaint();
       return;
     }
-    long stime = System.currentTimeMillis();
-    gg.copyArea(0, 0, imgWidth, getHeight(),
-            -horizontal * av.getCharWidth(), 0);
-    long mtime = System.currentTimeMillis();
-    int sr = av.startRes;
-    int er = av.endRes + 1;
+
+    int sr = av.getRanges().getStartRes();
+    int er = av.getRanges().getEndRes() + 1;
     int transX = 0;
+    long stime;
+    long mtime;
 
-    if (horizontal > 0) // scrollbar pulled right, image to the left
+    if (isresize)
     {
-      transX = (er - sr - horizontal) * av.getCharWidth();
-      sr = er - horizontal;
+      imgWidth = (av.getRanges().getEndRes() - av.getRanges().getStartRes()
+              + 1) * av.getCharWidth();
+
+      BufferedImage newimage = new BufferedImage(imgWidth,
+              ap.getAnnotationPanel().getHeight(),
+              BufferedImage.TYPE_INT_ARGB);
+
+      gg = (Graphics2D) newimage.getGraphics();
+      gg.setFont(av.getFont());
+      gg.drawImage(image, null, 0, 0);
+      image = newimage;
+
+      transX = (er - horizontal - sr) * av.getCharWidth();
+      sr = er - horizontal - sr;
     }
-    else if (horizontal < 0)
+    else
     {
-      er = sr - horizontal;
+      stime = System.currentTimeMillis();
+      gg.copyArea(0, 0, imgWidth, getHeight(),
+              -horizontal * av.getCharWidth(), 0);
+      mtime = System.currentTimeMillis();
+
+      if (horizontal > 0) // scrollbar pulled right, image to the left
+      {
+        transX = (er - sr - horizontal) * av.getCharWidth();
+        sr = er - horizontal;
+      }
+      else if (horizontal < 0)
+      {
+        er = sr - horizontal;
+      }
     }
 
     gg.translate(transX, 0);
@@ -1131,4 +1166,40 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       return null;
     }
   }
+
+  /**
+   * Try to ensure any references held are nulled
+   */
+  public void dispose()
+  {
+    av = null;
+    ap = null;
+    image = null;
+    fadedImage = null;
+    gg = null;
+    _mwl = null;
+
+    /*
+     * I created the renderer so I will dispose of it
+     */
+    if (renderer != null)
+    {
+      renderer.dispose();
+    }
+  }
+
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    // Respond to viewport range changes (e.g. alignment panel was scrolled)
+    if (evt.getPropertyName().equals("startres"))
+    {
+      fastPaint((int) evt.getNewValue() - (int) evt.getOldValue(), false);
+    }
+    else if (evt.getPropertyName().equals("endres"))
+    {
+      // resize
+      fastPaint((int) evt.getNewValue() - (int) evt.getOldValue(), true);
+    }
+  }
 }