JAL-2491 Started moving other scrolling fns into viewportranges
[jalview.git] / src / jalview / gui / AlignmentPanel.java
index 146df38..4cfa7d5 100644 (file)
@@ -35,6 +35,8 @@ import jalview.schemes.ResidueProperties;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.viewmodel.ViewportListenerI;
+import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BorderLayout;
 import java.awt.Color;
@@ -46,6 +48,8 @@ import java.awt.Graphics;
 import java.awt.Insets;
 import java.awt.event.AdjustmentEvent;
 import java.awt.event.AdjustmentListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
 import java.awt.print.PageFormat;
 import java.awt.print.Printable;
 import java.awt.print.PrinterException;
@@ -65,10 +69,13 @@ import javax.swing.SwingUtilities;
  * @version $Revision: 1.161 $
  */
 public class AlignmentPanel extends GAlignmentPanel implements
-        AdjustmentListener, Printable, AlignmentViewPanel
+        AdjustmentListener, Printable, AlignmentViewPanel,
+        ViewportListenerI
 {
   public AlignViewport av;
 
+  ViewportRanges vpRanges;
+
   OverviewPanel overviewPanel;
 
   private SeqPanel seqPanel;
@@ -113,6 +120,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
   {
     alignFrame = af;
     this.av = av;
+    vpRanges = av.getRanges();
     setSeqPanel(new SeqPanel(av, this));
     setIdPanel(new IdPanel(av, this));
 
@@ -136,6 +144,37 @@ public class AlignmentPanel extends GAlignmentPanel implements
     hscroll.addAdjustmentListener(this);
     vscroll.addAdjustmentListener(this);
 
+    addComponentListener(new ComponentAdapter()
+    {
+      @Override
+      public void componentResized(ComponentEvent evt)
+      {
+        // reset the viewport ranges when the alignment panel is resized
+        // in particular, this initialises the end residue value when Jalview
+        // is initialised
+        
+        
+        if (av.getWrapAlignment())
+        {
+          int widthInRes = getSeqPanel().seqCanvas
+                  .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
+          vpRanges.setStartEndRes(vpRanges.getStartRes(), widthInRes);
+        }
+        else
+        {
+          int widthInRes = (getSeqPanel().seqCanvas.getWidth() / av
+                  .getCharWidth()) - 1;
+          int heightInSeq = (getSeqPanel().seqCanvas.getHeight() / av.getCharHeight()) - 1;
+          
+          vpRanges.setStartEndRes(vpRanges.getStartRes(), widthInRes);
+          vpRanges.setStartEndSeq(vpRanges.getStartSeq(), heightInSeq);
+        }
+
+        
+      }
+
+    });
+
     final AlignmentPanel ap = this;
     propertyChangeListener = new PropertyChangeListener()
     {
@@ -150,6 +189,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
       }
     };
     av.addPropertyChangeListener(propertyChangeListener);
+
+    av.getRanges().addPropertyChangeListener(this);
     fontChanged();
     adjustAnnotationHeight();
     updateLayout();
@@ -195,10 +236,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
     getIdPanel().getIdCanvas().setPreferredSize(d);
     hscrollFillerPanel.setPreferredSize(d);
 
-    if (overviewPanel != null)
-    {
-      overviewPanel.setBoxPosition();
-    }
     if (this.alignFrame.getSplitViewContainer() != null)
     {
       ((SplitFrame) this.alignFrame.getSplitViewContainer()).adjustLayout();
@@ -377,7 +414,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
        */
       if (centre)
       {
-        int offset = (av.getEndRes() - av.getStartRes() + 1) / 2 - 1;
+        int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2 - 1;
         start = Math.max(start - offset, 0);
         end = end + offset - 1;
       }
@@ -413,7 +450,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
       // + av.getStartSeq() + ", ends=" + av.getEndSeq());
       if (!av.getWrapAlignment())
       {
-        if ((startv = av.getStartRes()) >= start)
+        if ((startv = vpRanges.getStartRes()) >= start)
         {
           /*
            * Scroll left to make start of search results visible
@@ -421,7 +458,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
           // setScrollValues(start - 1, seqIndex); // plus one residue
           setScrollValues(start, seqIndex);
         }
-        else if ((endv = av.getEndRes()) <= end)
+        else if ((endv = vpRanges.getEndRes()) <= end)
         {
           /*
            * Scroll right to make end of search results visible
@@ -429,19 +466,20 @@ public class AlignmentPanel extends GAlignmentPanel implements
           // setScrollValues(startv + 1 + end - endv, seqIndex); // plus one
           setScrollValues(startv + end - endv, seqIndex);
         }
-        else if ((starts = av.getStartSeq()) > seqIndex)
+        else if ((starts = vpRanges.getStartSeq()) > seqIndex)
         {
           /*
            * Scroll up to make start of search results visible
            */
-          setScrollValues(av.getStartRes(), seqIndex);
+          setScrollValues(vpRanges.getStartRes(), seqIndex);
         }
-        else if ((ends = av.getEndSeq()) <= seqIndex)
+        else if ((ends = vpRanges.getEndSeq()) <= seqIndex)
         {
           /*
            * Scroll down to make end of search results visible
            */
-          setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1);
+          setScrollValues(vpRanges.getStartRes(), starts + seqIndex - ends
+                  + 1);
         }
         /*
          * Else results are already visible - no need to scroll
@@ -449,29 +487,15 @@ public class AlignmentPanel extends GAlignmentPanel implements
       }
       else
       {
-        scrollToWrappedVisible(start);
+        vpRanges.scrollToWrappedVisible(start);
+        // scrollToWrappedVisible(start);
       }
     }
-    if (redrawOverview && overviewPanel != null)
-    {
-      overviewPanel.setBoxPosition();
-    }
+
     paintAlignment(redrawOverview);
     return true;
   }
 
-  void scrollToWrappedVisible(int res)
-  {
-    int cwidth = getSeqPanel().seqCanvas
-            .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
-    if (res < av.getStartRes() || res >= (av.getStartRes() + cwidth))
-    {
-      vscroll.setValue((res / cwidth));
-      av.startRes = vscroll.getValue() * cwidth;
-    }
-
-  }
-
   /**
    * DOCUMENT ME!
    * 
@@ -591,7 +615,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
     fontChanged();
     setAnnotationVisible(av.isShowAnnotation());
     boolean wrap = av.getWrapAlignment();
-    av.startSeq = 0;
+    vpRanges.setStartSeq(0);
     scalePanelHolder.setVisible(!wrap);
     hscroll.setVisible(!wrap);
     idwidthAdjuster.setVisible(!wrap);
@@ -607,75 +631,28 @@ public class AlignmentPanel extends GAlignmentPanel implements
       annotationSpaceFillerHolder.setVisible(true);
     }
 
-    idSpaceFillerPanel1.setVisible(!wrap);
-
-    repaint();
-  }
-
-  // return value is true if the scroll is valid
-  public boolean scrollUp(boolean up)
-  {
-    if (up)
+    if (wrap)
     {
-      if (vscroll.getValue() < 1)
-      {
-        return false;
-      }
-
-      fastPaint = false;
-      vscroll.setValue(vscroll.getValue() - 1);
+      int widthInRes = getSeqPanel().seqCanvas
+              .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
+      vpRanges.setStartEndRes(vpRanges.getStartRes(), widthInRes);
     }
     else
     {
-      if ((vextent + vscroll.getValue()) >= av.getAlignment().getHeight())
-      {
-        return false;
-      }
+      int widthInRes = (getSeqPanel().seqCanvas.getWidth() / av
+              .getCharWidth()) - 1;
+      int heightInSeq = (getSeqPanel().seqCanvas.getHeight() / av
+              .getCharHeight()) - 1;
 
-      fastPaint = false;
-      vscroll.setValue(vscroll.getValue() + 1);
+      vpRanges.setStartEndRes(vpRanges.getStartRes(), widthInRes);
+      vpRanges.setStartEndSeq(vpRanges.getStartSeq(), heightInSeq);
     }
 
-    fastPaint = true;
+    idSpaceFillerPanel1.setVisible(!wrap);
 
-    return true;
+    repaint();
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param right
-   *          DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
-  public boolean scrollRight(boolean right)
-  {
-    if (!right)
-    {
-      if (hscroll.getValue() < 1)
-      {
-        return false;
-      }
-
-      fastPaint = false;
-      hscroll.setValue(hscroll.getValue() - 1);
-    }
-    else
-    {
-      if ((hextent + hscroll.getValue()) >= av.getAlignment().getWidth())
-      {
-        return false;
-      }
-
-      fastPaint = false;
-      hscroll.setValue(hscroll.getValue() + 1);
-    }
-
-    fastPaint = true;
-
-    return true;
-  }
 
   /**
    * Adjust row/column scrollers to show a visible position in the alignment.
@@ -692,62 +669,60 @@ public class AlignmentPanel extends GAlignmentPanel implements
     {
       return;
     }
-    int width = av.getAlignment().getWidth();
-    int height = av.getAlignment().getHeight();
 
-    if (av.hasHiddenColumns())
+    if (av.getWrapAlignment())
     {
-      // reset the width to exclude hidden columns
-      width = av.getColumnSelection().findColumnPosition(width);
+      setScrollingForWrappedPanel(x);
     }
+    else
+    {
 
-    hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
-    vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight();
+      int width = av.getAlignment().getWidth();
+      int height = av.getAlignment().getHeight();
 
-    if (hextent > width)
-    {
-      hextent = width;
-    }
+      if (av.hasHiddenColumns())
+      {
+        // reset the width to exclude hidden columns
+        width = av.getColumnSelection().findColumnPosition(width);
+      }
 
-    if (vextent > height)
-    {
-      vextent = height;
-    }
+      hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
+      vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight();
 
-    if ((hextent + x) > width)
-    {
-      x = width - hextent;
-    }
+      if (hextent > width)
+      {
+        hextent = width;
+      }
 
-    if ((vextent + y) > height)
-    {
-      y = height - vextent;
-    }
+      if (vextent > height)
+      {
+        vextent = height;
+      }
 
-    if (y < 0)
-    {
-      y = 0;
-    }
+      if ((hextent + x) > width)
+      {
+        x = width - hextent;
+      }
 
-    if (x < 0)
-    {
-      x = 0;
-    }
+      if ((vextent + y) > height)
+      {
+        y = height - vextent;
+      }
 
+      if (y < 0)
+      {
+        y = 0;
+      }
 
-    // update endRes after x has (possibly) been adjusted
-    av.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
-            .getCharWidth())) - 1);
+      if (x < 0)
+      {
+        x = 0;
+      }
 
-    /*
-     * each scroll adjustment triggers adjustmentValueChanged, which resets the
-     * 'do not scroll complement' flag; ensure it is the same for both
-     * operations
-     */
-    boolean flag = isDontScrollComplement();
-    hscroll.setValues(x, hextent, 0, width);
-    setDontScrollComplement(flag);
-    vscroll.setValues(y, vextent, 0, height);
+      // update the scroll values
+      hscroll.setValues(x, hextent, 0, width);
+      vscroll.setValues(y, vextent, 0, height);
+    }
   }
 
   /**
@@ -759,29 +734,33 @@ public class AlignmentPanel extends GAlignmentPanel implements
   @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
-    int oldX = av.getStartRes();
-    int oldY = av.getStartSeq();
-
-    if (evt.getSource() == hscroll)
-    {
-      int x = hscroll.getValue();
-      av.setStartRes(x);
-      av.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
-              .getCharWidth())) - 1);
-    }
+    int oldX = vpRanges.getStartRes();
+    int oldwidth = vpRanges.getViewportWidth();
+    int oldY = vpRanges.getStartSeq();
+    int oldheight = vpRanges.getViewportHeight();
 
-    if (evt.getSource() == vscroll)
+    if (av.getWrapAlignment())
     {
-      int offy = vscroll.getValue();
-
-      if (av.getWrapAlignment())
+      if (evt.getSource() == hscroll)
+      {
+        return; // no horizontal scroll when wrapped
+      }
+      else if (evt.getSource() == vscroll)
       {
-        if (offy > -1)
+        int offy = vscroll.getValue();
+        int rowSize = getSeqPanel().seqCanvas
+                .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
+
+        // if we're scrolling to the position we're already at, stop
+        // this prevents infinite recursion of events when the scroll/viewport
+        // ranges values are the same
+        if ((offy * rowSize == oldX) && (oldwidth == rowSize))
         {
-          int rowSize = getSeqPanel().seqCanvas
-                  .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
-          av.setStartRes(offy * rowSize);
-          av.setEndRes((offy + 1) * rowSize);
+          return;
+        }
+        else if (offy > -1)
+        {
+          vpRanges.setStartEndRes(offy * rowSize, (offy + 1) * rowSize);
         }
         else
         {
@@ -793,67 +772,50 @@ public class AlignmentPanel extends GAlignmentPanel implements
             @Override
             public void run()
             {
-              setScrollValues(av.getStartRes(), av.getStartSeq());
+              setScrollValues(vpRanges.getStartRes(),
+                      vpRanges.getStartSeq());
             }
           });
         }
       }
-      else
-      {
-        av.setStartSeq(offy);
-        av.setEndSeq(offy
-                + (getSeqPanel().seqCanvas.getHeight() / av.getCharHeight()));
-      }
-    }
-
-    if (overviewPanel != null)
-    {
-      overviewPanel.setBoxPosition();
-    }
-
-    int scrollX = av.startRes - oldX;
-    int scrollY = av.startSeq - oldY;
-
-    if (av.getWrapAlignment() || !fastPaint)
-    {
       repaint();
     }
     else
     {
-      // Make sure we're not trying to draw a panel
-      // larger than the visible window
-      if (scrollX > av.endRes - av.startRes)
-      {
-        scrollX = av.endRes - av.startRes;
-      }
-      else if (scrollX < av.startRes - av.endRes)
+      // horizontal scroll
+      if (evt.getSource() == hscroll)
       {
-        scrollX = av.startRes - av.endRes;
-      }
+        int x = hscroll.getValue();
+        int width = (getSeqPanel().seqCanvas.getWidth() / av.getCharWidth()) - 1;
 
-      if (scrollX != 0 || scrollY != 0)
+        // if we're scrolling to the position we're already at, stop
+        // this prevents infinite recursion of events when the scroll/viewport
+        // ranges values are the same
+        if ((x == oldX) && (width == oldwidth))
+        {
+          return;
+        }
+        vpRanges.setStartEndRes(x, x + width);
+      }
+      else if (evt.getSource() == vscroll)
       {
-        getIdPanel().getIdCanvas().fastPaint(scrollY);
-        getSeqPanel().seqCanvas.fastPaint(scrollX, scrollY);
-        getScalePanel().repaint();
-
-        if (av.isShowAnnotation() && scrollX != 0)
+        int y = vscroll.getValue();
+        int height = (getSeqPanel().seqCanvas.getHeight() / av
+                .getCharHeight()) - 1;
+
+        // if we're scrolling to the position we're already at, stop
+        // this prevents infinite recursion of events when the scroll/viewport
+        // ranges values are the same
+        if ((y == oldY) && (height == oldheight))
         {
-          getAnnotationPanel().fastPaint(scrollX);
+          return;
         }
+        vpRanges.setStartEndSeq(y, y + height);
+      }
+      if (!fastPaint)
+      {
+        repaint();
       }
-    }
-    /*
-     * If there is one, scroll the (Protein/cDNA) complementary alignment to
-     * match, unless we are ourselves doing that.
-     */
-    if (isDontScrollComplement())
-    {
-      setDontScrollComplement(false);
-    }
-    else
-    {
-      av.scrollComplementaryAlignment();
     }
   }
 
@@ -899,36 +861,38 @@ public class AlignmentPanel extends GAlignmentPanel implements
     validate();
 
     /*
-     * set scroll bar positions; first suppress this being 'followed' in any
-     * complementary split pane
+     * set scroll bar positions
      */
-    setDontScrollComplement(true);
+    setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
+  }
 
-    if (av.getWrapAlignment())
+  /*
+   * Set vertical scroll bar parameters for wrapped panel
+   * @param res 
+   *    the residue to scroll to
+   */
+  private void setScrollingForWrappedPanel(int res)
+  {
+    // get the width of the alignment in residues
+    int maxwidth = av.getAlignment().getWidth();
+    if (av.hasHiddenColumns())
     {
-      int maxwidth = av.getAlignment().getWidth();
-
-      if (av.hasHiddenColumns())
-      {
-        maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
-      }
-
-      int canvasWidth = getSeqPanel().seqCanvas
-              .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
-      if (canvasWidth > 0)
-      {
-        int max = maxwidth
-                / getSeqPanel().seqCanvas
-                        .getWrappedCanvasWidth(getSeqPanel().seqCanvas
-                                .getWidth()) + 1;
-        vscroll.setMaximum(max);
-        vscroll.setUnitIncrement(1);
-        vscroll.setVisibleAmount(1);
-      }
+      maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
     }
-    else
+
+    // get the width of the canvas in residues
+    int canvasWidth = getSeqPanel().seqCanvas
+            .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
+    if (canvasWidth > 0)
     {
-      setScrollValues(av.getStartRes(), av.getStartSeq());
+      // position we want to scroll to is number of canvasWidth's to get there
+      int current = res / canvasWidth;
+
+      // max scroll position: add one because extent is 1 and scrollbar value
+      // can only be set to at most max - extent
+      int max = maxwidth / canvasWidth + 1;
+      vscroll.setUnitIncrement(1);
+      vscroll.setValues(current, 1, 0, max);
     }
   }
 
@@ -1877,4 +1841,48 @@ public class AlignmentPanel extends GAlignmentPanel implements
   {
     return this.dontScrollComplement;
   }
+
+  /**
+   * Redraw sensibly.
+   * 
+   * @adjustHeight if true, try to recalculate panel height for visible
+   *               annotations
+   */
+  protected void refresh(boolean adjustHeight)
+  {
+    validateAnnotationDimensions(adjustHeight);
+    addNotify();
+    if (adjustHeight)
+    {
+      // sort, repaint, update overview
+      paintAlignment(true);
+    }
+    else
+    {
+      // lightweight repaint
+      repaint();
+    }
+  }
+
+  @Override
+  /**
+   * Property change event fired when a change is made to the viewport ranges 
+   * object associated with this alignment panel's viewport
+   */
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    // update this panel's scroll values based on the new viewport ranges values
+    int x = vpRanges.getStartRes();
+    int y = vpRanges.getStartSeq();
+    setScrollValues(x, y);
+
+    // now update any complementary alignment (its viewport ranges object
+    // is different so does not get automatically updated)
+    if (!isDontScrollComplement())
+    {
+      setDontScrollComplement(true);
+      av.scrollComplementaryAlignment();
+      setDontScrollComplement(false);
+    }
+  }
 }