Merge branch 'bug/JAL-2491' into develop
authorJim Procter <jprocter@issues.jalview.org>
Sat, 27 May 2017 13:16:18 +0000 (14:16 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Sat, 27 May 2017 13:16:18 +0000 (14:16 +0100)
31 files changed:
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AlignViewport.java
src/jalview/appletgui/AlignmentPanel.java
src/jalview/appletgui/AnnotationPanel.java
src/jalview/appletgui/IdCanvas.java
src/jalview/appletgui/IdPanel.java
src/jalview/appletgui/OverviewPanel.java
src/jalview/appletgui/ScalePanel.java
src/jalview/appletgui/SeqCanvas.java
src/jalview/appletgui/SeqPanel.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/AlignmentPanel.java
src/jalview/gui/AnnotationPanel.java
src/jalview/gui/IdCanvas.java
src/jalview/gui/IdPanel.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/Jalview2XML_V1.java
src/jalview/gui/OverviewPanel.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/SeqCanvas.java
src/jalview/gui/SeqPanel.java
src/jalview/viewmodel/OverviewDimensions.java
src/jalview/viewmodel/OverviewDimensionsHideHidden.java
src/jalview/viewmodel/OverviewDimensionsShowHidden.java
src/jalview/viewmodel/ViewportListenerI.java [new file with mode: 0644]
src/jalview/viewmodel/ViewportProperties.java
src/jalview/viewmodel/ViewportRanges.java
test/jalview/viewmodel/OverviewDimensionsHideHiddenTest.java
test/jalview/viewmodel/OverviewDimensionsShowHiddenTest.java
test/jalview/viewmodel/ViewportRangesTest.java

index f914108..2eed311 100644 (file)
@@ -601,24 +601,22 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     case KeyEvent.VK_PAGE_UP:
       if (viewport.getWrapAlignment())
       {
-        alignPanel.scrollUp(true);
+        ranges.scrollUp(true);
       }
       else
       {
-        alignPanel.setScrollValues(ranges.getStartRes(),
-                2 * ranges.getStartSeq() - ranges.getEndSeq());
+        ranges.pageUp();
       }
       break;
 
     case KeyEvent.VK_PAGE_DOWN:
       if (viewport.getWrapAlignment())
       {
-        alignPanel.scrollUp(false);
+        ranges.scrollUp(false);
       }
       else
       {
-        alignPanel
-                .setScrollValues(ranges.getStartRes(), ranges.getEndSeq());
+        ranges.pageDown();
       }
       break;
 
index 9629a5f..73cd9e9 100644 (file)
@@ -449,8 +449,9 @@ public class AlignViewport extends AlignmentViewport implements
     int seqOffset = findComplementScrollTarget(sr);
     if (!sr.isEmpty())
     {
-      complementPanel.setFollowingComplementScroll(true);
+      complementPanel.setToScrollComplementPanel(false);
       complementPanel.scrollToCentre(sr, seqOffset);
+      complementPanel.setToScrollComplementPanel(true);
     }
   }
 
index 458ed54..e402b9b 100644 (file)
@@ -28,6 +28,7 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceI;
 import jalview.structure.StructureSelectionManager;
+import jalview.viewmodel.ViewportListenerI;
 import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BorderLayout;
@@ -42,10 +43,11 @@ import java.awt.event.AdjustmentEvent;
 import java.awt.event.AdjustmentListener;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
+import java.beans.PropertyChangeEvent;
 import java.util.List;
 
 public class AlignmentPanel extends Panel implements AdjustmentListener,
-        AlignmentViewPanel
+        AlignmentViewPanel, ViewportListenerI
 {
 
   public AlignViewport av;
@@ -131,7 +133,26 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       @Override
       public void componentResized(ComponentEvent evt)
       {
-        setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
+        // 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 = seqPanel.seqCanvas
+                  .getWrappedCanvasWidth(seqPanel.seqCanvas.getWidth());
+          vpRanges.setViewportWidth(widthInRes);
+        }
+        else
+        {
+          int widthInRes = seqPanel.seqCanvas.getWidth()
+                  / av.getCharWidth();
+          int heightInSeq = seqPanel.seqCanvas.getHeight()
+                  / av.getCharHeight();
+
+          vpRanges.setViewportWidth(widthInRes);
+          vpRanges.setViewportHeight(heightInSeq);
+        }
+        // setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
         if (getSize().height > 0
                 && annotationPanelHolder.getSize().height > 0)
         {
@@ -164,6 +185,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
         }
       }
     });
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   @Override
@@ -230,11 +252,6 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     annotationPanel.repaint();
     validate();
     repaint();
-
-    if (overviewPanel != null)
-    {
-      overviewPanel.updateOverviewImage();
-    }
   }
 
   public void setIdWidth(int w, int h)
@@ -390,7 +407,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       {
         int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2 - 1;
         start = Math.max(start - offset, 0);
-        end = Math.min(end + offset, seq.getEnd() - 1);
+        end = end + offset - 1;
+        // end = Math.min(end + offset, seq.getEnd() - 1);
       }
 
       if (start < 0)
@@ -509,28 +527,13 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     }
     else
     {
-      scrollToWrappedVisible(start);
-    }
-    if (redrawOverview && overviewPanel != null)
-    {
-      overviewPanel.setBoxPosition();
+      vpRanges.scrollToWrappedVisible(start);
     }
+
     paintAlignment(redrawOverview);
     return true;
   }
 
-  void scrollToWrappedVisible(int res)
-  {
-    int cwidth = seqPanel.seqCanvas
-            .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
-    if (res <= vpRanges.getStartRes()
-            || res >= (vpRanges.getStartRes() + cwidth))
-    {
-      vscroll.setValue(res / cwidth);
-      vpRanges.setStartRes(vscroll.getValue() * cwidth);
-    }
-  }
-
   public OverviewPanel getOverviewPanel()
   {
     return overviewPanel;
@@ -672,213 +675,175 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
   int vextent = 0;
 
-  // return value is true if the scroll is valid
-  public boolean scrollUp(boolean up)
+  public void setScrollValues(int xpos, int ypos)
   {
-    if (up)
+    int x = xpos;
+    int y = ypos;
+
+    if (av.getWrapAlignment())
     {
-      if (vscroll.getValue() < 1)
-      {
-        return false;
-      }
-      setScrollValues(hscroll.getValue(), vscroll.getValue() - 1);
+      setScrollingForWrappedPanel(x);
     }
     else
     {
-      if (vextent + vscroll.getValue() >= av.getAlignment().getHeight())
-      {
-        return false;
-      }
-      setScrollValues(hscroll.getValue(), vscroll.getValue() + 1);
-    }
-
-    repaint();
-    return true;
-  }
+      int width = av.getAlignment().getWidth();
+      int height = av.getAlignment().getHeight();
 
-  public boolean scrollRight(boolean right)
-  {
-    if (!right)
-    {
-      if (hscroll.getValue() < 1)
+      if (av.hasHiddenColumns())
       {
-        return false;
+        width = av.getAlignment().getHiddenColumns()
+                .findColumnPosition(width);
       }
-      setScrollValues(hscroll.getValue() - 1, vscroll.getValue());
-    }
-    else
-    {
-      if (hextent + hscroll.getValue() >= av.getAlignment().getWidth())
+      if (x < 0)
       {
-        return false;
+        x = 0;
       }
-      setScrollValues(hscroll.getValue() + 1, vscroll.getValue());
-    }
 
-    repaint();
-    return true;
-  }
-
-  public void setScrollValues(int x, int y)
-  {
-    int width = av.getAlignment().getWidth();
-    int height = av.getAlignment().getHeight();
-
-    if (av.hasHiddenColumns())
-    {
-      width = av.getAlignment().getHiddenColumns()
-              .findColumnPosition(width);
-    }
-    if (x < 0)
-    {
-      x = 0;
-    }
+      hextent = seqPanel.seqCanvas.getSize().width / av.getCharWidth();
+      vextent = seqPanel.seqCanvas.getSize().height / av.getCharHeight();
 
+      if (hextent > width)
+      {
+        hextent = width;
+      }
 
-    hextent = seqPanel.seqCanvas.getSize().width / av.getCharWidth();
-    vextent = seqPanel.seqCanvas.getSize().height / av.getCharHeight();
-
-    if (hextent > width)
-    {
-      hextent = width;
-    }
+      if (vextent > height)
+      {
+        vextent = height;
+      }
 
-    if (vextent > height)
-    {
-      vextent = height;
-    }
+      if ((hextent + x) > width)
+      {
+        System.err.println("hextent was " + hextent + " and x was " + x);
 
-    if ((hextent + x) > width)
-    {
-      // System.err.println("hextent was " + hextent + " and x was " + x);
-      //
-      x = width - hextent;
-    }
+        x = width - hextent;
+      }
 
-    if ((vextent + y) > height)
-    {
-      y = height - vextent;
-    }
+      if ((vextent + y) > height)
+      {
+        y = height - vextent;
+      }
 
-    if (y < 0)
-    {
-      y = 0;
-    }
+      if (y < 0)
+      {
+        y = 0;
+      }
 
-    if (x < 0)
-    {
-      System.err.println("x was " + x);
-      x = 0;
-    }
+      if (x < 0)
+      {
+        System.err.println("x was " + x);
+        x = 0;
+      }
 
-    vpRanges.setStartSeq(y);
-    vpRanges.setEndSeq(y + vextent);
-    vpRanges.setStartRes(x);
-    vpRanges.setEndRes((x + (seqPanel.seqCanvas.getSize().width / av
-            .getCharWidth())) - 1);
+      hscroll.setValues(x, hextent, 0, width);
+      vscroll.setValues(y, vextent, 0, height);
 
-    hscroll.setValues(x, hextent, 0, width);
-    vscroll.setValues(y, vextent, 0, height);
+      // AWT scrollbar does not fire adjustmentValueChanged for setValues
+      // so also call adjustment code!
+      adjustHorizontal(x);
+      adjustVertical(y);
 
-    if (overviewPanel != null)
-    {
-      overviewPanel.setBoxPosition();
+      sendViewPosition();
     }
-    sendViewPosition();
-
   }
 
+  /**
+   * Respond to adjustment event when horizontal or vertical scrollbar is
+   * changed
+   * 
+   * @param evt
+   *          adjustment event encoding whether apvscroll, hscroll or vscroll
+   *          changed
+   */
   @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
-    int oldX = vpRanges.getStartRes();
-    int oldY = vpRanges.getStartSeq();
-
+    // Note that this event is NOT fired by the AWT scrollbar when setValues is
+    // called. Instead manually call adjustHorizontal and adjustVertical
+    // directly.
     if (evt == null || evt.getSource() == apvscroll)
     {
       annotationPanel.setScrollOffset(apvscroll.getValue(), false);
       alabels.setScrollOffset(apvscroll.getValue(), false);
-      // annotationPanel.image=null;
-      // alabels.image=null;
-      // alabels.repaint();
-      // annotationPanel.repaint();
     }
     if (evt == null || evt.getSource() == hscroll)
     {
       int x = hscroll.getValue();
-      vpRanges.setStartRes(x);
-      vpRanges.setEndRes(x + seqPanel.seqCanvas.getSize().width
-              / av.getCharWidth() - 1);
+      adjustHorizontal(x);
     }
 
     if (evt == null || evt.getSource() == vscroll)
     {
       int offy = vscroll.getValue();
-      if (av.getWrapAlignment())
-      {
-        int rowSize = seqPanel.seqCanvas
-                .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
-        vpRanges.setStartRes(vscroll.getValue() * rowSize);
-        vpRanges.setEndRes((vscroll.getValue() + 1) * rowSize);
-      }
-      else
-      {
-        vpRanges.setStartSeq(offy);
-        vpRanges.setEndSeq(offy + seqPanel.seqCanvas.getSize().height
-                / av.getCharHeight() - 1);
-      }
+      adjustVertical(offy);
     }
 
-    if (overviewPanel != null)
+  }
+
+  private void adjustHorizontal(int x)
+  {
+    int oldX = vpRanges.getStartRes();
+    int oldwidth = vpRanges.getViewportWidth();
+    int width = seqPanel.seqCanvas.getWidth() / av.getCharWidth();
+
+    // 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))
     {
-      overviewPanel.setBoxPosition();
+      return;
     }
+    vpRanges.setViewportStartAndWidth(x, width);
 
-    int scrollX = vpRanges.getStartRes() - oldX;
-    int scrollY = vpRanges.getStartSeq() - oldY;
-
-    if (av.getWrapAlignment() || !fastPaint || av.MAC)
+    if (av.getWrapAlignment() || !fastPaint)
     {
       repaint();
     }
-    else
+    sendViewPosition();
+  }
+
+  private void adjustVertical(int offy)
+  {
+    int oldX = vpRanges.getStartRes();
+    int oldwidth = vpRanges.getViewportWidth();
+    int oldY = vpRanges.getStartSeq();
+    int oldheight = vpRanges.getViewportHeight();
+
+    if (av.getWrapAlignment())
     {
-      // Make sure we're not trying to draw a panel
-      // larger than the visible window
-      if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
+      int rowSize = seqPanel.seqCanvas
+              .getWrappedCanvasWidth(seqPanel.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))
       {
-        scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
+        return;
       }
-      else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
+      else if (offy > -1)
       {
-        scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
+        vpRanges.setViewportStartAndWidth(offy * rowSize, rowSize);
       }
+    }
+    else
+    {
+      int height = seqPanel.seqCanvas.getHeight() / av.getCharHeight();
 
-      idPanel.idCanvas.fastPaint(scrollY);
-      seqPanel.seqCanvas.fastPaint(scrollX, scrollY);
-
-      scalePanel.repaint();
-      if (av.isShowAnnotation())
+      // 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 == oldY) && (height == oldheight))
       {
-        annotationPanel.fastPaint(vpRanges.getStartRes() - oldX);
+        return;
       }
+      vpRanges.setViewportStartAndHeight(offy, height);
     }
-    sendViewPosition();
-
-    /*
-     * If there is one, scroll the (Protein/cDNA) complementary alignment to
-     * match, unless we are ourselves doing that.
-     */
-    if (isFollowingComplementScroll())
-    {
-      setFollowingComplementScroll(false);
-    }
-    else
+    if (av.getWrapAlignment() || !fastPaint)
     {
-      AlignmentPanel ap = getComplementPanel();
-      av.scrollComplementaryAlignment(ap);
+      repaint();
     }
-
+    sendViewPosition();
   }
 
   /**
@@ -929,7 +894,6 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
      * This is like AlignmentI.findIndex(seq) but here we are matching the
      * dataset sequence not the aligned sequence
      */
-    int sequenceIndex = 0;
     boolean matched = false;
     for (SequenceI seq : seqs)
     {
@@ -938,7 +902,6 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
         matched = true;
         break;
       }
-      sequenceIndex++;
     }
     if (!matched)
     {
@@ -949,8 +912,6 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
      * Scroll to position but centring the target residue. Also set a state flag
      * to prevent adjustmentValueChanged performing this recursively.
      */
-    setFollowingComplementScroll(true);
-    // this should be scrollToPosition(sr,verticalOffset,
     scrollToPosition(sr, seqOffset, true, true);
   }
 
@@ -1005,31 +966,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       idPanel.idCanvas.setSize(d.width, canvasHeight);
     }
 
-    if (av.getWrapAlignment())
-    {
-      int maxwidth = av.getAlignment().getWidth();
-
-      if (av.hasHiddenColumns())
-      {
-        maxwidth = av.getAlignment().getHiddenColumns()
-                .findColumnPosition(maxwidth) - 1;
-      }
-
-      int canvasWidth = seqPanel.seqCanvas
-              .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
-
-      if (canvasWidth > 0)
-      {
-        int max = maxwidth / canvasWidth;
-        vscroll.setMaximum(1 + max);
-        vscroll.setUnitIncrement(1);
-        vscroll.setVisibleAmount(1);
-      }
-    }
-    else
-    {
-      setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
-    }
+    setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
 
     seqPanel.seqCanvas.repaint();
     idPanel.idCanvas.repaint();
@@ -1045,6 +982,37 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
   }
 
+  /*
+   * 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())
+    {
+      maxwidth = av.getAlignment().getHiddenColumns()
+              .findColumnPosition(maxwidth) - 1;
+    }
+
+    // get the width of the canvas in residues
+    int canvasWidth = seqPanel.seqCanvas
+            .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
+    if (canvasWidth > 0)
+    {
+      // 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);
+    }
+  }
+
   protected Panel sequenceHolderPanel = new Panel();
 
   protected Scrollbar vscroll = new Scrollbar();
@@ -1069,9 +1037,9 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
   /*
    * Flag set while scrolling to follow complementary cDNA/protein scroll. When
-   * true, suppresses invoking the same method recursively.
+   * false, suppresses invoking the same method recursively.
    */
-  private boolean followingComplementScroll;
+  private boolean scrollComplementaryPanel = true;
 
   private void jbInit() throws Exception
   {
@@ -1180,14 +1148,42 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
    * 
    * @param b
    */
-  protected void setFollowingComplementScroll(boolean b)
+  protected void setToScrollComplementPanel(boolean b)
+  {
+    this.scrollComplementaryPanel = b;
+  }
+
+  /**
+   * Get whether to scroll complement panel
+   * 
+   * @return true if cDNA/protein complement panels should be scrolled
+   */
+  protected boolean isSetToScrollComplementPanel()
   {
-    this.followingComplementScroll = b;
+    return this.scrollComplementaryPanel;
   }
 
-  protected boolean isFollowingComplementScroll()
+  @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)
   {
-    return this.followingComplementScroll;
+    // 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 (isSetToScrollComplementPanel())
+    {
+      setToScrollComplementPanel(false);
+      av.scrollComplementaryAlignment(getComplementPanel());
+      setToScrollComplementPanel(true);
+    }
+
   }
 
 }
index 5026ee4..c658811 100755 (executable)
@@ -29,6 +29,7 @@ import jalview.schemes.ResidueProperties;
 import jalview.util.Comparison;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.viewmodel.ViewportListenerI;
 
 import java.awt.Color;
 import java.awt.Dimension;
@@ -47,10 +48,11 @@ import java.awt.event.InputEvent;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
 
 public class AnnotationPanel extends Panel implements AwtRenderPanelI,
         AdjustmentListener, ActionListener, MouseListener,
-        MouseMotionListener
+        MouseMotionListener, ViewportListenerI
 {
   AlignViewport av;
 
@@ -122,6 +124,7 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
   {
     this.av = av;
     renderer = new AnnotationRenderer();
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   @Override
@@ -750,4 +753,15 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
       return null;
     }
   }
+
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    // Respond to viewport range changes (e.g. alignment panel was scrolled)
+    if (evt.getPropertyName().equals("startres")
+            || evt.getPropertyName().equals("endres"))
+    {
+      fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
+    }
+  }
 }
index db9e661..74bbcf5 100755 (executable)
@@ -21,6 +21,7 @@
 package jalview.appletgui;
 
 import jalview.datamodel.SequenceI;
+import jalview.viewmodel.ViewportListenerI;
 import jalview.viewmodel.ViewportRanges;
 
 import java.awt.Color;
@@ -28,9 +29,10 @@ import java.awt.Font;
 import java.awt.Graphics;
 import java.awt.Image;
 import java.awt.Panel;
+import java.beans.PropertyChangeEvent;
 import java.util.List;
 
-public class IdCanvas extends Panel
+public class IdCanvas extends Panel implements ViewportListenerI
 {
   protected AlignViewport av;
 
@@ -55,6 +57,7 @@ public class IdCanvas extends Panel
     setLayout(null);
     this.av = av;
     PaintRefresher.Register(this, av.getSequenceSetId());
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   public void drawIdString(Graphics gg, boolean hiddenRows, SequenceI s,
@@ -394,4 +397,15 @@ public class IdCanvas extends Panel
     }
     return false;
   }
+
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    // Respond to viewport range changes (e.g. alignment panel was scrolled)
+    if (evt.getPropertyName().equals("startseq")
+            || evt.getPropertyName().equals("endseq"))
+    {
+      fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
+    }
+  }
 }
index 4cc4a3a..66eb053 100755 (executable)
@@ -413,7 +413,7 @@ public class IdPanel extends Panel implements MouseListener,
     if (av.getRanges().getStartSeq() > index
             || av.getRanges().getEndSeq() < index)
     {
-      alignPanel.setScrollValues(av.getRanges().getStartRes(), index);
+      av.getRanges().setStartSeq(index);
     }
   }
 
@@ -441,7 +441,7 @@ public class IdPanel extends Panel implements MouseListener,
       running = true;
       while (running)
       {
-        if (alignPanel.scrollUp(up))
+        if (av.getRanges().scrollUp(up))
         {
           // scroll was ok, so add new sequence to selection
           int seq = av.getRanges().getStartSeq();
index b933d30..b3c4a37 100755 (executable)
@@ -25,6 +25,7 @@ import jalview.util.Platform;
 import jalview.viewmodel.OverviewDimensions;
 import jalview.viewmodel.OverviewDimensionsHideHidden;
 import jalview.viewmodel.OverviewDimensionsShowHidden;
+import jalview.viewmodel.ViewportListenerI;
 
 import java.awt.BorderLayout;
 import java.awt.CheckboxMenuItem;
@@ -39,9 +40,10 @@ import java.awt.event.ItemListener;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
 
 public class OverviewPanel extends Panel implements Runnable,
-        MouseMotionListener, MouseListener
+        MouseMotionListener, MouseListener, ViewportListenerI
 {
   private OverviewDimensions od;
 
@@ -69,6 +71,9 @@ public class OverviewPanel extends Panel implements Runnable,
     add(oviewCanvas, BorderLayout.CENTER);
 
     setSize(new Dimension(od.getWidth(), od.getHeight()));
+
+    av.getRanges().addPropertyChangeListener(this);
+
     addComponentListener(new ComponentAdapter()
     {
 
@@ -146,7 +151,6 @@ public class OverviewPanel extends Panel implements Runnable,
     {
       od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment()
               .getHiddenSequences(), av.getAlignment().getHiddenColumns());
-      ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
       ap.paintAlignment(false);
     }
   }
@@ -194,7 +198,7 @@ public class OverviewPanel extends Panel implements Runnable,
    * changed
    * 
    */
-  public void setBoxPosition()
+  private void setBoxPosition()
   {
     od.setBoxPosition(av.getAlignment()
 .getHiddenSequences(), av
@@ -225,6 +229,12 @@ public class OverviewPanel extends Panel implements Runnable,
     popup.show(this, e.getX(), e.getY());
   }
 
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    setBoxPosition();
+  }
+
   /*
    * Toggle overview display between showing hidden columns and hiding hidden columns
    */
index 22b4e3a..ec3e246 100755 (executable)
@@ -26,6 +26,7 @@ import jalview.datamodel.SequenceGroup;
 import jalview.renderer.ScaleRenderer;
 import jalview.renderer.ScaleRenderer.ScaleMark;
 import jalview.util.MessageManager;
+import jalview.viewmodel.ViewportListenerI;
 
 import java.awt.Color;
 import java.awt.FontMetrics;
@@ -39,10 +40,11 @@ import java.awt.event.InputEvent;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
 import java.util.List;
 
 public class ScalePanel extends Panel implements MouseMotionListener,
-        MouseListener
+        MouseListener, ViewportListenerI
 {
 
   protected int offy = 4;
@@ -72,6 +74,7 @@ public class ScalePanel extends Panel implements MouseMotionListener,
     addMouseListener(this);
     addMouseMotionListener(this);
 
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   @Override
@@ -466,4 +469,11 @@ public class ScalePanel extends Panel implements MouseMotionListener,
     }
   }
 
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    // Respond to viewport change events (e.g. alignment panel was scrolled)
+    repaint();
+  }
+
 }
index 39382c5..46a908e 100755 (executable)
@@ -28,6 +28,7 @@ import jalview.datamodel.SequenceI;
 import jalview.renderer.ScaleRenderer;
 import jalview.renderer.ScaleRenderer.ScaleMark;
 import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportListenerI;
 import jalview.viewmodel.ViewportRanges;
 
 import java.awt.Color;
@@ -35,8 +36,9 @@ import java.awt.FontMetrics;
 import java.awt.Graphics;
 import java.awt.Image;
 import java.awt.Panel;
+import java.beans.PropertyChangeEvent;
 
-public class SeqCanvas extends Panel
+public class SeqCanvas extends Panel implements ViewportListenerI
 {
   FeatureRenderer fr;
 
@@ -65,6 +67,8 @@ public class SeqCanvas extends Panel
     sr = new SequenceRenderer(av);
     PaintRefresher.Register(this, av.getSequenceSetId());
     updateViewport();
+
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   int avcharHeight = 0, avcharWidth = 0;
@@ -436,7 +440,7 @@ public class SeqCanvas extends Panel
 
     av.setWrappedWidth(cWidth);
 
-    av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth);
+    av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth - 1);
 
     int endx;
     int ypos = hgap;
@@ -866,4 +870,35 @@ public class SeqCanvas extends Panel
     repaint();
   }
 
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    if (!av.getWrapAlignment())
+    {
+      if (evt.getPropertyName().equals("startres")
+              || evt.getPropertyName().equals("endres"))
+      {
+        // Make sure we're not trying to draw a panel
+        // larger than the visible window
+        ViewportRanges vpRanges = av.getRanges();
+        int scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
+        if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
+        {
+          scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
+        }
+        else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
+        {
+          scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
+        }
+        fastPaint(scrollX, 0);
+      }
+      else if (evt.getPropertyName().equals("startseq")
+              || evt.getPropertyName().equals("endseq"))
+      {
+        fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
+      }
+    }
+
+  }
+
 }
index 2d2e3fd..14ea222 100644 (file)
@@ -228,7 +228,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     endEditing();
     if (av.getWrapAlignment())
     {
-      ap.scrollToWrappedVisible(seqCanvas.cursorX);
+      av.getRanges().scrollToWrappedVisible(seqCanvas.cursorX);
     }
     else
     {
@@ -236,17 +236,17 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       HiddenColumns hidden = av.getAlignment().getHiddenColumns();
       while (seqCanvas.cursorY < ranges.getStartSeq())
       {
-        ap.scrollUp(true);
+        ranges.scrollUp(true);
       }
       while (seqCanvas.cursorY > ranges.getEndSeq())
       {
-        ap.scrollUp(false);
+        ranges.scrollUp(false);
       }
       while (seqCanvas.cursorX < hidden.adjustForHiddenColumns(ranges
               .getStartRes()))
       {
 
-        if (!ap.scrollRight(false))
+        if (!ranges.scrollRight(false))
         {
           break;
         }
@@ -254,7 +254,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       while (seqCanvas.cursorX > hidden.adjustForHiddenColumns(ranges
               .getEndRes()))
       {
-        if (!ap.scrollRight(true))
+        if (!ranges.scrollRight(true))
         {
           break;
         }
@@ -747,10 +747,16 @@ public class SeqPanel extends Panel implements MouseMotionListener,
   {
     if (av.isFollowHighlight())
     {
+      // don't allow highlight of protein/cDNA to also scroll a complementary
+      // panel,as this sets up a feedback loop (scrolling panel 1 causes moused
+      // over residue to change abruptly, causing highlighted residue in panel 2
+      // to change, causing a scroll in panel 1 etc)
+      ap.setToScrollComplementPanel(false);
       if (ap.scrollToPosition(results, true))
       {
         ap.alignFrame.repaint();
       }
+      ap.setToScrollComplementPanel(true);
     }
     setStatusMessage(results);
     seqCanvas.highlightSearchResults(results);
@@ -1770,24 +1776,24 @@ public class SeqPanel extends Panel implements MouseMotionListener,
           if (mouseDragging && evt.getY() < 0
                   && av.getRanges().getStartSeq() > 0)
           {
-            running = ap.scrollUp(true);
+            running = av.getRanges().scrollUp(true);
           }
 
           if (mouseDragging && evt.getY() >= getSize().height
                   && av.getAlignment().getHeight() > av.getRanges()
                           .getEndSeq())
           {
-            running = ap.scrollUp(false);
+            running = av.getRanges().scrollUp(false);
           }
 
           if (mouseDragging && evt.getX() < 0)
           {
-            running = ap.scrollRight(false);
+            running = av.getRanges().scrollRight(false);
           }
 
           else if (mouseDragging && evt.getX() >= getSize().width)
           {
-            running = ap.scrollRight(true);
+            running = av.getRanges().scrollRight(true);
           }
         }
 
index 4073e3e..d849398 100644 (file)
@@ -691,23 +691,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         case KeyEvent.VK_PAGE_UP:
           if (viewport.getWrapAlignment())
           {
-            alignPanel.scrollUp(true);
+            vpRanges.scrollUp(true);
           }
           else
           {
-            alignPanel.setScrollValues(vpRanges.getStartRes(),
-                    2 * vpRanges.getStartSeq() - vpRanges.getEndSeq());
+            vpRanges.pageUp();
           }
           break;
         case KeyEvent.VK_PAGE_DOWN:
           if (viewport.getWrapAlignment())
           {
-            alignPanel.scrollUp(false);
+            vpRanges.scrollUp(false);
           }
           else
           {
-            alignPanel.setScrollValues(vpRanges.getStartRes(),
-                    vpRanges.getEndSeq());
+            vpRanges.pageDown();
           }
           break;
         }
index 6409b56..86e1144 100644 (file)
@@ -1049,8 +1049,9 @@ public class AlignViewport extends AlignmentViewport implements
       // TODO would like next line without cast but needs more refactoring...
       final AlignmentPanel complementPanel = ((AlignViewport) getCodingComplement())
               .getAlignPanel();
-      complementPanel.setDontScrollComplement(true);
+      complementPanel.setToScrollComplementPanel(false);
       complementPanel.scrollToCentre(sr, verticalOffset);
+      complementPanel.setToScrollComplementPanel(true);
     }
   }
 
index 885d79d..ce9e989 100644 (file)
@@ -36,6 +36,7 @@ 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;
@@ -48,6 +49,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;
@@ -67,7 +70,8 @@ import javax.swing.SwingUtilities;
  * @version $Revision: 1.161 $
  */
 public class AlignmentPanel extends GAlignmentPanel implements
-        AdjustmentListener, Printable, AlignmentViewPanel
+        AdjustmentListener, Printable, AlignmentViewPanel,
+        ViewportListenerI
 {
   public AlignViewport av;
 
@@ -101,9 +105,9 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
   /*
    * Flag set while scrolling to follow complementary cDNA/protein scroll. When
-   * true, suppresses invoking the same method recursively.
+   * false, suppresses invoking the same method recursively.
    */
-  private boolean dontScrollComplement;
+  private boolean scrollComplementaryPanel = true;
 
   private PropertyChangeListener propertyChangeListener;
 
@@ -143,6 +147,34 @@ 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.setViewportWidth(widthInRes);
+        }
+        else
+        {
+          int widthInRes = getSeqPanel().seqCanvas.getWidth()
+                  / av.getCharWidth();
+          int heightInSeq = getSeqPanel().seqCanvas.getHeight()
+                  / av.getCharHeight();
+          
+          vpRanges.setViewportWidth(widthInRes);
+          vpRanges.setViewportHeight(heightInSeq);
+        }
+      }
+
+    });
+
     final AlignmentPanel ap = this;
     propertyChangeListener = new PropertyChangeListener()
     {
@@ -157,6 +189,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
       }
     };
     av.addPropertyChangeListener(propertyChangeListener);
+
+    av.getRanges().addPropertyChangeListener(this);
     fontChanged();
     adjustAnnotationHeight();
     updateLayout();
@@ -207,10 +241,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();
@@ -379,9 +409,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
       }
       int start = r[0];
       int end = r[1];
-      // DEBUG
-      // System.err.println(this.av.viewName + " Seq : " + seqIndex
-      // + " Scroll to " + start + "," + end);
 
       /*
        * To centre results, scroll to positions half the visible width
@@ -421,9 +448,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
        */
       seqIndex = Math.max(0, seqIndex - verticalOffset);
 
-      // System.out.println("start=" + start + ", end=" + end + ", startv="
-      // + av.getStartRes() + ", endv=" + av.getEndRes() + ", starts="
-      // + av.getStartSeq() + ", ends=" + av.getEndSeq());
       if (!av.getWrapAlignment())
       {
         if ((startv = vpRanges.getStartRes()) >= start)
@@ -431,7 +455,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
           /*
            * Scroll left to make start of search results visible
            */
-          // setScrollValues(start - 1, seqIndex); // plus one residue
           setScrollValues(start, seqIndex);
         }
         else if ((endv = vpRanges.getEndRes()) <= end)
@@ -439,7 +462,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
           /*
            * Scroll right to make end of search results visible
            */
-          // setScrollValues(startv + 1 + end - endv, seqIndex); // plus one
           setScrollValues(startv + end - endv, seqIndex);
         }
         else if ((starts = vpRanges.getStartSeq()) > seqIndex)
@@ -463,30 +485,14 @@ public class AlignmentPanel extends GAlignmentPanel implements
       }
       else
       {
-        scrollToWrappedVisible(start);
+        vpRanges.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 < vpRanges.getStartRes()
-            || res >= (vpRanges.getStartRes() + cwidth))
-    {
-      vscroll.setValue((res / cwidth));
-      vpRanges.setStartRes(vscroll.getValue() * cwidth);
-    }
-
-  }
-
   /**
    * DOCUMENT ME!
    * 
@@ -622,75 +628,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.setViewportWidth(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.setViewportWidth(widthInRes);
+      vpRanges.setViewportHeight(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.
@@ -701,176 +660,170 @@ public class AlignmentPanel extends GAlignmentPanel implements
    *          visible row to scroll to
    * 
    */
-  public void setScrollValues(int x, int y)
+  public void setScrollValues(int xpos, int ypos)
   {
+    int x = xpos;
+    int y = ypos;
+
     if (av == null || av.getAlignment() == null)
     {
       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.getAlignment().getHiddenColumns()
-              .findColumnPosition(width);
+      setScrollingForWrappedPanel(x);
     }
+    else
+    {
+      int width = av.getAlignment().getWidth();
+      int height = av.getAlignment().getHeight();
 
-    hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
-    vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight();
+      if (av.hasHiddenColumns())
+      {
+        // reset the width to exclude hidden columns
+        width = av.getAlignment().getHiddenColumns().findColumnPosition(width);
+      }
 
-    if (hextent > width)
-    {
-      hextent = width;
-    }
+      hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
+      vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight();
 
-    if (vextent > height)
-    {
-      vextent = height;
-    }
+      if (hextent > width)
+      {
+        hextent = width;
+      }
 
-    if ((hextent + x) > width)
-    {
-      x = width - hextent;
-    }
+      if (vextent > height)
+      {
+        vextent = height;
+      }
 
-    if ((vextent + y) > height)
-    {
-      y = height - vextent;
-    }
+      if ((hextent + x) > width)
+      {
+        x = width - hextent;
+      }
 
-    if (y < 0)
-    {
-      y = 0;
-    }
+      if ((vextent + y) > height)
+      {
+        y = height - vextent;
+      }
 
-    if (x < 0)
-    {
-      x = 0;
-    }
+      if (y < 0)
+      {
+        y = 0;
+      }
 
-    // update endRes after x has (possibly) been adjusted
-    vpRanges.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);
+    }
   }
 
   /**
-   * DOCUMENT ME!
+   * Respond to adjustment event when horizontal or vertical scrollbar is
+   * changed
    * 
    * @param evt
-   *          DOCUMENT ME!
+   *          adjustment event encoding whether hscroll or vscroll changed
    */
   @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
     int oldX = vpRanges.getStartRes();
+    int oldwidth = vpRanges.getViewportWidth();
     int oldY = vpRanges.getStartSeq();
+    int oldheight = vpRanges.getViewportHeight();
 
-    if (evt.getSource() == hscroll)
-    {
-      int x = hscroll.getValue();
-      vpRanges.setStartRes(x);
-      vpRanges.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
-              .getCharWidth())) - 1);
-    }
-
-    if (evt.getSource() == vscroll)
+    if (av.getWrapAlignment())
     {
-      int offy = vscroll.getValue();
-
-      if (av.getWrapAlignment())
+      if (evt.getSource() == hscroll)
       {
-        if (offy > -1)
+        return; // no horizontal scroll when wrapped
+      }
+      else if (evt.getSource() == vscroll)
+      {
+        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());
-          vpRanges.setStartRes(offy * rowSize);
-          vpRanges.setEndRes((offy + 1) * rowSize);
+          return;
         }
-        else
+        else if (offy > -1)
         {
-          // This is only called if file loaded is a jar file that
-          // was wrapped when saved and user has wrap alignment true
-          // as preference setting
-          SwingUtilities.invokeLater(new Runnable()
-          {
-            @Override
-            public void run()
-            {
-              setScrollValues(vpRanges.getStartRes(),
-                      vpRanges.getStartSeq());
-            }
-          });
+          vpRanges.setViewportStartAndWidth(offy * rowSize, rowSize);
         }
       }
       else
       {
-        vpRanges.setStartSeq(offy);
-        vpRanges.setEndSeq(offy
-                + (getSeqPanel().seqCanvas.getHeight() / av.getCharHeight())
-                - 1);
+        // This is only called if file loaded is a jar file that
+        // was wrapped when saved and user has wrap alignment true
+        // as preference setting
+        SwingUtilities.invokeLater(new Runnable()
+        {
+          @Override
+          public void run()
+        {
+            // When updating scrolling to use ViewportChange events, this code
+            // could not be validated and it is not clear if it is now being
+            // called. Log warning here in case it is called and unforeseen
+            // problems occur
+            Cache.log
+                    .warn("Unexpected path through code: Wrapped jar file opened with wrap alignment set in preferences");
+
+            // scroll to start of panel
+            vpRanges.setStartRes(0);
+            vpRanges.setStartSeq(0);
+          }
+        });
       }
-    }
-
-    if (overviewPanel != null)
-    {
-      overviewPanel.setBoxPosition();
-    }
-
-    int scrollX = vpRanges.getStartRes() - oldX;
-    int scrollY = vpRanges.getStartSeq() - oldY;
-
-    if (av.getWrapAlignment() || !fastPaint)
-    {
       repaint();
     }
     else
     {
-      // Make sure we're not trying to draw a panel
-      // larger than the visible window
-      if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
+      // horizontal scroll
+      if (evt.getSource() == hscroll)
       {
-        scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
-      }
-      else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
-      {
-        scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
-      }
+        int x = hscroll.getValue();
+        int width = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
 
-      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.setViewportStartAndWidth(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();
+
+        // 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.setViewportStartAndHeight(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();
     }
   }
 
@@ -916,37 +869,39 @@ 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.getAlignment().getHiddenColumns()
                 .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);
-      }
     }
-    else
+
+    // get the width of the canvas in residues
+    int canvasWidth = getSeqPanel().seqCanvas
+            .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
+    if (canvasWidth > 0)
     {
-      setScrollValues(vpRanges.getStartRes(), vpRanges.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);
     }
   }
 
@@ -1902,14 +1857,19 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * 
    * @param b
    */
-  protected void setDontScrollComplement(boolean b)
+  protected void setToScrollComplementPanel(boolean b)
   {
-    this.dontScrollComplement = b;
+    this.scrollComplementaryPanel = b;
   }
 
-  protected boolean isDontScrollComplement()
+  /**
+   * Get whether to scroll complement panel
+   * 
+   * @return true if cDNA/protein complement panels should be scrolled
+   */
+  protected boolean isSetToScrollComplementPanel()
   {
-    return this.dontScrollComplement;
+    return this.scrollComplementaryPanel;
   }
 
   /**
@@ -1934,6 +1894,28 @@ public class AlignmentPanel extends GAlignmentPanel implements
     }
   }
 
+  @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 (isSetToScrollComplementPanel())
+    {
+      setToScrollComplementPanel(false);
+      av.scrollComplementaryAlignment();
+      setToScrollComplementPanel(true);
+    }
+  }
+
   /**
    * Set the reference to the PCA/Tree chooser dialog for this panel. This
    * reference should be nulled when the dialog is closed.
index 919356f..452f002 100755 (executable)
@@ -30,6 +30,7 @@ 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;
@@ -50,6 +51,7 @@ 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;
@@ -70,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");
 
@@ -156,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)
@@ -172,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
@@ -1159,4 +1163,15 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       renderer.dispose();
     }
   }
+
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    // Respond to viewport range changes (e.g. alignment panel was scrolled)
+    if (evt.getPropertyName().equals("startres")
+            || evt.getPropertyName().equals("endres"))
+    {
+      fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
+    }
+  }
 }
index 1b79f54..5ce36cb 100755 (executable)
@@ -21,6 +21,7 @@
 package jalview.gui;
 
 import jalview.datamodel.SequenceI;
+import jalview.viewmodel.ViewportListenerI;
 import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BorderLayout;
@@ -31,6 +32,7 @@ import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.RenderingHints;
 import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeEvent;
 import java.util.List;
 
 import javax.swing.JPanel;
@@ -41,7 +43,7 @@ import javax.swing.JPanel;
  * @author $author$
  * @version $Revision$
  */
-public class IdCanvas extends JPanel
+public class IdCanvas extends JPanel implements ViewportListenerI
 {
   protected AlignViewport av;
 
@@ -80,6 +82,7 @@ public class IdCanvas extends JPanel
     setLayout(new BorderLayout());
     this.av = av;
     PaintRefresher.Register(this, av.getSequenceSetId());
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   /**
@@ -516,4 +519,15 @@ public class IdCanvas extends JPanel
   {
     this.idfont = idfont;
   }
+
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    // Respond to viewport range changes (e.g. alignment panel was scrolled)
+    if (evt.getPropertyName().equals("startseq")
+            || evt.getPropertyName().equals("endseq"))
+    {
+      fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
+    }
+  }
 }
index 2074900..6097089 100755 (executable)
@@ -152,22 +152,22 @@ public class IdPanel extends JPanel implements MouseListener,
     {
       if (e.isShiftDown())
       {
-        alignPanel.scrollRight(true);
+        av.getRanges().scrollRight(true);
       }
       else
       {
-        alignPanel.scrollUp(false);
+        av.getRanges().scrollUp(false);
       }
     }
     else
     {
       if (e.isShiftDown())
       {
-        alignPanel.scrollRight(false);
+        av.getRanges().scrollRight(false);
       }
       else
       {
-        alignPanel.scrollUp(true);
+        av.getRanges().scrollUp(true);
       }
     }
   }
@@ -446,7 +446,7 @@ public class IdPanel extends JPanel implements MouseListener,
     if ((av.getRanges().getStartSeq() > index)
             || (av.getRanges().getEndSeq() < index))
     {
-      alignPanel.setScrollValues(av.getRanges().getStartRes(), index);
+      av.getRanges().setStartSeq(index);
     }
   }
 
@@ -485,7 +485,7 @@ public class IdPanel extends JPanel implements MouseListener,
 
       while (running)
       {
-        if (alignPanel.scrollUp(up))
+        if (av.getRanges().scrollUp(up))
         {
           // scroll was ok, so add new sequence to selection
           int seq = av.getRanges().getStartSeq();
index 6361caf..dee921e 100644 (file)
@@ -4464,7 +4464,7 @@ public class Jalview2XML
     af.viewport.setShowUnconserved(view.hasShowUnconserved() ? view
             .isShowUnconserved() : false);
     af.viewport.getRanges().setStartRes(view.getStartRes());
-    af.viewport.getRanges().setStartSeq(view.getStartSeq());
+    // startSeq set in af.alignPanel.updateLayout below
     af.alignPanel.updateLayout();
     ColourSchemeI cs = null;
     // apply colourschemes
index cc2f636..8d71ccf 100755 (executable)
@@ -368,7 +368,7 @@ public class Jalview2XML_V1
     af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
             view.getHeight());
     af.viewport.getRanges().setStartRes(view.getStartRes());
-    af.viewport.getRanges().setStartSeq(view.getStartSeq());
+    // startSeq set in af.alignPanel.updateLayout below
     af.viewport.setShowAnnotation(view.getShowAnnotation());
     af.viewport.setAbovePIDThreshold(view.getPidSelected());
     af.viewport.setColourText(view.getShowColourText());
index a6c3960..3fa674e 100755 (executable)
@@ -25,6 +25,7 @@ import jalview.util.Platform;
 import jalview.viewmodel.OverviewDimensions;
 import jalview.viewmodel.OverviewDimensionsHideHidden;
 import jalview.viewmodel.OverviewDimensionsShowHidden;
+import jalview.viewmodel.ViewportListenerI;
 
 import java.awt.BorderLayout;
 import java.awt.Dimension;
@@ -35,6 +36,7 @@ import java.awt.event.ComponentEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseMotionAdapter;
+import java.beans.PropertyChangeEvent;
 
 import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JPanel;
@@ -48,7 +50,8 @@ import javax.swing.SwingUtilities;
  * @author $author$
  * @version $Revision$
  */
-public class OverviewPanel extends JPanel implements Runnable
+public class OverviewPanel extends JPanel implements Runnable,
+        ViewportListenerI
 {
   private OverviewDimensions od;
 
@@ -77,10 +80,14 @@ public class OverviewPanel extends JPanel implements Runnable
             (av.isShowAnnotation() && av
                     .getAlignmentConservationAnnotation() != null));
 
+    setSize(od.getWidth(), od.getHeight());
+
     oviewCanvas = new OverviewCanvas(od, av);
     setLayout(new BorderLayout());
     add(oviewCanvas, BorderLayout.CENTER);
 
+    av.getRanges().addPropertyChangeListener(this);
+
     addComponentListener(new ComponentAdapter()
     {
       @Override
@@ -90,6 +97,7 @@ public class OverviewPanel extends JPanel implements Runnable
                 || (getHeight() != (od.getHeight())))
         {
           updateOverviewImage();
+          setBoxPosition();
         }
       }
     });
@@ -105,7 +113,7 @@ public class OverviewPanel extends JPanel implements Runnable
           od.updateViewportFromMouse(evt.getX(), evt.getY(), av
                   .getAlignment().getHiddenSequences(), av.getAlignment()
                   .getHiddenColumns());
-          ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
+
         }
       }
     });
@@ -127,7 +135,6 @@ public class OverviewPanel extends JPanel implements Runnable
           od.updateViewportFromMouse(evt.getX(), evt.getY(), av
                   .getAlignment().getHiddenSequences(), av.getAlignment()
                   .getHiddenColumns());
-          ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
         }
       }
 
@@ -191,6 +198,7 @@ public class OverviewPanel extends JPanel implements Runnable
     }
     oviewCanvas.resetOviewDims(od);
     updateOverviewImage();
+    setBoxPosition();
   }
 
   /**
@@ -232,10 +240,16 @@ public class OverviewPanel extends JPanel implements Runnable
    * changed
    * 
    */
-  public void setBoxPosition()
+  private void setBoxPosition()
   {
     od.setBoxPosition(av.getAlignment().getHiddenSequences(), av
             .getAlignment().getHiddenColumns());
     repaint();
   }
+
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    setBoxPosition();
+  }
 }
index 90f7cd2..cb19539 100755 (executable)
@@ -28,6 +28,7 @@ import jalview.renderer.ScaleRenderer;
 import jalview.renderer.ScaleRenderer.ScaleMark;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.viewmodel.ViewportListenerI;
 
 import java.awt.Color;
 import java.awt.FontMetrics;
@@ -39,6 +40,7 @@ import java.awt.event.ActionListener;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
 import java.util.List;
 
 import javax.swing.JMenuItem;
@@ -52,7 +54,7 @@ import javax.swing.ToolTipManager;
  * supports a range of mouse operations to select, hide or reveal columns.
  */
 public class ScalePanel extends JPanel implements MouseMotionListener,
-        MouseListener
+        MouseListener, ViewportListenerI
 {
   protected int offy = 4;
 
@@ -91,6 +93,8 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
 
     addMouseListener(this);
     addMouseMotionListener(this);
+
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   /**
@@ -548,4 +552,11 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
     }
   }
 
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    // Respond to viewport change events (e.g. alignment panel was scrolled)
+    repaint();
+  }
+
 }
index c2a2ccb..0e5e1b8 100755 (executable)
@@ -27,6 +27,7 @@ import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.ScaleRenderer;
 import jalview.renderer.ScaleRenderer.ScaleMark;
+import jalview.viewmodel.ViewportListenerI;
 import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BasicStroke;
@@ -38,6 +39,7 @@ import java.awt.Graphics2D;
 import java.awt.RenderingHints;
 import java.awt.Shape;
 import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeEvent;
 import java.util.List;
 
 import javax.swing.JComponent;
@@ -48,7 +50,7 @@ import javax.swing.JComponent;
  * @author $author$
  * @version $Revision$
  */
-public class SeqCanvas extends JComponent
+public class SeqCanvas extends JComponent implements ViewportListenerI
 {
   final FeatureRenderer fr;
 
@@ -89,6 +91,8 @@ public class SeqCanvas extends JComponent
     setLayout(new BorderLayout());
     PaintRefresher.Register(this, av.getSequenceSetId());
     setBackground(Color.white);
+
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   public SequenceRenderer getSequenceRenderer()
@@ -295,13 +299,12 @@ public class SeqCanvas extends JComponent
 
     if (horizontal > 0) // scrollbar pulled right, image to the left
     {
-      er++;
       transX = (er - sr - horizontal) * charWidth;
       sr = er - horizontal;
     }
     else if (horizontal < 0)
     {
-      er = sr - horizontal - 1;
+      er = sr - horizontal;
     }
     else if (vertical > 0) // scroll down
     {
@@ -512,7 +515,7 @@ public class SeqCanvas extends JComponent
 
     av.setWrappedWidth(cWidth);
 
-    av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth);
+    av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth - 1);
 
     int endx;
     int ypos = hgap;
@@ -981,4 +984,34 @@ public class SeqCanvas extends JComponent
 
     repaint();
   }
+
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    if (!av.getWrapAlignment())
+    {
+      if (evt.getPropertyName().equals("startres")
+              || evt.getPropertyName().equals("endres"))
+      {
+        // Make sure we're not trying to draw a panel
+        // larger than the visible window
+        ViewportRanges vpRanges = av.getRanges();
+        int scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
+        if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
+        {
+          scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
+        }
+        else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
+        {
+          scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
+        }
+        fastPaint(scrollX, 0);
+      }
+      else if (evt.getPropertyName().equals("startseq")
+              || evt.getPropertyName().equals("endseq"))
+      {
+        fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
+      }
+    }
+  }
 }
index 20e585a..fd6232d 100644 (file)
@@ -389,38 +389,12 @@ public class SeqPanel extends JPanel implements MouseListener,
     endEditing();
     if (av.getWrapAlignment())
     {
-      ap.scrollToWrappedVisible(seqCanvas.cursorX);
+      av.getRanges().scrollToWrappedVisible(seqCanvas.cursorX);
     }
     else
     {
-      while (seqCanvas.cursorY < av.getRanges().getStartSeq())
-      {
-        ap.scrollUp(true);
-      }
-      while (seqCanvas.cursorY > av.getRanges().getEndSeq())
-      {
-        ap.scrollUp(false);
-      }
-      if (!av.getWrapAlignment())
-      {
-        HiddenColumns hidden = av.getAlignment().getHiddenColumns();
-        while (seqCanvas.cursorX < hidden.adjustForHiddenColumns(av
-                .getRanges().getStartRes()))
-        {
-          if (!ap.scrollRight(false))
-          {
-            break;
-          }
-        }
-        while (seqCanvas.cursorX > hidden.adjustForHiddenColumns(av
-                .getRanges().getEndRes()))
-        {
-          if (!ap.scrollRight(true))
-          {
-            break;
-          }
-        }
-      }
+      av.getRanges().scrollToVisible(seqCanvas.cursorX, seqCanvas.cursorY,
+              av);
     }
     setStatusMessage(av.getAlignment().getSequenceAt(seqCanvas.cursorY),
             seqCanvas.cursorX, seqCanvas.cursorY);
@@ -696,17 +670,16 @@ public class SeqPanel extends JPanel implements MouseListener,
 
     if (av.isFollowHighlight())
     {
-      /*
-       * if scrollToPosition requires a scroll adjustment, this flag prevents
-       * another scroll event being propagated back to the originator
-       * 
-       * @see AlignmentPanel#adjustmentValueChanged
-       */
-      ap.setDontScrollComplement(true);
+      // don't allow highlight of protein/cDNA to also scroll a complementary
+      // panel,as this sets up a feedback loop (scrolling panel 1 causes moused
+      // over residue to change abruptly, causing highlighted residue in panel 2
+      // to change, causing a scroll in panel 1 etc)
+      ap.setToScrollComplementPanel(false);
       if (ap.scrollToPosition(results, false))
       {
         seqCanvas.revalidate();
       }
+      ap.setToScrollComplementPanel(true);
     }
     setStatusMessage(results);
     seqCanvas.highlightSearchResults(results);
@@ -1587,23 +1560,23 @@ public class SeqPanel extends JPanel implements MouseListener,
     {
       if (e.isShiftDown())
       {
-        ap.scrollRight(true);
+        av.getRanges().scrollRight(true);
 
       }
       else
       {
-        ap.scrollUp(false);
+        av.getRanges().scrollUp(false);
       }
     }
     else
     {
       if (e.isShiftDown())
       {
-        ap.scrollRight(false);
+        av.getRanges().scrollRight(false);
       }
       else
       {
-        ap.scrollUp(true);
+        av.getRanges().scrollUp(true);
       }
     }
     // TODO Update tooltip for new position.
@@ -1971,23 +1944,23 @@ public class SeqPanel extends JPanel implements MouseListener,
           if (mouseDragging && (evt.getY() < 0)
                   && (av.getRanges().getStartSeq() > 0))
           {
-            running = ap.scrollUp(true);
+            running = av.getRanges().scrollUp(true);
           }
 
           if (mouseDragging && (evt.getY() >= getHeight())
                   && (av.getAlignment().getHeight() > av.getRanges()
                           .getEndSeq()))
           {
-            running = ap.scrollUp(false);
+            running = av.getRanges().scrollUp(false);
           }
 
           if (mouseDragging && (evt.getX() < 0))
           {
-            running = ap.scrollRight(false);
+            running = av.getRanges().scrollRight(false);
           }
           else if (mouseDragging && (evt.getX() >= getWidth()))
           {
-            running = ap.scrollRight(true);
+            running = av.getRanges().scrollRight(true);
           }
         }
 
index a837d53..d2912d8 100644 (file)
@@ -31,24 +31,41 @@ import java.awt.Graphics;
 public abstract class OverviewDimensions
 {
   protected static final int MAX_WIDTH = 400;
+
   protected static final int MIN_WIDTH = 120;
+
   protected static final int MIN_SEQ_HEIGHT = 40;
+
   protected static final int MAX_SEQ_HEIGHT = 300;
 
   private static final int DEFAULT_GRAPH_HEIGHT = 20;
 
   protected int width;
+
   protected int sequencesHeight;
+
   protected int graphHeight = DEFAULT_GRAPH_HEIGHT;
+
   protected int boxX = -1;
+
   protected int boxY = -1;
+
   protected int boxWidth = -1;
+
   protected int boxHeight = -1;
-  protected int scrollCol = -1;
-  protected int scrollRow = -1;
+
   protected int alwidth;
+
   protected int alheight;
 
+  /**
+   * Create an OverviewDimensions object
+   * 
+   * @param ranges
+   *          positional properties of the viewport
+   * @param showAnnotationPanel
+   *          true if the annotation panel is to be shown, false otherwise
+   */
   public OverviewDimensions(ViewportRanges ranges,
           boolean showAnnotationPanel)
   {
@@ -97,16 +114,6 @@ public abstract class OverviewDimensions
     g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);
   }
 
-  public int getScrollCol()
-  {
-    return scrollCol;
-  }
-
-  public int getScrollRow()
-  {
-    return scrollRow;
-  }
-
   public int getBoxX()
   {
     return boxX;
@@ -218,8 +225,8 @@ public abstract class OverviewDimensions
    */
   protected abstract void resetAlignmentDims();
 
-  protected void setBoxPosition(int startRes, int endRes, int startSeq,
-          int endSeq)
+  protected void setBoxPosition(int startRes, int startSeq, int vpwidth,
+          int vpheight)
   {
     resetAlignmentDims();
 
@@ -228,12 +235,9 @@ public abstract class OverviewDimensions
     boxY = Math.round((float) startSeq * sequencesHeight / alheight);
 
     // boxWidth is the width in residues translated to pixels
-    // since the box includes both the start and end residues, add 1 to the
-    // difference
-    boxWidth = Math
-            .round((float) (endRes - startRes + 1) * width / alwidth);
+    boxWidth = Math.round((float) vpwidth * width / alwidth);
+
     // boxHeight is the height in sequences translated to pixels
-    boxHeight = Math.round((float) (endSeq - startSeq + 1)
-            * sequencesHeight / alheight);
+    boxHeight = Math.round((float) vpheight * sequencesHeight / alheight);
   }
 }
\ No newline at end of file
index b03f9ac..4bf7694 100644 (file)
@@ -51,20 +51,20 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions
     int xAsRes = Math.round((float) x * alwidth / width);
 
     // get viewport width in residues
-    int vpwidth = ranges.getEndRes() - ranges.getStartRes() + 1;
+    int vpwidth = ranges.getViewportWidth();
 
     if (xAsRes + vpwidth > alwidth)
     {
       // went past the end of the alignment, adjust backwards
 
       // if last position was before the end of the alignment, need to update
-      if ((scrollCol + vpwidth - 1) < alwidth)
+      if (ranges.getStartRes() < alwidth)
       {
         xAsRes = alwidth - vpwidth;
       }
       else
       {
-        xAsRes = scrollCol;
+        xAsRes = ranges.getStartRes();
       }
     }
 
@@ -78,24 +78,24 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions
 
     // get viewport height in sequences
     // add 1 because height includes both endSeq and startSeq
-    int vpheight = ranges.getEndSeq() - ranges.getStartSeq() + 1;
+    int vpheight = ranges.getViewportHeight();
 
     if (yAsSeq + vpheight > alheight)
     {
       // went past the end of the alignment, adjust backwards
-      if ((scrollRow + vpheight - 1) < alheight)
+      if (ranges.getEndSeq() < alheight)
       {
         yAsSeq = alheight - vpheight;
       }
       else
       {
-        yAsSeq = scrollRow;
+        yAsSeq = ranges.getStartSeq();
       }
     }
 
-    // update scroll values
-    scrollCol = xAsRes;
-    scrollRow = yAsSeq;
+    // update viewport
+    ranges.setStartRes(xAsRes);
+    ranges.setStartSeq(yAsSeq);
 
   }
 
@@ -103,15 +103,8 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions
   public void setBoxPosition(HiddenSequences hiddenSeqs,
           HiddenColumns hiddenCols)
   {
-    // work with visible values of startRes and endRes
-    int startRes = ranges.getStartRes();
-    int endRes = ranges.getEndRes();
-
-    // work with visible values of startSeq and endSeq
-    int startSeq = ranges.getStartSeq();
-    int endSeq = ranges.getEndSeq();
-
-    setBoxPosition(startRes, endRes, startSeq, endSeq);
+    setBoxPosition(ranges.getStartRes(), ranges.getStartSeq(),
+            ranges.getViewportWidth(), ranges.getViewportHeight());
   }
 
   @Override
index b897189..4b396a6 100644 (file)
@@ -93,7 +93,7 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions
     int xAsRes = Math.round((float) x * alwidth / width);
 
     // get viewport width in residues
-    int vpwidth = ranges.getEndRes() - ranges.getStartRes() + 1;
+    int vpwidth = ranges.getViewportWidth();
 
     // get where x should be when accounting for hidden cols
     // if x is in a hidden col region, shift to left - but we still need
@@ -108,14 +108,14 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions
       // went past the end of the alignment, adjust backwards
 
       // if last position was before the end of the alignment, need to update
-      if ((scrollCol + vpwidth - 1) < visAlignWidth)
+      if (ranges.getEndRes() < visAlignWidth)
       {
         visXAsRes = hiddenCols.findColumnPosition(hiddenCols
                 .subtractVisibleColumns(vpwidth - 1, alwidth - 1));
       }
       else
       {
-        visXAsRes = scrollCol;
+        visXAsRes = ranges.getStartRes();
       }
     }
 
@@ -127,8 +127,7 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions
     int yAsSeq = Math.round((float) y * alheight / sequencesHeight);
 
     // get viewport height in sequences
-    // add 1 because height includes both endSeq and startSeq
-    int vpheight = ranges.getEndSeq() - ranges.getStartSeq() + 1;
+    int vpheight = ranges.getViewportHeight();
 
     // get where y should be when accounting for hidden rows
     // if y is in a hidden row region, shift up - but we still need absolute
@@ -143,20 +142,20 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions
     if (visYAsSeq + vpheight - 1 > visAlignHeight)
     {
       // went past the end of the alignment, adjust backwards
-      if ((scrollRow + vpheight - 1) < visAlignHeight)
+      if (ranges.getEndSeq() < visAlignHeight)
       {
         visYAsSeq = hiddenSeqs.findIndexWithoutHiddenSeqs(hiddenSeqs
                 .subtractVisibleRows(vpheight - 1, alheight - 1));
       }
       else
       {
-        visYAsSeq = scrollRow;
+        visYAsSeq = ranges.getStartSeq();
       }
     }
 
-    // update scroll values
-    scrollCol = visXAsRes;
-    scrollRow = visYAsSeq;
+    // update viewport
+    ranges.setStartRes(visXAsRes);
+    ranges.setStartSeq(visYAsSeq);
 
   }
 
@@ -176,15 +175,15 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions
           HiddenColumns hiddenCols)
   {
     // work with absolute values of startRes and endRes
-    int startRes = hiddenCols
-            .adjustForHiddenColumns(ranges.getStartRes());
+    int startRes = hiddenCols.adjustForHiddenColumns(ranges.getStartRes());
     int endRes = hiddenCols.adjustForHiddenColumns(ranges.getEndRes());
 
     // work with absolute values of startSeq and endSeq
     int startSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getStartSeq());
     int endSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getEndSeq());
 
-    setBoxPosition(startRes, endRes, startSeq, endSeq);
+    setBoxPosition(startRes, startSeq, endRes - startRes + 1, endSeq
+            - startSeq + 1);
   }
 
   @Override
diff --git a/src/jalview/viewmodel/ViewportListenerI.java b/src/jalview/viewmodel/ViewportListenerI.java
new file mode 100644 (file)
index 0000000..555089e
--- /dev/null
@@ -0,0 +1,8 @@
+package jalview.viewmodel;
+
+import java.beans.PropertyChangeListener;
+
+public interface ViewportListenerI extends PropertyChangeListener
+{
+
+}
index 246806e..a78a1c0 100644 (file)
  */
 package jalview.viewmodel;
 
+import java.beans.PropertyChangeSupport;
+
 public abstract class ViewportProperties
 {
+  protected PropertyChangeSupport changeSupport = new PropertyChangeSupport(
+          this);
+
+  public void addPropertyChangeListener(ViewportListenerI listener)
+  {
+    changeSupport.addPropertyChangeListener(listener);
+  }
+
+  public void removePropertyChangeListener(ViewportListenerI listener)
+  {
+    changeSupport.removePropertyChangeListener(listener);
+  }
 
 }
index fc163e0..da39e36 100644 (file)
  */
 package jalview.viewmodel;
 
+import jalview.api.AlignViewportI;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
 
 /**
- * Embryonic class which: Supplies and updates viewport properties relating to
- * position such as: start and end residues and sequences; ideally will serve
- * hidden columns/rows too. Intention also to support calculations for
- * positioning, scrolling etc. such as finding the middle of the viewport,
+ * Slightly less embryonic class which: Supplies and updates viewport properties
+ * relating to position such as: start and end residues and sequences; ideally
+ * will serve hidden columns/rows too. Intention also to support calculations
+ * for positioning, scrolling etc. such as finding the middle of the viewport,
  * checking for scrolls off screen
  */
 public class ViewportRanges extends ViewportProperties
@@ -95,79 +97,159 @@ public class ViewportRanges extends ViewportProperties
   }
 
   /**
-   * Set first residue visible in the viewport
+   * Set first residue visible in the viewport, and retain the current width.
+   * Fires a property change event.
    * 
    * @param res
    *          residue position
    */
   public void setStartRes(int res)
   {
-    if (res > al.getWidth() - 1)
+    int width = getViewportWidth();
+    setStartEndRes(res, res + width - 1);
+  }
+
+  /**
+   * Set start and end residues at the same time. This method only fires one
+   * event for the two changes, and should be used in preference to separate
+   * calls to setStartRes and setEndRes.
+   * 
+   * @param start
+   *          the start residue
+   * @param end
+   *          the end residue
+   */
+  public void setStartEndRes(int start, int end)
+  {
+    int oldstartres = this.startRes;
+    if (start > al.getWidth() - 1)
+    {
+      startRes = al.getWidth() - 1;
+    }
+    else if (start < 0)
+    {
+      startRes = 0;
+    }
+    else
     {
-      res = al.getWidth() - 1;
+      startRes = start;
     }
-    else if (res < 0)
+
+    int oldendres = this.endRes;
+    if (end < 0)
     {
-      res = 0;
+      endRes = 0;
+    }
+    else
+    {
+      endRes = end;
+    }
+
+    changeSupport.firePropertyChange("startres", oldstartres, startRes);
+    if (oldstartres == startRes)
+    {
+      // event won't be fired if start positions are same
+      // fire an event for the end positions in case they changed
+      changeSupport.firePropertyChange("endres", oldendres, endRes);
     }
-    this.startRes = res;
   }
 
   /**
-   * Set last residue visible in the viewport
+   * Set last residue visible in the viewport. Fires a property change event.
    * 
    * @param res
    *          residue position
    */
   public void setEndRes(int res)
   {
-    if (res >= al.getWidth())
-    {
-      res = al.getWidth() - 1;
-    }
-    else if (res < 0)
+    int startres = res;
+    int width = getViewportWidth();
+    if (startres + width - 1 > al.getWidth() - 1)
     {
-      res = 0;
+      startres = al.getWidth() - width;
     }
-    this.endRes = res;
+    setStartEndRes(startres - width + 1, startres);
   }
 
   /**
-   * Set the first sequence visible in the viewport
+   * Set the first sequence visible in the viewport, maintaining the height. If
+   * the viewport would extend past the last sequence, sets the viewport so it
+   * sits at the bottom of the alignment. Fires a property change event.
    * 
    * @param seq
    *          sequence position
    */
   public void setStartSeq(int seq)
   {
-    if (seq > al.getHeight() - 1)
+    int startseq = seq;
+    int height = getViewportHeight();
+    if (startseq + height - 1 > al.getHeight() - 1)
+    {
+      startseq = al.getHeight() - height;
+    }
+    setStartEndSeq(startseq, startseq + height - 1);
+  }
+
+  /**
+   * Set start and end sequences at the same time. The viewport height may
+   * change. This method only fires one event for the two changes, and should be
+   * used in preference to separate calls to setStartSeq and setEndSeq.
+   * 
+   * @param start
+   *          the start sequence
+   * @param end
+   *          the end sequence
+   */
+  public void setStartEndSeq(int start, int end)
+  {
+    int oldstartseq = this.startSeq;
+    if (start > al.getHeight() - 1)
+    {
+      startSeq = al.getHeight() - 1;
+    }
+    else if (start < 0)
+    {
+      startSeq = 0;
+    }
+    else
+    {
+      startSeq = start;
+    }
+
+    int oldendseq = this.endSeq;
+    if (end >= al.getHeight())
+    {
+      endSeq = al.getHeight() - 1;
+    }
+    else if (end < 0)
+    {
+      endSeq = 0;
+    }
+    else
     {
-      seq = al.getHeight() - 1;
+      endSeq = end;
     }
-    else if (seq < 0)
+
+    changeSupport.firePropertyChange("startseq", oldstartseq, startSeq);
+    if (oldstartseq == startSeq)
     {
-      seq = 0;
+      // event won't be fired if start positions are the same
+      // fire in case the end positions changed
+      changeSupport.firePropertyChange("endseq", oldendseq, endSeq);
     }
-    this.startSeq = seq;
   }
 
   /**
-   * Set the last sequence visible in the viewport
+   * Set the last sequence visible in the viewport. Fires a property change
+   * event.
    * 
    * @param seq
    *          sequence position
    */
   public void setEndSeq(int seq)
   {
-    if (seq >= al.getHeight())
-    {
-      seq = al.getHeight() - 1;
-    }
-    else if (seq < 0)
-    {
-      seq = 0;
-    }
-    this.endSeq = seq;
+    int height = getViewportHeight();
+    setStartEndSeq(seq - height + 1, seq);
   }
 
   /**
@@ -201,4 +283,231 @@ public class ViewportRanges extends ViewportProperties
   {
     return endSeq;
   }
+
+  /**
+   * Set viewport width in residues, without changing startRes. Use in
+   * preference to calculating endRes from the width, to avoid out by one
+   * errors! Fires a property change event.
+   * 
+   * @param w
+   *          width in residues
+   */
+  public void setViewportWidth(int w)
+  {
+    setStartEndRes(startRes, startRes + w - 1);
+  }
+
+  /**
+   * Set viewport height in residues, without changing startSeq. Use in
+   * preference to calculating endSeq from the height, to avoid out by one
+   * errors! Fires a property change event.
+   * 
+   * @param h
+   *          height in sequences
+   */
+  public void setViewportHeight(int h)
+  {
+    setStartEndSeq(startSeq, startSeq + h - 1);
+  }
+
+  /**
+   * Set viewport horizontal start position and width. Use in preference to
+   * calculating endRes from the width, to avoid out by one errors! Fires a
+   * property change event.
+   * 
+   * @param start
+   *          start residue
+   * @param w
+   *          width in residues
+   */
+  public void setViewportStartAndWidth(int start, int w)
+  {
+    int vpstart = start;
+    if (vpstart < 0)
+    {
+      vpstart = 0;
+    }
+    else if (vpstart + w - 1 > al.getWidth() - 1)
+    {
+      vpstart = al.getWidth() - 1;
+    }
+    setStartEndRes(vpstart, vpstart + w - 1);
+  }
+
+  /**
+   * Set viewport vertical start position and height. Use in preference to
+   * calculating endSeq from the height, to avoid out by one errors! Fires a
+   * property change event.
+   * 
+   * @param start
+   *          start sequence
+   * @param h
+   *          height in sequences
+   */
+  public void setViewportStartAndHeight(int start, int h)
+  {
+    int vpstart = start;
+    if (vpstart < 0)
+    {
+      vpstart = 0;
+    }
+    else if (vpstart + h - 1 > al.getHeight() - 1)
+    {
+      vpstart = al.getHeight() - h;
+    }
+    setStartEndSeq(vpstart, vpstart + h - 1);
+  }
+
+  /**
+   * Get width of viewport in residues
+   * 
+   * @return width of viewport
+   */
+  public int getViewportWidth()
+  {
+    return (endRes - startRes + 1);
+  }
+
+  /**
+   * Get height of viewport in residues
+   * 
+   * @return height of viewport
+   */
+  public int getViewportHeight()
+  {
+    return (endSeq - startSeq + 1);
+  }
+
+  /**
+   * Scroll the viewport range vertically. Fires a property change event.
+   * 
+   * @param up
+   *          true if scrolling up, false if down
+   * 
+   * @return true if the scroll is valid
+   */
+  public boolean scrollUp(boolean up)
+  {
+    if (up)
+    {
+      if (startSeq < 1)
+      {
+        return false;
+      }
+
+      setStartSeq(startSeq - 1);
+    }
+    else
+    {
+      if (endSeq >= al.getHeight() - 1)
+      {
+        return false;
+      }
+
+      setStartSeq(startSeq + 1);
+    }
+    return true;
+  }
+
+  /**
+   * Scroll the viewport range horizontally. Fires a property change event.
+   * 
+   * @param right
+   *          true if scrolling right, false if left
+   * 
+   * @return true if the scroll is valid
+   */
+  public boolean scrollRight(boolean right)
+  {
+    if (!right)
+    {
+      if (startRes < 1)
+      {
+        return false;
+      }
+
+      setStartRes(startRes - 1);
+    }
+    else
+    {
+      if (endRes > al.getWidth() - 1)
+      {
+        return false;
+      }
+
+      setStartRes(startRes + 1);
+    }
+
+    return true;
+  }
+
+  /**
+   * Scroll a wrapped alignment so that the specified residue is visible. Fires
+   * a property change event.
+   * 
+   * @param res
+   *          residue position to scroll to
+   */
+  public void scrollToWrappedVisible(int res)
+  {
+    // get the start residue of the wrapped row which res is in
+    // and set that as our start residue
+    int width = getViewportWidth();
+    setStartRes((res / width) * width);
+  }
+
+  /**
+   * Scroll so that (x,y) is visible. Fires a property change event.
+   * 
+   * @param x
+   *          x position in alignment
+   * @param y
+   *          y position in alignment
+   * @param av
+   *          viewport to be visible in. Here until hidden columns JAL-2388
+   *          merged, then use alignment to get hidden cols
+   */
+  public void scrollToVisible(int x, int y, AlignViewportI av)
+  {
+    while (y < startSeq)
+    {
+      scrollUp(true);
+    }
+    while (y > endSeq)
+    {
+      scrollUp(false);
+    }
+
+    HiddenColumns hidden = al.getHiddenColumns();
+    while (x < hidden.adjustForHiddenColumns(startRes))
+    {
+      if (!scrollRight(false))
+      {
+        break;
+      }
+    }
+    while (x > hidden.adjustForHiddenColumns(endRes))
+    {
+      if (!scrollRight(true))
+      {
+        break;
+      }
+    }
+  }
+  
+  /**
+   * Adjust sequence position for page up. Fires a property change event.
+   */
+  public void pageUp()
+  {
+    setViewportStartAndHeight(2 * startSeq - endSeq, getViewportHeight());
+  }
+  
+  /**
+   * Adjust sequence position for page down. Fires a property change event.
+   */
+  public void pageDown()
+  {
+    setViewportStartAndHeight(endSeq, getViewportHeight());
+  }
 }
index 2bd9c47..0e931eb 100644 (file)
@@ -79,10 +79,8 @@ public class OverviewDimensionsHideHiddenTest
     hiddenCols.revealAllHiddenColumns(colsel);
     
     vpranges = new ViewportRanges(al);
-    vpranges.setStartRes(0);
-    vpranges.setEndRes(62);
-    vpranges.setStartSeq(0);
-    vpranges.setEndSeq(17);
+    vpranges.setViewportStartAndHeight(0, 18);
+    vpranges.setViewportStartAndWidth(0, 63);
 
     viewHeight = vpranges.getEndSeq() - vpranges.getStartSeq() + 1;
     viewWidth = vpranges.getEndRes() - vpranges.getStartRes() + 1;
@@ -204,26 +202,26 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // negative boxX value reset to 0
     mouseClick(od, -5, 10);
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollRow(),
+    assertEquals(vpranges.getStartSeq(),
             Math.round((float) 10 * alheight / od.getSequencesHeight()));
-    assertEquals(od.getScrollCol(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
 
     // negative boxY value reset to 0
     mouseClick(od, 6, -2);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) 6 * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // overly large boxX value reset to width-boxWidth
     mouseClick(od, 100, 6);
@@ -231,9 +229,10 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), 6);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
 
@@ -243,13 +242,14 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight());
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
 
     // here (float) od.getBoxY() * alheight / od.getSequencesHeight() = 507.5
     // and round rounds to 508; however we get 507 working with row values
     // hence the subtraction of 1
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()) - 1);
 
@@ -258,9 +258,10 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
 
@@ -274,19 +275,20 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), oldboxx + 5);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
     assertEquals(od.getBoxY(), oldboxy + 2);
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
 
     // click at top corner
     mouseClick(od, 0, 0);
     assertEquals(od.getBoxX(), 0);
-    assertEquals(od.getScrollCol(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
     assertEquals(od.getBoxY(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
   }
@@ -302,8 +304,8 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide cols at start and check updated box position is correct
     int lastHiddenCol = 30;
@@ -313,8 +315,8 @@ public class OverviewDimensionsHideHiddenTest
 
     // click to right of hidden columns, box moves to click point
     testBoxIsAtClickPoint(40, 0);
-    assertEquals(od.getScrollRow(), 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartSeq(), 0);
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) 40 * alwidth / od.getWidth()));
 
     // click to right of hidden columns such that box runs over right hand side
@@ -327,9 +329,9 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
   }
 
   /**
@@ -344,8 +346,8 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
     
     // hide columns 63-73, no change to box position or dimensions
     int firstHidden = 63;
@@ -357,8 +359,8 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so that it overlaps with hidden cols on one side
     // box width, boxX and scrollCol as for unhidden case
@@ -366,35 +368,35 @@ public class OverviewDimensionsHideHiddenTest
                               // between cols 60 and 70
     mouseClick(od, xpos, 0);
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round(xpos * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so that it completely covers hidden cols
     // box width, boxX and scrollCol as for unhidden case
     xpos = 33;
     mouseClick(od, xpos, 0);
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) xpos * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so boxX is in hidden cols, box overhangs at right
     // boxX and scrollCol at left of hidden area, box width unchanged
     xpos = 50;
     mouseClick(od, xpos, 0);
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) xpos * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so boxX is to right of hidden cols, but does not go beyond full
     // width of alignment
     // box width, boxX and scrollCol all as for non-hidden case
     xpos = 75;
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollRow(), 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartSeq(), 0);
+    assertEquals(vpranges.getStartRes(),
             Math.round(xpos * alwidth / od.getWidth()));
     
     // move box so it goes beyond full width of alignment
@@ -405,9 +407,9 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
   }
 
@@ -422,8 +424,8 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide columns 140-164, no change to box position or dimensions
     int firstHidden = 140;
@@ -433,15 +435,15 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // click to left of hidden cols, without overlapping
     // boxX, scrollCol and width as normal
     int xpos = 5;
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollRow(), 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartSeq(), 0);
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) xpos * alwidth / od.getWidth()));
 
     // click to left of hidden cols, with overlap
@@ -449,9 +451,9 @@ public class OverviewDimensionsHideHiddenTest
     xpos = Math.round((float) 145 * od.getWidth() / alwidth) - boxWidth;
     mouseClick(od, xpos, 0);
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) xpos * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // click off end of alignment
     // boxX and scrollCol adjusted backwards, width normal
@@ -461,9 +463,9 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
   }
 
   /**
@@ -750,8 +752,8 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxHeight(), boxHeight);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide rows at start and check updated box position is correct
     int lastHiddenRow = 30;
@@ -795,8 +797,8 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide rows in middle and check updated box position is correct
     // no changes
@@ -855,8 +857,8 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide rows at end and check updated box position is correct
     // no changes
@@ -911,8 +913,7 @@ public class OverviewDimensionsHideHiddenTest
    */
   private void moveViewportH(int startRes)
   {
-    vpranges.setStartRes(startRes);
-    vpranges.setEndRes(startRes + viewWidth - 1);
+    vpranges.setViewportStartAndWidth(startRes, viewWidth);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
 
@@ -921,8 +922,7 @@ public class OverviewDimensionsHideHiddenTest
    */
   private void moveViewportV(int startSeq)
   {
-    vpranges.setStartSeq(startSeq);
-    vpranges.setEndSeq(startSeq + viewHeight - 1);
+    vpranges.setViewportStartAndHeight(startSeq, viewHeight);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
 
@@ -931,28 +931,21 @@ public class OverviewDimensionsHideHiddenTest
    */
   private void moveViewport(int startRes, int startSeq)
   {
-    vpranges.setStartRes(startRes);
-    vpranges.setEndRes(startRes + viewWidth - 1);
-    vpranges.setStartSeq(startSeq);
-    vpranges.setEndSeq(startSeq + viewHeight - 1);
+    vpranges.setViewportStartAndWidth(startRes, viewWidth);
+    vpranges.setViewportStartAndHeight(startSeq, viewHeight);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
 
   /*
    * Mouse click as position x,y in overview window
    */
-  private void mouseClick(OverviewDimensionsHideHidden od, int x, int y)
+  private void mouseClick(OverviewDimensions od, int x, int y)
   {
     od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols);
 
     // updates require an OverviewPanel to exist which it doesn't here
     // so call setBoxPosition() as it would be called by the AlignmentPanel
     // normally
-
-    vpranges.setStartRes(od.getScrollCol());
-    vpranges.setEndRes(od.getScrollCol() + viewWidth - 1);
-    vpranges.setStartSeq(od.getScrollRow());
-    vpranges.setEndSeq(od.getScrollRow() + viewHeight - 1);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
   
index 8297159..1bc3bfa 100644 (file)
@@ -78,10 +78,8 @@ public class OverviewDimensionsShowHiddenTest
     hiddenCols.revealAllHiddenColumns(colsel);
     
     vpranges = new ViewportRanges(al);
-    vpranges.setStartRes(0);
-    vpranges.setEndRes(62);
-    vpranges.setStartSeq(0);
-    vpranges.setEndSeq(17);
+    vpranges.setViewportStartAndHeight(0, 18);
+    vpranges.setViewportStartAndWidth(0, 63);
 
     viewHeight = vpranges.getEndSeq() - vpranges.getStartSeq() + 1;
     viewWidth = vpranges.getEndRes() - vpranges.getStartRes() + 1;
@@ -203,26 +201,26 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // negative boxX value reset to 0
     mouseClick(od, -5, 10);
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollRow(),
+    assertEquals(vpranges.getStartSeq(),
             Math.round((float) 10 * alheight / od.getSequencesHeight()));
-    assertEquals(od.getScrollCol(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
 
     // negative boxY value reset to 0
     mouseClick(od, 6, -2);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) 6 * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // overly large boxX value reset to width-boxWidth
     mouseClick(od, 100, 6);
@@ -230,9 +228,10 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 6);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
 
@@ -242,13 +241,14 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight());
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
 
     // here (float) od.getBoxY() * alheight / od.getSequencesHeight() = 507.5
     // and round rounds to 508; however we get 507 working with row values
     // hence the subtraction of 1
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()) - 1);
 
@@ -257,9 +257,10 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
 
@@ -273,19 +274,20 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), oldboxx + 5);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
     assertEquals(od.getBoxY(), oldboxy + 2);
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
 
     // click at top corner
     mouseClick(od, 0, 0);
     assertEquals(od.getBoxX(), 0);
-    assertEquals(od.getScrollCol(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
     assertEquals(od.getBoxY(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
   }
@@ -301,8 +303,8 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide cols at start and check updated box position is correct
     // changes boxX but not boxwidth
@@ -326,13 +328,13 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollRow(), 0);
-    assertEquals(od.getScrollCol(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
 
     // click to right of hidden columns, box moves to click point
     testBoxIsAtClickPoint(40, 0);
-    assertEquals(od.getScrollRow(), 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartSeq(), 0);
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) 40 * alwidth / od.getWidth())
                     - (lastHiddenCol + 1));
 
@@ -346,10 +348,11 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 5);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth())
                     - (lastHiddenCol + 1));
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
   }
@@ -365,8 +368,8 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
     
     // hide columns 63-73, no change to box position or dimensions
     int firstHidden = 63;
@@ -377,8 +380,8 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so that it overlaps with hidden cols on one side
     // box width changes, boxX and scrollCol as for unhidden case
@@ -392,9 +395,9 @@ public class OverviewDimensionsShowHiddenTest
             Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
                     * od.getWidth() / alwidth));
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round(xpos * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so that it completely covers hidden cols
     // box width changes, boxX and scrollCol as for hidden case
@@ -407,9 +410,9 @@ public class OverviewDimensionsShowHiddenTest
             Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
                     * od.getWidth() / alwidth));
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) xpos * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so boxX is in hidden cols, box overhangs at right
     // boxX and scrollCol at left of hidden area, box width extends across
@@ -425,16 +428,16 @@ public class OverviewDimensionsShowHiddenTest
                     + Math.round((float) (lastHidden - firstHidden + 1)
                             * od.getWidth() / alwidth));
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(), firstHidden - 1);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), firstHidden - 1);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so boxX is to right of hidden cols, but does not go beyond full
     // width of alignment
     // box width, boxX and scrollCol all as for non-hidden case
     xpos = 75;
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollRow(), 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartSeq(), 0);
+    assertEquals(vpranges.getStartRes(),
             Math.round(xpos * alwidth / od.getWidth())
                     - (lastHidden - firstHidden + 1));
     
@@ -446,10 +449,12 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 5);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(
+            vpranges.getStartRes(),
             Math.round(((float) od.getBoxX() * alwidth / od.getWidth())
                     - (lastHidden - firstHidden + 1)));
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
 
@@ -466,8 +471,8 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide columns 140-164, no change to box position or dimensions
     int firstHidden = 140;
@@ -477,15 +482,15 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // click to left of hidden cols, without overlapping
     // boxX, scrollCol and width as normal
     int xpos = 5;
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollRow(), 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartSeq(), 0);
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) xpos * alwidth / od.getWidth()));
 
     // click to left of hidden cols, with overlap
@@ -498,9 +503,9 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // click in hidden cols
     // boxX and scrollCol adjusted for hidden cols, width normal
@@ -511,9 +516,9 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // click off end of alignment
     // boxX and scrollCol adjusted for hidden cols, width normal
@@ -524,9 +529,9 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
   }
 
   /**
@@ -791,8 +796,8 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxHeight(), boxHeight);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide rows at start and check updated box position is correct
     // changes boxY but not boxheight
@@ -838,8 +843,8 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide rows in middle and check updated box position is correct
     // no changes
@@ -895,8 +900,8 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide rows at end and check updated box position is correct
     // no changes
@@ -951,8 +956,7 @@ public class OverviewDimensionsShowHiddenTest
    */
   private void moveViewportH(int startRes)
   {
-    vpranges.setStartRes(startRes);
-    vpranges.setEndRes(startRes + viewWidth - 1);
+    vpranges.setViewportStartAndWidth(startRes, viewWidth);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
 
@@ -961,8 +965,7 @@ public class OverviewDimensionsShowHiddenTest
    */
   private void moveViewportV(int startSeq)
   {
-    vpranges.setStartSeq(startSeq);
-    vpranges.setEndSeq(startSeq + viewHeight - 1);
+    vpranges.setViewportStartAndHeight(startSeq, viewHeight);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
 
@@ -971,28 +974,21 @@ public class OverviewDimensionsShowHiddenTest
    */
   private void moveViewport(int startRes, int startSeq)
   {
-    vpranges.setStartRes(startRes);
-    vpranges.setEndRes(startRes + viewWidth - 1);
-    vpranges.setStartSeq(startSeq);
-    vpranges.setEndSeq(startSeq + viewHeight - 1);
+    vpranges.setViewportStartAndWidth(startRes, viewWidth);
+    vpranges.setViewportStartAndHeight(startSeq, viewHeight);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
 
   /*
    * Mouse click as position x,y in overview window
    */
-  private void mouseClick(OverviewDimensionsShowHidden od, int x, int y)
+  private void mouseClick(OverviewDimensions od, int x, int y)
   {
     od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols);
 
     // updates require an OverviewPanel to exist which it doesn't here
     // so call setBoxPosition() as it would be called by the AlignmentPanel
     // normally
-
-    vpranges.setStartRes(od.getScrollCol());
-    vpranges.setEndRes(od.getScrollCol() + viewWidth - 1);
-    vpranges.setStartSeq(od.getScrollRow());
-    vpranges.setEndSeq(od.getScrollRow() + viewHeight - 1);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
   
index cfd03cd..3cd2096 100644 (file)
@@ -1,10 +1,16 @@
 package jalview.viewmodel;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
 
 import jalview.analysis.AlignmentGenerator;
 import jalview.datamodel.AlignmentI;
 
+import java.beans.PropertyChangeEvent;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
 import org.testng.annotations.Test;
 
 public class ViewportRangesTest {
@@ -13,7 +19,7 @@ public class ViewportRangesTest {
 
   AlignmentI al = gen.generate(20, 30, 1, 5, 5);
 
-  @Test
+  @Test(groups = { "Functional" })
   public void testViewportRanges() 
   {
     ViewportRanges vr = new ViewportRanges(al);
@@ -24,7 +30,7 @@ public class ViewportRangesTest {
     assertEquals(vr.getEndSeq(), al.getHeight() - 1);
   }
 
-  @Test
+  @Test(groups = { "Functional" })
   public void testGetAbsoluteAlignmentHeight()
   {
     ViewportRanges vr = new ViewportRanges(al);
@@ -35,28 +41,25 @@ public class ViewportRangesTest {
     assertEquals(vr.getAbsoluteAlignmentHeight(), al.getHeight() + 1);
   }
 
-  @Test
+  @Test(groups = { "Functional" })
   public void testGetAbsoluteAlignmentWidth()
   {
     ViewportRanges vr = new ViewportRanges(al);
     assertEquals(vr.getAbsoluteAlignmentWidth(), al.getWidth());
   }
 
-  @Test
+  @Test(groups = { "Functional" })
   public void testSetEndRes()
   {
     ViewportRanges vr = new ViewportRanges(al);
     vr.setEndRes(-1);
     assertEquals(vr.getEndRes(), 0);
 
-    vr.setEndRes(al.getWidth());
-    assertEquals(vr.getEndRes(), al.getWidth() - 1);
-
     vr.setEndRes(al.getWidth() - 1);
     assertEquals(vr.getEndRes(), al.getWidth() - 1);
   }
 
-  @Test
+  @Test(groups = { "Functional" })
   public void testSetEndSeq()
   {
     ViewportRanges vr = new ViewportRanges(al);
@@ -70,7 +73,7 @@ public class ViewportRangesTest {
     assertEquals(vr.getEndSeq(), al.getHeight() - 1);
   }
 
-  @Test
+  @Test(groups = { "Functional" })
   public void testSetStartRes()
   {
     ViewportRanges vr = new ViewportRanges(al);
@@ -84,17 +87,394 @@ public class ViewportRangesTest {
     assertEquals(vr.getStartRes(), al.getWidth() - 1);
   }
 
-  @Test
+  @Test(groups = { "Functional" })
   public void testSetStartSeq()
   {
     ViewportRanges vr = new ViewportRanges(al);
     vr.setStartSeq(-1);
     assertEquals(vr.getStartSeq(), 0);
 
-    vr.setStartSeq(al.getHeight());
-    assertEquals(vr.getStartSeq(), al.getHeight() - 1);
+    vr.setStartSeq(al.getHeight() - vr.getViewportHeight() + 1);
+    assertEquals(vr.getStartSeq(), al.getHeight() - vr.getViewportHeight());
+
+    vr.setStartSeq(al.getHeight() - vr.getViewportHeight());
+    assertEquals(vr.getStartSeq(), al.getHeight() - vr.getViewportHeight());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetStartEndRes()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setStartEndRes(-1, -1);
+    assertEquals(vr.getStartRes(), 0);
+    assertEquals(vr.getEndRes(), 0);
+
+    vr.setStartEndRes(5, 19);
+    assertEquals(vr.getStartRes(), 5);
+    assertEquals(vr.getEndRes(), 19);
+
+    vr.setStartEndRes(al.getWidth(), al.getWidth());
+    assertEquals(vr.getEndRes(), al.getWidth());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetStartEndSeq()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setStartEndSeq(-1, -1);
+    assertEquals(vr.getStartSeq(), 0);
+    assertEquals(vr.getEndSeq(), 0);
+
+    vr.setStartEndSeq(5, 19);
+    assertEquals(vr.getStartSeq(), 5);
+    assertEquals(vr.getEndSeq(), 19);
+
+    vr.setStartEndSeq(al.getHeight(), al.getHeight());
+    assertEquals(vr.getEndSeq(), al.getHeight() - 1);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetViewportHeight()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportHeight(13);
+    assertEquals(vr.getViewportHeight(), 13);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetViewportWidth()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportWidth(13);
+    assertEquals(vr.getViewportWidth(), 13);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetViewportStartAndHeight()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportStartAndHeight(2, 6);
+    assertEquals(vr.getViewportHeight(), 6);
+    assertEquals(vr.getStartSeq(), 2);
+
+    // reset -ve values of start to 0
+    vr.setViewportStartAndHeight(-1, 7);
+    assertEquals(vr.getViewportHeight(), 7);
+    assertEquals(vr.getStartSeq(), 0);
+
+    // reset out of bounds start values to within bounds
+    vr.setViewportStartAndHeight(35, 5);
+    assertEquals(vr.getViewportHeight(), 5);
+    assertEquals(vr.getStartSeq(), 24);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetViewportStartAndWidth()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportStartAndWidth(2, 6);
+    assertEquals(vr.getViewportWidth(), 6);
+    assertEquals(vr.getStartRes(), 2);
+
+    // reset -ve values of start to 0
+    vr.setViewportStartAndWidth(-1, 7);
+    assertEquals(vr.getViewportWidth(), 7);
+    assertEquals(vr.getStartRes(), 0);
+
+    // reset out of bounds start values to within bounds
+    vr.setViewportStartAndWidth(35, 5);
+    assertEquals(vr.getViewportWidth(), 5);
+    assertEquals(vr.getStartRes(), 20);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testPageUpDown()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportStartAndHeight(8, 6);
+    vr.pageDown();
+    assertEquals(vr.getStartSeq(), 13);
+
+    vr.pageUp();
+    assertEquals(vr.getStartSeq(), 8);
+
+    vr.pageUp();
+    assertEquals(vr.getStartSeq(), 3);
+
+    vr.pageUp();
+    // pageup does not go beyond 0, viewport height stays the same
+    assertEquals(vr.getStartSeq(), 0);
+    assertEquals(vr.getViewportHeight(), 6);
+
+    vr.pageDown();
+    vr.pageDown();
+    vr.pageDown();
+    vr.pageDown();
+    vr.pageDown();
+
+    // pagedown to bottom does not go beyond end, and height stays same
+    assertEquals(vr.getStartSeq(), 23);
+    assertEquals(vr.getViewportHeight(), 6);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testScrollUp()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportStartAndHeight(1, 5);
+    vr.scrollUp(true);
+    assertEquals(vr.getStartSeq(), 0);
+    // can't scroll above top
+    vr.scrollUp(true);
+    assertEquals(vr.getStartSeq(), 0);
+
+    vr.setViewportStartAndHeight(23, 5);
+    vr.scrollUp(false);
+    assertEquals(vr.getStartSeq(), 24);
+    // can't scroll beyond bottom
+    vr.scrollUp(false);
+    assertEquals(vr.getStartSeq(), 24);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testScrollRight()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportStartAndWidth(1, 5);
+    vr.scrollRight(false);
+    assertEquals(vr.getStartRes(), 0);
+    // can't scroll left past start
+    vr.scrollRight(false);
+    assertEquals(vr.getStartRes(), 0);
+
+    vr.setViewportStartAndWidth(19, 5);
+    vr.scrollRight(true);
+    assertEquals(vr.getStartRes(), 20);
+    // can't scroll right past end
+    vr.scrollRight(true);
+    assertEquals(vr.getStartRes(), 20);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testScrollToWrappedVisible()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportStartAndWidth(5, 10);
+
+    vr.scrollToWrappedVisible(0);
+    assertEquals(vr.getStartRes(), 0);
+
+    vr.scrollToWrappedVisible(10);
+    assertEquals(vr.getStartRes(), 10);
+
+    vr.scrollToWrappedVisible(15);
+    assertEquals(vr.getStartRes(), 10);
+  }
+
+  // leave until JAL-2388 is merged and we can do without viewport
+  /*@Test(groups = { "Functional" })
+  public void testScrollToVisible()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportStartAndWidth(12,5);
+    vr.setViewportStartAndHeight(10,6);
+    vr.scrollToVisible(13,14)
+    
+    // no change
+    assertEquals(vr.getStartRes(), 12);
+    assertEquals(vr.getStartSeq(), 10);
+    
+    vr.scrollToVisible(5,6);
+    assertEquals(vr.getStartRes(), 5);
+    assertEquals(vr.getStartSeq(), 6);
+    
+    // test for hidden columns too
+  }*/
+
+  @Test(groups = { "Functional" })
+  public void testEventFiring()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    MockPropChangeListener l = new MockPropChangeListener(vr);
+    List<String> emptylist = new ArrayList<String>();
+
+    vr.setViewportWidth(5);
+    vr.setViewportHeight(5);
+    l.reset();
+
+    // one event fired when startRes is called with new value
+    vr.setStartRes(4);
+    assertTrue(l.verify(1, Arrays.asList("startres")));
+    l.reset();
+
+    // no event fired for same value
+    vr.setStartRes(4);
+    assertTrue(l.verify(0, emptylist));
+    l.reset();
+
+    vr.setEndRes(10);
+    assertTrue(l.verify(1, Arrays.asList("startres")));
+    l.reset();
+
+    // no event fired for same value
+    vr.setEndRes(10);
+    assertTrue(l.verify(0, emptylist));
+    l.reset();
+
+    vr.setStartSeq(4);
+    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    l.reset();
+
+    vr.setStartSeq(4);
+    assertTrue(l.verify(0, emptylist));
+    l.reset();
+
+    vr.setEndSeq(10);
+    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    l.reset();
+
+    vr.setEndSeq(10);
+    assertTrue(l.verify(0, emptylist));
+    l.reset();
+
+    vr.setStartEndRes(2, 15);
+    assertTrue(l.verify(1, Arrays.asList("startres")));
+    l.reset();
+
+    vr.setStartEndRes(2, 15);
+    assertTrue(l.verify(0, emptylist));
+    l.reset();
+
+    // check new value fired by event is corrected startres
+    vr.setStartEndRes(-1, 5);
+    assertTrue(l.verify(1, Arrays.asList("startres"), Arrays.asList(0)));
+    l.reset();
+
+    // check new value fired by event is corrected endres
+    vr.setStartEndRes(0, -1);
+    assertTrue(l.verify(1, Arrays.asList("endres"), Arrays.asList(0)));
+    l.reset();
+
+    vr.setStartEndSeq(2, 15);
+    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    l.reset();
+
+    vr.setStartEndSeq(2, 15);
+    assertTrue(l.verify(0, emptylist));
+    l.reset();
+
+    vr.setStartEndRes(2, 2); // so seq and res values should be different, in
+                             // case of transposing in code
+    l.reset();
 
-    vr.setStartSeq(al.getHeight() - 1);
-    assertEquals(vr.getStartSeq(), al.getHeight() - 1);
+    // check new value fired by event is corrected startseq
+    vr.setStartEndSeq(-1, 5);
+    assertTrue(l.verify(1, Arrays.asList("startseq"), Arrays.asList(0)));
+    l.reset();
+
+    // check new value fired by event is corrected endseq
+    vr.setStartEndSeq(0, -1);
+    assertTrue(l.verify(1, Arrays.asList("endseq"), Arrays.asList(0)));
+    l.reset();
+
+    // reset for later tests
+    vr.setStartEndSeq(2, 15);
+    l.reset();
+
+    // test viewport height and width setting triggers event
+    vr.setViewportHeight(10);
+    assertTrue(l.verify(1, Arrays.asList("endseq")));
+    l.reset();
+
+    vr.setViewportWidth(18);
+    assertTrue(l.verify(1, Arrays.asList("endres")));
+    l.reset();
+
+    // already has seq start set to 2, so triggers endseq
+    vr.setViewportStartAndHeight(2, 16);
+    assertTrue(l.verify(1, Arrays.asList("endseq")));
+    l.reset();
+
+    vr.setViewportStartAndWidth(1, 14);
+    assertTrue(l.verify(1, Arrays.asList("startres")));
+    l.reset();
+
+    // test page up/down triggers event
+    vr.pageUp();
+    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    l.reset();
+
+    vr.pageDown();
+    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    l.reset();
+
+    // test scrolling triggers event
+    vr.scrollUp(true);
+    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    l.reset();
+
+    vr.scrollUp(false);
+    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    l.reset();
+
+    vr.scrollRight(true);
+    assertTrue(l.verify(1, Arrays.asList("startres")));
+    l.reset();
+
+    vr.scrollRight(false);
+    assertTrue(l.verify(1, Arrays.asList("startres")));
+    l.reset();
+
+    // TODO test scrollToVisibble once hidden columns JAL-2388 merged in
+    // to avoid somersaults with align viewport
+    /*vr.scrollToVisible(10, 10);
+    assertTrue(l.verify(1, Arrays.asList("startres")));
+    l.reset();*/
+
+    vr.scrollToWrappedVisible(5);
+    assertTrue(l.verify(1, Arrays.asList("startres")));
+    l.reset();
+  }
+}
+
+// mock listener for property change events
+class MockPropChangeListener implements ViewportListenerI
+{
+  private int firecount = 0;
+
+  private List<String> events = new ArrayList<String>();
+
+  private List<Integer> newvalues = new ArrayList<Integer>();
+
+  public MockPropChangeListener(ViewportRanges vr)
+  {
+    vr.addPropertyChangeListener(this);
+  }
+
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    firecount++;
+    events.add(evt.getPropertyName());
+    newvalues.add((Integer) evt.getNewValue());
+  }
+
+  public boolean verify(int count, List<String> eventslist,
+          List<Integer> valueslist)
+  {
+    return (count == firecount) && events.equals(eventslist)
+            && newvalues.equals(valueslist);
+  }
+
+  public boolean verify(int count, List<String> eventslist)
+  {
+    return (count == firecount) && events.equals(eventslist);
+  }
+
+  public void reset()
+  {
+    firecount = 0;
+    events.clear();
+    newvalues.clear();
   }
 }