Merge remote-tracking branch 'origin/develop' into
authorkiramt <k.mourao@dundee.ac.uk>
Wed, 22 Mar 2017 12:36:24 +0000 (12:36 +0000)
committerkiramt <k.mourao@dundee.ac.uk>
Wed, 22 Mar 2017 12:36:24 +0000 (12:36 +0000)
bug/JAL-2436featureRendererThreading

Conflicts:
src/jalview/appletgui/OverviewPanel.java
src/jalview/gui/OverviewPanel.java

43 files changed:
src/jalview/analysis/AAFrequency.java
src/jalview/api/AlignViewportI.java
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AlignViewport.java
src/jalview/appletgui/AlignmentPanel.java
src/jalview/appletgui/AnnotationLabels.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/datamodel/Alignment.java
src/jalview/datamodel/AlignmentI.java
src/jalview/datamodel/ColumnSelection.java
src/jalview/datamodel/HiddenSequences.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/renderer/AnnotationRenderer.java
src/jalview/viewmodel/AlignmentViewport.java
src/jalview/viewmodel/OverviewDimensions.java [new file with mode: 0644]
src/jalview/viewmodel/ViewportProperties.java [new file with mode: 0644]
src/jalview/viewmodel/ViewportRanges.java [new file with mode: 0644]
src/jalview/ws/DasSequenceFeatureFetcher.java
test/jalview/datamodel/AlignmentTest.java
test/jalview/datamodel/ColumnSelectionTest.java
test/jalview/datamodel/HiddenSequencesTest.java
test/jalview/gui/AlignmentPanelTest.java [new file with mode: 0644]
test/jalview/viewmodel/OverviewDimensionsTest.java [new file with mode: 0644]
test/jalview/viewmodel/ViewportRangesTest.java [new file with mode: 0644]
test/jalview/ws/seqfetcher/DasSequenceFetcher.java
test/jalview/ws/sifts/SiftsClientTest.java

index ffa413b..ee16f94 100755 (executable)
@@ -291,7 +291,7 @@ public class AAFrequency
   /**
    * Derive the gap count annotation row.
    * 
-   * @param consensus
+   * @param gaprow
    *          the annotation row to add annotations to
    * @param profiles
    *          the source consensus data
@@ -300,11 +300,11 @@ public class AAFrequency
    * @param endCol
    *          end column (exclusive)
    */
-  public static void completeGapAnnot(AlignmentAnnotation consensus,
+  public static void completeGapAnnot(AlignmentAnnotation gaprow,
           ProfilesI profiles, int startCol, int endCol, long nseq)
   {
-    if (consensus == null || consensus.annotations == null
-            || consensus.annotations.length < endCol)
+    if (gaprow == null || gaprow.annotations == null
+            || gaprow.annotations.length < endCol)
     {
       /*
        * called with a bad alignment annotation row 
@@ -313,8 +313,8 @@ public class AAFrequency
       return;
     }
     // always set ranges again
-    consensus.graphMax = nseq;
-    consensus.graphMin = 0;
+    gaprow.graphMax = nseq;
+    gaprow.graphMin = 0;
     for (int i = startCol; i < endCol; i++)
     {
       ProfileI profile = profiles.get(i);
@@ -324,7 +324,7 @@ public class AAFrequency
          * happens if sequences calculated over were 
          * shorter than alignment width
          */
-        consensus.annotations[i] = null;
+        gaprow.annotations[i] = null;
         return;
       }
 
@@ -332,7 +332,7 @@ public class AAFrequency
 
       String description = String.valueOf(gapped);
 
-      consensus.annotations[i] = new Annotation(description, description,
+      gaprow.annotations[i] = new Annotation(description, description,
               '\0',
               gapped);
     }
index 634521c..8b07340 100644 (file)
@@ -33,6 +33,7 @@ import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.ResidueShaderI;
 import jalview.schemes.ColourSchemeI;
+import jalview.viewmodel.ViewportRanges;
 
 import java.awt.Color;
 import java.util.Hashtable;
@@ -46,7 +47,13 @@ import java.util.Map;
 public interface AlignViewportI extends ViewStyleI
 {
 
-  int getEndRes();
+  /**
+   * Get the ranges object containing details of the start and end sequences and
+   * residues
+   * 
+   * @return
+   */
+  public ViewportRanges getRanges();
 
   /**
    * calculate the height for visible annotation, revalidating bounds where
index 6a0b390..e51131b 100644 (file)
@@ -75,6 +75,7 @@ import jalview.structures.models.AAStructureBindingModel;
 import jalview.util.MappingUtils;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BorderLayout;
 import java.awt.Canvas;
@@ -420,6 +421,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
   @Override
   public void keyPressed(KeyEvent evt)
   {
+    ViewportRanges ranges = viewport.getRanges();
+
     if (viewport.cursorMode
             && ((evt.getKeyCode() >= KeyEvent.VK_0 && evt.getKeyCode() <= KeyEvent.VK_9) || (evt
                     .getKeyCode() >= KeyEvent.VK_NUMPAD0 && evt
@@ -571,8 +574,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
               new String[] { (viewport.cursorMode ? "on" : "off") }));
       if (viewport.cursorMode)
       {
-        alignPanel.seqPanel.seqCanvas.cursorX = viewport.startRes;
-        alignPanel.seqPanel.seqCanvas.cursorY = viewport.startSeq;
+        alignPanel.seqPanel.seqCanvas.cursorX = ranges.getStartRes();
+        alignPanel.seqPanel.seqCanvas.cursorY = ranges.getStartSeq();
       }
       break;
 
@@ -598,8 +601,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
       }
       else
       {
-        alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
-                - viewport.endSeq + viewport.startSeq);
+        alignPanel.setScrollValues(ranges.getStartRes(),
+                2 * ranges.getStartSeq() - ranges.getEndSeq());
       }
       break;
 
@@ -610,8 +613,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
       }
       else
       {
-        alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
-                + viewport.endSeq - viewport.startSeq);
+        alignPanel
+                .setScrollValues(ranges.getStartRes(), ranges.getEndSeq());
       }
       break;
 
@@ -2063,7 +2066,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
             seqs, 0, viewport.getAlignment().getWidth(),
             viewport.getAlignment()));
 
-    viewport.setEndSeq(viewport.getAlignment().getHeight());
+    viewport.getRanges().setEndSeq(viewport.getAlignment().getHeight());
     viewport.getAlignment().getWidth();
     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
             .getSequences());
@@ -2299,6 +2302,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
 
   void trimAlignment(boolean trimLeft)
   {
+    AlignmentI al = viewport.getAlignment();
+    ViewportRanges ranges = viewport.getRanges();
     ColumnSelection colSel = viewport.getColumnSelection();
     int column;
 
@@ -2321,20 +2326,20 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
       }
       else
       {
-        seqs = viewport.getAlignment().getSequencesArray();
+        seqs = al.getSequencesArray();
       }
 
       TrimRegionCommand trimRegion;
       if (trimLeft)
       {
         trimRegion = new TrimRegionCommand("Remove Left", true, seqs,
-                column, viewport.getAlignment());
-        viewport.setStartRes(0);
+                column, al);
+        ranges.setStartRes(0);
       }
       else
       {
         trimRegion = new TrimRegionCommand("Remove Right", false, seqs,
-                column, viewport.getAlignment());
+                column, al);
       }
 
       statusBar.setText(MessageManager.formatMessage(
@@ -2343,23 +2348,25 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
                       .toString() }));
       addHistoryItem(trimRegion);
 
-      for (SequenceGroup sg : viewport.getAlignment().getGroups())
+      for (SequenceGroup sg : al.getGroups())
       {
         if ((trimLeft && !sg.adjustForRemoveLeft(column))
                 || (!trimLeft && !sg.adjustForRemoveRight(column)))
         {
-          viewport.getAlignment().deleteGroup(sg);
+          al.deleteGroup(sg);
         }
       }
 
-      viewport.firePropertyChange("alignment", null, viewport
-              .getAlignment().getSequences());
+      viewport.firePropertyChange("alignment", null, al.getSequences());
     }
   }
 
   public void removeGappedColumnMenuItem_actionPerformed()
   {
-    int start = 0, end = viewport.getAlignment().getWidth() - 1;
+    AlignmentI al = viewport.getAlignment();
+    ViewportRanges ranges = viewport.getRanges();
+    int start = 0;
+    int end = ranges.getAbsoluteAlignmentWidth() - 1;
 
     SequenceI[] seqs;
     if (viewport.getSelectionGroup() != null)
@@ -2387,22 +2394,24 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
 
     // This is to maintain viewport position on first residue
     // of first sequence
-    SequenceI seq = viewport.getAlignment().getSequenceAt(0);
-    int startRes = seq.findPosition(viewport.startRes);
+    SequenceI seq = al.getSequenceAt(0);
+    int startRes = seq.findPosition(ranges.getStartRes());
     // ShiftList shifts;
     // viewport.getAlignment().removeGaps(shifts=new ShiftList());
     // edit.alColumnChanges=shifts.getInverse();
     // if (viewport.hasHiddenColumns)
     // viewport.getColumnSelection().compensateForEdits(shifts);
-    viewport.setStartRes(seq.findIndex(startRes) - 1);
-    viewport.firePropertyChange("alignment", null, viewport.getAlignment()
-            .getSequences());
+    ranges.setStartRes(seq.findIndex(startRes) - 1);
+    viewport.firePropertyChange("alignment", null, al.getSequences());
 
   }
 
   public void removeAllGapsMenuItem_actionPerformed()
   {
-    int start = 0, end = viewport.getAlignment().getWidth() - 1;
+    AlignmentI al = viewport.getAlignment();
+    ViewportRanges ranges = viewport.getRanges();
+    int start = 0;
+    int end = ranges.getAbsoluteAlignmentWidth() - 1;
 
     SequenceI[] seqs;
     if (viewport.getSelectionGroup() != null)
@@ -2419,16 +2428,15 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
 
     // This is to maintain viewport position on first residue
     // of first sequence
-    SequenceI seq = viewport.getAlignment().getSequenceAt(0);
-    int startRes = seq.findPosition(viewport.startRes);
+    SequenceI seq = al.getSequenceAt(0);
+    int startRes = seq.findPosition(ranges.getStartRes());
 
     addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
-            viewport.getAlignment()));
+            al));
 
-    viewport.setStartRes(seq.findIndex(startRes) - 1);
+    ranges.setStartRes(seq.findIndex(startRes) - 1);
 
-    viewport.firePropertyChange("alignment", null, viewport.getAlignment()
-            .getSequences());
+    viewport.firePropertyChange("alignment", null, al.getSequences());
 
   }
 
index fc087c6..065c503 100644 (file)
@@ -35,16 +35,16 @@ import jalview.datamodel.SequenceI;
 import jalview.renderer.ResidueShader;
 import jalview.schemes.ColourSchemeProperty;
 import jalview.schemes.UserColourScheme;
-import jalview.structure.CommandListener;
 import jalview.structure.SelectionSource;
 import jalview.structure.StructureSelectionManager;
 import jalview.structure.VamsasSource;
 import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
 
 import java.awt.Font;
 
 public class AlignViewport extends AlignmentViewport implements
-        SelectionSource, VamsasSource, CommandListener
+        SelectionSource
 {
   boolean cursorMode = false;
 
@@ -75,12 +75,10 @@ public class AlignViewport extends AlignmentViewport implements
     calculator = new jalview.workers.AlignCalcManager();
     this.applet = applet;
     alignment = al;
+    ranges = new ViewportRanges(this.alignment);
     // we always pad gaps
     this.setPadGaps(true);
-    this.startRes = 0;
-    this.endRes = al.getWidth() - 1;
-    this.startSeq = 0;
-    this.endSeq = al.getHeight() - 1;
+
     if (applet != null)
     {
       // get the width and height scaling factors if they were specified
@@ -299,7 +297,7 @@ public class AlignViewport extends AlignmentViewport implements
 
   public void resetSeqLimits(int height)
   {
-    setEndSeq(height / getCharHeight());
+    ranges.setEndSeq(height / getCharHeight());
   }
 
   public void setCurrentTree(NJTree tree)
index e97c347..3ae0394 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.ViewportRanges;
 
 import java.awt.BorderLayout;
 import java.awt.Color;
@@ -65,6 +66,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
   AnnotationLabels alabels;
 
+  ViewportRanges vpRanges;
+
   // this value is set false when selection area being dragged
   boolean fastPaint = true;
 
@@ -73,6 +76,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
   {
     alignFrame = null;
     av = null;
+    vpRanges = null;
     seqPanel = null;
     seqPanelHolder = null;
     sequenceHolderPanel = null;
@@ -96,6 +100,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
     alignFrame = af;
     this.av = av;
+    vpRanges = av.getRanges();
     seqPanel = new SeqPanel(av, this);
     idPanel = new IdPanel(av, this);
     scalePanel = new ScalePanel(av, this);
@@ -126,7 +131,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       @Override
       public void componentResized(ComponentEvent evt)
       {
-        setScrollValues(av.getStartRes(), av.getStartSeq());
+        setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
         if (getSize().height > 0
                 && annotationPanelHolder.getSize().height > 0)
         {
@@ -383,7 +388,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
        */
       if (centre)
       {
-        int offset = (av.getEndRes() - av.getStartRes() + 1) / 2 - 1;
+        int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2 - 1;
         start = Math.max(start - offset, 0);
         end = Math.min(end + offset, seq.getEnd() - 1);
       }
@@ -468,33 +473,34 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       // setScrollValues(start, seqIndex);
       // }
       // logic copied from jalview.gui.AlignmentPanel:
-      if ((startv = av.getStartRes()) >= start)
+      if ((startv = vpRanges.getStartRes()) >= start)
       {
         /*
          * Scroll left to make start of search results visible
          */
         setScrollValues(start - 1, seqIndex);
       }
-      else if ((endv = av.getEndRes()) <= end)
+      else if ((endv = vpRanges.getEndRes()) <= end)
       {
         /*
          * Scroll right to make end of search results visible
          */
         setScrollValues(startv + 1 + end - endv, seqIndex);
       }
-      else if ((starts = av.getStartSeq()) > seqIndex)
+      else if ((starts = vpRanges.getStartSeq()) > seqIndex)
       {
         /*
          * Scroll up to make start of search results visible
          */
-        setScrollValues(av.getStartRes(), seqIndex);
+        setScrollValues(vpRanges.getStartRes(), seqIndex);
       }
-      else if ((ends = av.getEndSeq()) <= seqIndex)
+      else if ((ends = vpRanges.getEndSeq()) <= seqIndex)
       {
         /*
          * Scroll down to make end of search results visible
          */
-        setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1);
+        setScrollValues(vpRanges.getStartRes(), starts + seqIndex - ends
+                + 1);
       }
       /*
        * Else results are already visible - no need to scroll
@@ -516,10 +522,11 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
   {
     int cwidth = seqPanel.seqCanvas
             .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
-    if (res <= av.getStartRes() || res >= (av.getStartRes() + cwidth))
+    if (res <= vpRanges.getStartRes()
+            || res >= (vpRanges.getStartRes() + cwidth))
     {
       vscroll.setValue(res / cwidth);
-      av.startRes = vscroll.getValue() * cwidth;
+      vpRanges.setStartRes(vscroll.getValue() * cwidth);
     }
   }
 
@@ -632,8 +639,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
   public void setWrapAlignment(boolean wrap)
   {
-    av.startSeq = 0;
-    av.startRes = 0;
+    vpRanges.setStartSeq(0);
+    vpRanges.setStartRes(0);
     scalePanelHolder.setVisible(!wrap);
 
     hscroll.setVisible(!wrap);
@@ -724,7 +731,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     {
       x = 0;
     }
-    ;
+
 
     hextent = seqPanel.seqCanvas.getSize().width / av.getCharWidth();
     vextent = seqPanel.seqCanvas.getSize().height / av.getCharHeight();
@@ -762,17 +769,10 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       x = 0;
     }
 
-    av.setStartSeq(y);
-
-    int endSeq = y + vextent;
-    if (endSeq > av.getAlignment().getHeight())
-    {
-      endSeq = av.getAlignment().getHeight();
-    }
-
-    av.setEndSeq(endSeq);
-    av.setStartRes(x);
-    av.setEndRes((x + (seqPanel.seqCanvas.getSize().width / av
+    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);
@@ -789,8 +789,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
   @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
-    int oldX = av.getStartRes();
-    int oldY = av.getStartSeq();
+    int oldX = vpRanges.getStartRes();
+    int oldY = vpRanges.getStartSeq();
 
     if (evt == null || evt.getSource() == apvscroll)
     {
@@ -804,8 +804,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     if (evt == null || evt.getSource() == hscroll)
     {
       int x = hscroll.getValue();
-      av.setStartRes(x);
-      av.setEndRes(x + seqPanel.seqCanvas.getSize().width
+      vpRanges.setStartRes(x);
+      vpRanges.setEndRes(x + seqPanel.seqCanvas.getSize().width
               / av.getCharWidth() - 1);
     }
 
@@ -816,14 +816,14 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       {
         int rowSize = seqPanel.seqCanvas
                 .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
-        av.setStartRes(vscroll.getValue() * rowSize);
-        av.setEndRes((vscroll.getValue() + 1) * rowSize);
+        vpRanges.setStartRes(vscroll.getValue() * rowSize);
+        vpRanges.setEndRes((vscroll.getValue() + 1) * rowSize);
       }
       else
       {
-        av.setStartSeq(offy);
-        av.setEndSeq(offy + seqPanel.seqCanvas.getSize().height
-                / av.getCharHeight());
+        vpRanges.setStartSeq(offy);
+        vpRanges.setEndSeq(offy + seqPanel.seqCanvas.getSize().height
+                / av.getCharHeight() - 1);
       }
     }
 
@@ -832,8 +832,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       overviewPanel.setBoxPosition();
     }
 
-    int scrollX = av.startRes - oldX;
-    int scrollY = av.startSeq - oldY;
+    int scrollX = vpRanges.getStartRes() - oldX;
+    int scrollY = vpRanges.getStartSeq() - oldY;
 
     if (av.getWrapAlignment() || !fastPaint || av.MAC)
     {
@@ -843,13 +843,13 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     {
       // Make sure we're not trying to draw a panel
       // larger than the visible window
-      if (scrollX > av.endRes - av.startRes)
+      if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
       {
-        scrollX = av.endRes - av.startRes;
+        scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
       }
-      else if (scrollX < av.startRes - av.endRes)
+      else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
       {
-        scrollX = av.startRes - av.endRes;
+        scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
       }
 
       idPanel.idCanvas.fastPaint(scrollY);
@@ -858,7 +858,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       scalePanel.repaint();
       if (av.isShowAnnotation())
       {
-        annotationPanel.fastPaint(av.getStartRes() - oldX);
+        annotationPanel.fastPaint(vpRanges.getStartRes() - oldX);
       }
     }
     sendViewPosition();
@@ -955,8 +955,9 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
   private void sendViewPosition()
   {
     StructureSelectionManager.getStructureSelectionManager(av.applet)
-            .sendViewPosition(this, av.startRes, av.endRes, av.startSeq,
-                    av.endSeq);
+            .sendViewPosition(this, vpRanges.getStartRes(),
+                    vpRanges.getEndRes(), vpRanges.getStartSeq(),
+                    vpRanges.getEndSeq());
   }
 
   /**
@@ -1024,7 +1025,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     }
     else
     {
-      setScrollValues(av.getStartRes(), av.getStartSeq());
+      setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
     }
 
     seqPanel.seqCanvas.repaint();
index b28ccc7..ad74b25 100755 (executable)
@@ -339,7 +339,8 @@ public class AnnotationLabels extends Panel implements ActionListener,
                 av.calcPanelHeight());
         f.height += dif;
         ap.seqPanelHolder.setPreferredSize(f);
-        ap.setScrollValues(av.getStartRes(), av.getStartSeq());
+        ap.setScrollValues(av.getRanges().getStartRes(), av.getRanges()
+                .getStartSeq());
         ap.validate();
         // ap.paintAlignment(true);
         ap.addNotify();
index 6012c1a..0ec7adf 100755 (executable)
@@ -462,7 +462,8 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
       }
     }
 
-    int column = evt.getX() / av.getCharWidth() + av.getStartRes();
+    int column = evt.getX() / av.getCharWidth()
+            + av.getRanges().getStartRes();
 
     if (av.hasHiddenColumns())
     {
@@ -618,7 +619,8 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
 
     gg.setColor(Color.white);
     gg.fillRect(0, 0, getSize().width, getSize().height);
-    drawComponent(gg, av.startRes, av.endRes + 1);
+    drawComponent(gg, av.getRanges().getStartRes(), av.getRanges()
+            .getEndRes() + 1);
 
     g.drawImage(image, 0, 0, this);
   }
@@ -635,7 +637,7 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
 
     gg.copyArea(0, 0, imgWidth, getSize().height,
             -horizontal * av.getCharWidth(), 0);
-    int sr = av.startRes, er = av.endRes + 1, transX = 0;
+    int sr = av.getRanges().getStartRes(), er = av.getRanges().getEndRes() + 1, transX = 0;
 
     if (horizontal > 0) // scrollbar pulled right, image to the left
     {
index d72e91f..abcbd70 100755 (executable)
@@ -21,6 +21,7 @@
 package jalview.appletgui;
 
 import jalview.datamodel.SequenceI;
+import jalview.viewmodel.ViewportRanges;
 
 import java.awt.Color;
 import java.awt.Font;
@@ -103,28 +104,32 @@ public class IdCanvas extends Panel
       return;
     }
 
+    ViewportRanges ranges = av.getRanges();
+
     gg.copyArea(0, 0, getSize().width, imgHeight, 0,
             -vertical * av.getCharHeight());
 
-    int ss = av.startSeq, es = av.endSeq, transY = 0;
+    int ss = ranges.getStartSeq(), es = ranges.getEndSeq(), transY = 0;
     if (vertical > 0) // scroll down
     {
       ss = es - vertical;
-      if (ss < av.startSeq) // ie scrolling too fast, more than a page at a time
+      if (ss < ranges.getStartSeq()) // ie scrolling too fast, more than a page
+                                     // at a
+                                 // time
       {
-        ss = av.startSeq;
+        ss = ranges.getStartSeq();
       }
       else
       {
-        transY = imgHeight - vertical * av.getCharHeight();
+        transY = imgHeight - ((vertical + 1) * av.getCharHeight());
       }
     }
     else if (vertical < 0)
     {
       es = ss - vertical;
-      if (es > av.endSeq)
+      if (es > ranges.getEndSeq())
       {
-        es = av.endSeq;
+        es = ranges.getEndSeq();
       }
     }
 
@@ -180,7 +185,7 @@ public class IdCanvas extends Panel
     gg.setFont(italic);
 
     gg.fillRect(0, 0, getSize().width, getSize().height);
-    drawIds(av.startSeq, av.endSeq);
+    drawIds(av.getRanges().getStartSeq(), av.getRanges().getEndSeq());
     g.drawImage(image, 0, 0, this);
   }
 
@@ -233,9 +238,10 @@ public class IdCanvas extends Panel
 
       int cHeight = alheight * avcharHeight + hgap + annotationHeight;
 
-      int rowSize = av.getEndRes() - av.getStartRes();
+      int rowSize = av.getRanges().getEndRes()
+              - av.getRanges().getStartRes();
       // Draw the rest of the panels
-      for (int ypos = hgap, row = av.startRes; (ypos <= getSize().height)
+      for (int ypos = hgap, row = av.getRanges().getStartRes(); (ypos <= getSize().height)
               && (row < maxwidth); ypos += cHeight, row += rowSize)
       {
         for (int i = starty; i < alheight; i++)
@@ -263,7 +269,7 @@ public class IdCanvas extends Panel
     {
       // Now draw the id strings
       SequenceI seq;
-      for (int i = starty; i < endy; i++)
+      for (int i = starty; i <= endy; i++)
       {
 
         seq = av.getAlignment().getSequenceAt(i);
index b03a638..e47c50a 100755 (executable)
@@ -253,13 +253,13 @@ public class IdPanel extends Panel implements MouseListener,
       return;
     }
 
-    if (mouseDragging && e.getY() < 0 && av.getStartSeq() > 0)
+    if (mouseDragging && e.getY() < 0 && av.getRanges().getStartSeq() > 0)
     {
       scrollThread = new ScrollThread(true);
     }
 
     if (mouseDragging && e.getY() >= getSize().height
-            && av.getAlignment().getHeight() > av.getEndSeq())
+            && av.getAlignment().getHeight() > av.getRanges().getEndSeq())
     {
       scrollThread = new ScrollThread(false);
     }
@@ -398,9 +398,10 @@ public class IdPanel extends Panel implements MouseListener,
     int index = av.getAlignment().findIndex(list.get(0));
 
     // do we need to scroll the panel?
-    if (av.getStartSeq() > index || av.getEndSeq() < index)
+    if (av.getRanges().getStartSeq() > index
+            || av.getRanges().getEndSeq() < index)
     {
-      alignPanel.setScrollValues(av.getStartRes(), index);
+      alignPanel.setScrollValues(av.getRanges().getStartRes(), index);
     }
   }
 
@@ -431,10 +432,10 @@ public class IdPanel extends Panel implements MouseListener,
         if (alignPanel.scrollUp(up))
         {
           // scroll was ok, so add new sequence to selection
-          int seq = av.getStartSeq();
+          int seq = av.getRanges().getStartSeq();
           if (!up)
           {
-            seq = av.getEndSeq();
+            seq = av.getRanges().getEndSeq();
           }
 
           if (seq < lastid)
index 251e1c8..2fc5716 100755 (executable)
@@ -20,8 +20,9 @@
  */
 package jalview.appletgui;
 
-import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
 import jalview.renderer.seqfeatures.FeatureColourFinder;
+import jalview.viewmodel.OverviewDimensions;
 
 import java.awt.Color;
 import java.awt.Dimension;
@@ -38,38 +39,34 @@ import java.awt.event.MouseMotionListener;
 public class OverviewPanel extends Panel implements Runnable,
         MouseMotionListener, MouseListener
 {
-  Image miniMe;
+  private OverviewDimensions od;
 
-  Image offscreen;
+  private Image miniMe;
 
-  AlignViewport av;
+  private Image offscreen;
 
-  AlignmentPanel ap;
+  private AlignViewport av;
 
-  float scalew = 1f;
+  private AlignmentPanel ap;
 
-  float scaleh = 1f;
+  private boolean resizing = false;
 
-  public int width, sequencesHeight;
-
-  int graphHeight = 20;
-
-  int boxX = -1, boxY = -1, boxWidth = -1, boxHeight = -1;
-
-  boolean resizing = false;
+  // This is set true if the user resizes whilst
+  // the overview is being calculated
+  private boolean resizeAgain = false;
 
   // Can set different properties in this seqCanvas than
   // main visible SeqCanvas
-  SequenceRenderer sr;
+  private SequenceRenderer sr;
 
-  FeatureRenderer fr;
+  private FeatureRenderer fr;
 
-  Frame nullFrame;
+  private Frame nullFrame;
 
-  public OverviewPanel(AlignmentPanel ap)
+  public OverviewPanel(AlignmentPanel alPanel)
   {
-    this.av = ap.av;
-    this.ap = ap;
+    this.av = alPanel.av;
+    this.ap = alPanel;
     setLayout(null);
     nullFrame = new Frame();
     nullFrame.addNotify();
@@ -80,45 +77,17 @@ public class OverviewPanel extends Panel implements Runnable,
     sr.forOverview = true;
     fr = new FeatureRenderer(av);
 
-    // scale the initial size of overviewpanel to shape of alignment
-    float initialScale = (float) av.getAlignment().getWidth()
-            / (float) av.getAlignment().getHeight();
-
-    if (av.getSequenceConsensusHash() == null)
-    {
-      graphHeight = 0;
-    }
+    od = new OverviewDimensions(av.getRanges(), av.isShowAnnotation());
 
-    if (av.getAlignment().getWidth() > av.getAlignment().getHeight())
-    {
-      // wider
-      width = 400;
-      sequencesHeight = (int) (400f / initialScale);
-      if (sequencesHeight < 40)
-      {
-        sequencesHeight = 40;
-      }
-    }
-    else
-    {
-      // taller
-      width = (int) (400f * initialScale);
-      sequencesHeight = 300;
-      if (width < 120)
-      {
-        width = 120;
-      }
-    }
-
-    setSize(new Dimension(width, sequencesHeight + graphHeight));
+    setSize(new Dimension(od.getWidth(), od.getHeight()));
     addComponentListener(new ComponentAdapter()
     {
 
       @Override
       public void componentResized(ComponentEvent evt)
       {
-        if (getSize().width != width
-                || getSize().height != sequencesHeight + graphHeight)
+        if ((getWidth() != od.getWidth())
+                || (getHeight() != (od.getHeight())))
         {
           updateOverviewImage();
         }
@@ -156,79 +125,32 @@ public class OverviewPanel extends Panel implements Runnable,
   @Override
   public void mousePressed(MouseEvent evt)
   {
-    boxX = evt.getX();
-    boxY = evt.getY();
-    checkValid();
+    mouseAction(evt);
   }
 
   @Override
   public void mouseReleased(MouseEvent evt)
   {
-    boxX = evt.getX();
-    boxY = evt.getY();
-    checkValid();
+    mouseAction(evt);
   }
 
   @Override
   public void mouseDragged(MouseEvent evt)
   {
-    boxX = evt.getX();
-    boxY = evt.getY();
-    checkValid();
+    mouseAction(evt);
   }
 
-  void checkValid()
+  private void mouseAction(MouseEvent evt)
   {
-    if (boxY < 0)
-    {
-      boxY = 0;
-    }
-
-    if (boxY > (sequencesHeight - boxHeight))
-    {
-      boxY = sequencesHeight - boxHeight + 1;
-    }
-
-    if (boxX < 0)
-    {
-      boxX = 0;
-    }
-
-    if (boxX > (width - boxWidth))
-    {
-      if (av.hasHiddenColumns())
-      {
-        // Try smallest possible box
-        boxWidth = (int) ((av.endRes - av.startRes + 1) * av.getCharWidth() * scalew);
-      }
-      boxX = width - boxWidth;
-    }
-
-    int col = (int) (boxX / scalew / av.getCharWidth());
-    int row = (int) (boxY / scaleh / av.getCharHeight());
-
-    if (av.hasHiddenColumns())
-    {
-      if (!av.getColumnSelection().isVisible(col))
-      {
-        return;
-      }
-
-      col = av.getColumnSelection().findColumnPosition(col);
-    }
-
-    if (av.hasHiddenRows())
-    {
-      row = av.getAlignment().getHiddenSequences()
-              .findIndexWithoutHiddenSeqs(row);
-    }
-
-    ap.setScrollValues(col, row);
+    od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment()
+            .getHiddenSequences(), av.getColumnSelection(), av
+            .getRanges());
+    ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
     ap.paintAlignment(false);
   }
 
   /**
-   * DOCUMENT ME!
+   * Updates the overview image when the related alignment panel is updated
    */
   public void updateOverviewImage()
   {
@@ -247,27 +169,20 @@ public class OverviewPanel extends Panel implements Runnable,
 
     if ((getSize().width > 0) && (getSize().height > 0))
     {
-      width = getSize().width;
-      sequencesHeight = getSize().height - graphHeight;
+      od.setWidth(getSize().width);
+      od.setHeight(getSize().height);
     }
-    setSize(new Dimension(width, sequencesHeight + graphHeight));
+    setSize(new Dimension(od.getWidth(), od.getHeight()));
 
     Thread thread = new Thread(this);
     thread.start();
     repaint();
   }
 
-  // This is set true if the user resizes whilst
-  // the overview is being calculated
-  boolean resizeAgain = false;
-
   @Override
   public void run()
   {
     miniMe = null;
-    int alwidth = av.getAlignment().getWidth();
-    int alheight = av.getAlignment().getHeight()
-            + av.getAlignment().getHiddenSequences().getSize();
 
     if (av.isShowSequenceFeatures())
     {
@@ -276,132 +191,35 @@ public class OverviewPanel extends Panel implements Runnable,
 
     if (getSize().width > 0 && getSize().height > 0)
     {
-      width = getSize().width;
-      sequencesHeight = getSize().height - graphHeight;
+      od.setWidth(getSize().width);
+      od.setHeight(getSize().height);
     }
 
-    setSize(new Dimension(width, sequencesHeight + graphHeight));
-
-    int fullsizeWidth = alwidth * av.getCharWidth();
-    int fullsizeHeight = alheight * av.getCharHeight();
-
-    scalew = (float) width / (float) fullsizeWidth;
-    scaleh = (float) sequencesHeight / (float) fullsizeHeight;
+    setSize(new Dimension(od.getWidth(), od.getHeight()));
 
-    miniMe = nullFrame.createImage(width, sequencesHeight + graphHeight);
-    offscreen = nullFrame.createImage(width, sequencesHeight + graphHeight);
+    miniMe = nullFrame.createImage(od.getWidth(), od.getHeight());
+    offscreen = nullFrame.createImage(od.getWidth(), od.getHeight());
 
     Graphics mg = miniMe.getGraphics();
-    float sampleCol = (float) alwidth / (float) width;
-    float sampleRow = (float) alheight / (float) sequencesHeight;
-
-    int lastcol = 0, lastrow = 0;
-    int xstart = 0, ystart = 0;
-    Color color = Color.yellow;
-    int row, col, sameRow = 0, sameCol = 0;
-    jalview.datamodel.SequenceI seq;
-    final boolean hasHiddenRows = av.hasHiddenRows(), hasHiddenCols = av
-            .hasHiddenColumns();
-    boolean hiddenRow = false;
-    AlignmentI alignment = av.getAlignment();
-
-    FeatureColourFinder finder = new FeatureColourFinder(fr);
-    for (row = 0; row <= sequencesHeight; row++)
-    {
-      if (resizeAgain)
-      {
-        break;
-      }
-      if ((int) (row * sampleRow) == lastrow)
-      {
-        sameRow++;
-        continue;
-      }
-
-      hiddenRow = false;
-      if (hasHiddenRows)
-      {
-        seq = alignment.getHiddenSequences().getHiddenSequence(lastrow);
-        if (seq == null)
-        {
-          int index = alignment.getHiddenSequences()
-                  .findIndexWithoutHiddenSeqs(lastrow);
 
-          seq = alignment.getSequenceAt(index);
-        }
-        else
-        {
-          hiddenRow = true;
-        }
-      }
-      else
-      {
-        seq = alignment.getSequenceAt(lastrow);
-      }
-
-      for (col = 0; col < width; col++)
-      {
-        if ((int) (col * sampleCol) == lastcol
-                && (int) (row * sampleRow) == lastrow)
-        {
-          sameCol++;
-          continue;
-        }
-
-        lastcol = (int) (col * sampleCol);
-
-        if (seq.getLength() > lastcol)
-        {
-          color = sr.getResidueColour(seq, lastcol, finder);
-        }
-        else
-        {
-          color = Color.white;
-        }
-
-        if (hiddenRow
-                || (hasHiddenCols && !av.getColumnSelection().isVisible(
-                        lastcol)))
-        {
-          color = color.darker().darker();
-        }
-
-        mg.setColor(color);
-        if (sameCol == 1 && sameRow == 1)
-        {
-          mg.drawLine(xstart, ystart, xstart, ystart);
-        }
-        else
-        {
-          mg.fillRect(xstart, ystart, sameCol, sameRow);
-        }
+    int alwidth = av.getAlignment().getWidth();
+    int alheight = av.getAlignment().getAbsoluteHeight();
+    float sampleCol = alwidth / (float) od.getWidth();
+    float sampleRow = alheight / (float) od.getSequencesHeight();
 
-        xstart = col;
-        sameCol = 1;
-      }
-      lastrow = (int) (row * sampleRow);
-      ystart = row;
-      sameRow = 1;
-    }
+    buildImage(sampleRow, sampleCol, mg);
 
-    if (av.getAlignmentConservationAnnotation() != null)
+    if (av.isShowAnnotation())
     {
-      for (col = 0; col < width; col++)
+      for (int col = 0; col < od.getWidth() && !resizeAgain; col++)
       {
-        if (resizeAgain)
-        {
-          break;
-        }
-        lastcol = (int) (col * sampleCol);
-        {
-          mg.translate(col, sequencesHeight);
-          ap.annotationPanel.renderer.drawGraph(mg,
-                  av.getAlignmentConservationAnnotation(),
-                  av.getAlignmentConservationAnnotation().annotations,
-                  (int) (sampleCol) + 1, graphHeight,
-                  (int) (col * sampleCol), (int) (col * sampleCol) + 1);
-          mg.translate(-col, -sequencesHeight);
-        }
+        mg.translate(col, od.getSequencesHeight());
+        ap.annotationPanel.renderer.drawGraph(mg,
+                av.getAlignmentConservationAnnotation(),
+                av.getAlignmentConservationAnnotation().annotations,
+                (int) (sampleCol) + 1, od.getGraphHeight(),
+                (int) (col * sampleCol), (int) (col * sampleCol) + 1);
+        mg.translate(-col, -od.getSequencesHeight());
       }
     }
     System.gc();
@@ -417,52 +235,104 @@ public class OverviewPanel extends Panel implements Runnable,
     }
   }
 
-  public void setBoxPosition()
+  /*
+   * Build the overview panel image
+   */
+  private void buildImage(float sampleRow, float sampleCol, Graphics mg)
   {
-    int fullsizeWidth = av.getAlignment().getWidth() * av.getCharWidth();
-    int fullsizeHeight = (av.getAlignment().getHeight() + av.getAlignment()
-            .getHiddenSequences().getSize())
-            * av.getCharHeight();
-
-    int startRes = av.getStartRes();
-    int endRes = av.getEndRes();
+    int lastcol = 0;
+    int lastrow = 0;
+    int xstart = 0;
+    int ystart = 0;
+    Color color = Color.yellow;
+    int sameRow = 0;
+    int sameCol = 0;
 
-    if (av.hasHiddenColumns())
-    {
-      startRes = av.getColumnSelection().adjustForHiddenColumns(startRes);
-      endRes = av.getColumnSelection().adjustForHiddenColumns(endRes);
-    }
+    SequenceI seq = null;
+    FeatureColourFinder finder = new FeatureColourFinder(fr);
 
-    int startSeq = av.startSeq;
-    int endSeq = av.endSeq;
+    final boolean hasHiddenCols = av.hasHiddenColumns();
+    boolean hiddenRow = false;
 
-    if (av.hasHiddenRows())
+    for (int row = 0; row <= od.getSequencesHeight() && !resizeAgain; row++)
     {
-      startSeq = av.getAlignment().getHiddenSequences()
-              .adjustForHiddenSeqs(startSeq);
-
-      endSeq = av.getAlignment().getHiddenSequences()
-              .adjustForHiddenSeqs(endSeq);
+      if ((int) (row * sampleRow) == lastrow)
+      {
+        sameRow++;
+      }
+      else
+      {
+        // get the sequence which would be at alignment index 'lastrow' if no
+        // columns were hidden, and determine whether it is hidden or not
+        hiddenRow = av.getAlignment().isHidden(lastrow);
+        seq = av.getAlignment().getSequenceAtAbsoluteIndex(lastrow);
 
+        for (int col = 0; col < od.getWidth(); col++)
+        {
+          if ((int) (col * sampleCol) == lastcol
+                  && (int) (row * sampleRow) == lastrow)
+          {
+            sameCol++;
+          }
+          else
+          {
+            lastcol = (int) (col * sampleCol);
+
+            color = getColumnColourFromSequence(seq, hiddenRow,
+                    hasHiddenCols, lastcol, finder);
+
+            mg.setColor(color);
+            if (sameCol == 1 && sameRow == 1)
+            {
+              mg.drawLine(xstart, ystart, xstart, ystart);
+            }
+            else
+            {
+              mg.fillRect(xstart, ystart, sameCol, sameRow);
+            }
+
+            xstart = col;
+            sameCol = 1;
+          }
+        }
+        lastrow = (int) (row * sampleRow);
+        ystart = row;
+        sameRow = 1;
+      }
     }
+  }
 
-    scalew = (float) width / (float) fullsizeWidth;
-    scaleh = (float) sequencesHeight / (float) fullsizeHeight;
-
-    boxX = (int) (startRes * av.getCharWidth() * scalew);
-    boxY = (int) (startSeq * av.getCharHeight() * scaleh);
-
-    if (av.hasHiddenColumns())
+  /*
+   * Find the colour of a sequence at a specified column position
+   */
+  private Color getColumnColourFromSequence(
+          jalview.datamodel.SequenceI seq, boolean hiddenRow,
+          boolean hasHiddenCols, int lastcol, FeatureColourFinder finder)
+  {
+    Color color = Color.white;
+    if (seq.getLength() > lastcol)
     {
-      boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
+      color = sr.getResidueColour(seq, lastcol, finder);
     }
-    else
+
+    if (hiddenRow
+            || (hasHiddenCols && !av.getColumnSelection()
+                    .isVisible(lastcol)))
     {
-      boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
+      color = color.darker().darker();
     }
+    return color;
+  }
 
-    boxHeight = (int) ((endSeq - startSeq) * av.getCharHeight() * scaleh);
-
+  /**
+   * Update the overview panel box when the associated alignment panel is
+   * changed
+   * 
+   */
+  public void setBoxPosition()
+  {
+    od.setBoxPosition(av.getAlignment()
+            .getHiddenSequences(), av.getColumnSelection(), av.getRanges());
     repaint();
   }
 
@@ -480,8 +350,7 @@ public class OverviewPanel extends Panel implements Runnable,
     {
       og.drawImage(miniMe, 0, 0, this);
       og.setColor(Color.red);
-      og.drawRect(boxX, boxY, boxWidth, boxHeight);
-      og.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);
+      od.drawBox(og);
       g.drawImage(offscreen, 0, 0, this);
     }
   }
index ed07b63..15d82a5 100755 (executable)
@@ -76,7 +76,7 @@ public class ScalePanel extends Panel implements MouseMotionListener,
   @Override
   public void mousePressed(MouseEvent evt)
   {
-    int x = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+    int x = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes();
     final int res;
 
     if (av.hasHiddenColumns())
@@ -229,7 +229,8 @@ public class ScalePanel extends Panel implements MouseMotionListener,
   {
     mouseDragging = false;
 
-    int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+    int res = (evt.getX() / av.getCharWidth())
+            + av.getRanges().getStartRes();
 
     if (res > av.getAlignment().getWidth())
     {
@@ -276,7 +277,8 @@ public class ScalePanel extends Panel implements MouseMotionListener,
     mouseDragging = true;
     ColumnSelection cs = av.getColumnSelection();
 
-    int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+    int res = (evt.getX() / av.getCharWidth())
+            + av.getRanges().getStartRes();
     res = Math.max(0, res);
     res = cs.adjustForHiddenColumns(res);
     res = Math.min(res, av.getAlignment().getWidth() - 1);
@@ -324,7 +326,8 @@ public class ScalePanel extends Panel implements MouseMotionListener,
       return;
     }
 
-    int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+    int res = (evt.getX() / av.getCharWidth())
+            + av.getRanges().getStartRes();
 
     res = av.getColumnSelection().adjustForHiddenColumns(res);
 
@@ -350,7 +353,8 @@ public class ScalePanel extends Panel implements MouseMotionListener,
   @Override
   public void paint(Graphics g)
   {
-    drawScale(g, av.getStartRes(), av.getEndRes(), getSize().width,
+    drawScale(g, av.getRanges().getStartRes(), av.getRanges().getEndRes(),
+            getSize().width,
             getSize().height);
   }
 
index 5ab3459..ed8a46d 100755 (executable)
@@ -27,6 +27,7 @@ import jalview.datamodel.SequenceI;
 import jalview.renderer.ScaleRenderer;
 import jalview.renderer.ScaleRenderer.ScaleMark;
 import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
 
 import java.awt.Color;
 import java.awt.FontMetrics;
@@ -211,17 +212,19 @@ public class SeqCanvas extends Panel
       return;
     }
 
+    ViewportRanges ranges = av.getRanges();
+
     updateViewport();
 
     // Its possible on certain browsers that the call to fastpaint
     // is faster than it can paint, so this check here catches
     // this possibility
-    if (lastsr + horizontal != av.startRes)
+    if (lastsr + horizontal != ranges.getStartRes())
     {
-      horizontal = av.startRes - lastsr;
+      horizontal = ranges.getStartRes() - lastsr;
     }
 
-    lastsr = av.startRes;
+    lastsr = ranges.getStartRes();
 
     fastPaint = true;
     gg.copyArea(horizontal * avcharWidth, vertical * avcharHeight, imgWidth
@@ -229,7 +232,9 @@ public class SeqCanvas extends Panel
             imgHeight - vertical * avcharHeight, -horizontal * avcharWidth,
             -vertical * avcharHeight);
 
-    int sr = av.startRes, er = av.endRes, ss = av.startSeq, es = av.endSeq, transX = 0, transY = 0;
+    int sr = ranges.getStartRes(), er = ranges.getEndRes(), ss = ranges
+            .getStartSeq(), es = ranges
+            .getEndSeq(), transX = 0, transY = 0;
 
     if (horizontal > 0) // scrollbar pulled right, image to the left
     {
@@ -244,21 +249,23 @@ public class SeqCanvas extends Panel
     else if (vertical > 0) // scroll down
     {
       ss = es - vertical;
-      if (ss < av.startSeq) // ie scrolling too fast, more than a page at a time
+      if (ss < ranges.getStartSeq()) // ie scrolling too fast, more than a page
+                                     // at a
+                                 // time
       {
-        ss = av.startSeq;
+        ss = ranges.getStartSeq();
       }
       else
       {
-        transY = imgHeight - vertical * avcharHeight;
+        transY = imgHeight - ((vertical + 1) * avcharHeight);
       }
     }
     else if (vertical < 0)
     {
       es = ss - vertical;
-      if (es > av.endSeq)
+      if (es > ranges.getEndSeq())
       {
-        es = av.endSeq;
+        es = ranges.getEndSeq();
       }
     }
 
@@ -329,13 +336,16 @@ public class SeqCanvas extends Panel
     gg.setColor(Color.white);
     gg.fillRect(0, 0, imgWidth, imgHeight);
 
+    ViewportRanges ranges = av.getRanges();
+
     if (av.getWrapAlignment())
     {
-      drawWrappedPanel(gg, imgWidth, imgHeight, av.startRes);
+      drawWrappedPanel(gg, imgWidth, imgHeight, ranges.getStartRes());
     }
     else
     {
-      drawPanel(gg, av.startRes, av.endRes, av.startSeq, av.endSeq, 0);
+      drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(),
+              ranges.getStartSeq(), ranges.getEndSeq(), 0);
     }
 
     g.drawImage(img, 0, 0, this);
@@ -421,7 +431,7 @@ public class SeqCanvas extends Panel
 
     av.setWrappedWidth(cWidth);
 
-    av.endRes = av.startRes + cWidth;
+    av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth);
 
     int endx;
     int ypos = hgap;
@@ -610,7 +620,7 @@ public class SeqCanvas extends Panel
 
     // / First draw the sequences
     // ///////////////////////////
-    for (int i = startSeq; i < endSeq; i++)
+    for (int i = startSeq; i <= endSeq; i++)
     {
       nextSeq = av.getAlignment().getSequenceAt(i);
 
@@ -694,7 +704,7 @@ public class SeqCanvas extends Panel
         int bottom = -1;
         int alHeight = av.getAlignment().getHeight() - 1;
 
-        for (i = startSeq; i < endSeq; i++)
+        for (i = startSeq; i <= endSeq; i++)
         {
           sx = (group.getStartRes() - startRes) * avcharWidth;
           sy = offset + ((i - startSeq) * avcharHeight);
index 1352fe9..0e12703 100644 (file)
@@ -41,6 +41,7 @@ import jalview.structure.VamsasSource;
 import jalview.util.MappingUtils;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BorderLayout;
 import java.awt.Font;
@@ -226,16 +227,17 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     }
     else
     {
-      while (seqCanvas.cursorY < av.startSeq)
+      ViewportRanges ranges = av.getRanges();
+      while (seqCanvas.cursorY < ranges.getStartSeq())
       {
         ap.scrollUp(true);
       }
-      while (seqCanvas.cursorY + 1 > av.endSeq)
+      while (seqCanvas.cursorY + 1 > ranges.getEndSeq())
       {
         ap.scrollUp(false);
       }
       while (seqCanvas.cursorX < av.getColumnSelection()
-              .adjustForHiddenColumns(av.startRes))
+              .adjustForHiddenColumns(ranges.getStartRes()))
       {
 
         if (!ap.scrollRight(false))
@@ -244,7 +246,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         }
       }
       while (seqCanvas.cursorX > av.getColumnSelection()
-              .adjustForHiddenColumns(av.endRes))
+              .adjustForHiddenColumns(ranges.getEndRes()))
       {
         if (!ap.scrollRight(true))
         {
@@ -624,14 +626,14 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       }
 
       wrappedBlock = y / cHeight;
-      wrappedBlock += av.getStartRes() / cwidth;
+      wrappedBlock += av.getRanges().getStartRes() / cwidth;
 
       res = wrappedBlock * cwidth + x / av.getCharWidth();
 
     }
     else
     {
-      res = (x / av.getCharWidth()) + av.getStartRes();
+      res = (x / av.getCharWidth()) + av.getRanges().getStartRes();
     }
 
     if (av.hasHiddenColumns())
@@ -681,7 +683,9 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     }
     else
     {
-      seq = Math.min((y / av.getCharHeight()) + av.getStartSeq(), av
+      seq = Math.min((y / av.getCharHeight())
+              + av.getRanges().getStartSeq(),
+              av
               .getAlignment().getHeight() - 1);
       if (seq < 0)
       {
@@ -1643,8 +1647,10 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       oldSeq = -1;
     }
 
-    if (res > av.endRes || res < av.startRes || y < av.startSeq
-            || y > av.endSeq)
+    if (res > av.getRanges().getEndRes()
+            || res < av.getRanges().getStartRes()
+            || y < av.getRanges().getStartSeq()
+            || y > av.getRanges().getEndSeq())
     {
       mouseExited(evt);
     }
@@ -1742,13 +1748,15 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         if (evt != null)
         {
 
-          if (mouseDragging && evt.getY() < 0 && av.getStartSeq() > 0)
+          if (mouseDragging && evt.getY() < 0
+                  && av.getRanges().getStartSeq() > 0)
           {
             running = ap.scrollUp(true);
           }
 
           if (mouseDragging && evt.getY() >= getSize().height
-                  && av.getAlignment().getHeight() > av.getEndSeq())
+                  && av.getAlignment().getHeight() > av.getRanges()
+                          .getEndSeq())
           {
             running = ap.scrollUp(false);
           }
@@ -1890,8 +1898,8 @@ public class SeqPanel extends Panel implements MouseMotionListener,
   public void scrollTo(int row, int column)
   {
 
-    row = row < 0 ? ap.av.startSeq : row;
-    column = column < 0 ? ap.av.startRes : column;
+    row = row < 0 ? ap.av.getRanges().getStartSeq() : row;
+    column = column < 0 ? ap.av.getRanges().getStartRes() : column;
     ap.scrollTo(column, column, row, true, true);
   }
 
@@ -1903,8 +1911,9 @@ public class SeqPanel extends Panel implements MouseMotionListener,
   public void scrollToRow(int row)
   {
 
-    row = row < 0 ? ap.av.startSeq : row;
-    ap.scrollTo(ap.av.startRes, ap.av.startRes, row, true, true);
+    row = row < 0 ? ap.av.getRanges().getStartSeq() : row;
+    ap.scrollTo(ap.av.getRanges().getStartRes(), ap.av.getRanges()
+            .getStartRes(), row, true, true);
   }
 
   /**
@@ -1915,8 +1924,8 @@ public class SeqPanel extends Panel implements MouseMotionListener,
   public void scrollToColumn(int column)
   {
 
-    column = column < 0 ? ap.av.startRes : column;
-    ap.scrollTo(column, column, ap.av.startSeq, true, true);
+    column = column < 0 ? ap.av.getRanges().getStartRes() : column;
+    ap.scrollTo(column, column, ap.av.getRanges().getStartSeq(), true, true);
   }
 
   /**
index a6f2bf4..41488ea 100755 (executable)
@@ -185,14 +185,7 @@ public class Alignment implements AlignmentI
     return AlignmentUtils.getSequencesByName(this);
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param i
-   *          DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
+
   @Override
   public SequenceI getSequenceAt(int i)
   {
@@ -206,6 +199,28 @@ public class Alignment implements AlignmentI
     return null;
   }
 
+  @Override
+  public SequenceI getSequenceAtAbsoluteIndex(int i)
+  {
+    SequenceI seq = null;
+    if (getHiddenSequences().getSize() > 0)
+    {
+      seq = getHiddenSequences().getHiddenSequence(i);
+      if (seq == null)
+      {
+        // didn't find the sequence in the hidden sequences, get it from the
+        // alignment
+        int index = getHiddenSequences().findIndexWithoutHiddenSeqs(i);
+        seq = getSequenceAt(index);
+      }
+    }
+    else
+    {
+      seq = getSequenceAt(i);
+    }
+    return seq;
+  }
+
   /**
    * Adds a sequence to the alignment. Recalculates maxLength and size. Note
    * this currently does not recalculate whether or not the alignment is
@@ -320,30 +335,21 @@ public class Alignment implements AlignmentI
     }
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param s
-   *          DOCUMENT ME!
-   */
   @Override
   public void deleteSequence(SequenceI s)
   {
-    deleteSequence(findIndex(s));
+    synchronized (sequences)
+    {
+      deleteSequence(findIndex(s));
+    }
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param i
-   *          DOCUMENT ME!
-   */
   @Override
   public void deleteSequence(int i)
   {
-    if (i > -1 && i < getHeight())
+    synchronized (sequences)
     {
-      synchronized (sequences)
+      if (i > -1 && i < getHeight())
       {
         sequences.remove(i);
         hiddenSequences.adjustHeightSequenceDeleted(i);
@@ -351,6 +357,18 @@ public class Alignment implements AlignmentI
     }
   }
 
+  @Override
+  public void deleteHiddenSequence(int i)
+  {
+    synchronized (sequences)
+    {
+      if (i > -1 && i < getHeight())
+      {
+        sequences.remove(i);
+      }
+    }
+  }
+
   /*
    * (non-Javadoc)
    * 
@@ -668,22 +686,19 @@ public class Alignment implements AlignmentI
     return -1;
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
+
   @Override
   public int getHeight()
   {
     return sequences.size();
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
+  @Override
+  public int getAbsoluteHeight()
+  {
+    return sequences.size() + getHiddenSequences().getSize();
+  }
+
   @Override
   public int getWidth()
   {
@@ -769,6 +784,12 @@ public class Alignment implements AlignmentI
     return true;
   }
 
+  @Override
+  public boolean isHidden(int alignmentIndex)
+  {
+    return (getHiddenSequences().getHiddenSequence(alignmentIndex) != null);
+  }
+
   /**
    * Delete all annotations, including auto-calculated if the flag is set true.
    * Returns true if at least one annotation was deleted, else false.
index 5d185cd..2abb1f8 100755 (executable)
@@ -31,13 +31,22 @@ import java.util.Set;
 public interface AlignmentI extends AnnotatedCollectionI
 {
   /**
-   * Calculates the number of sequences in an alignment
+   * Calculates the number of sequences in an alignment, excluding hidden
+   * sequences
    * 
    * @return Number of sequences in alignment
    */
   int getHeight();
 
   /**
+   * Calculates the number of sequences in an alignment, including hidden
+   * sequences
+   * 
+   * @return Number of sequences in alignment
+   */
+  int getAbsoluteHeight();
+
+  /**
    * 
    * Calculates the maximum width of the alignment, including gaps.
    * 
@@ -65,6 +74,15 @@ public interface AlignmentI extends AnnotatedCollectionI
   boolean isAligned(boolean includeHidden);
 
   /**
+   * Answers if the sequence at alignmentIndex is hidden
+   * 
+   * @param alignmentIndex
+   *          the index to check
+   * @return true if the sequence is hidden
+   */
+  boolean isHidden(int alignmentIndex);
+
+  /**
    * Gets sequences as a Synchronized collection
    * 
    * @return All sequences in alignment.
@@ -90,6 +108,17 @@ public interface AlignmentI extends AnnotatedCollectionI
   SequenceI getSequenceAt(int i);
 
   /**
+   * Find a specific sequence in this alignment.
+   * 
+   * @param i
+   *          Index of required sequence in full alignment, i.e. if all columns
+   *          were visible
+   * 
+   * @return SequenceI at given index.
+   */
+  SequenceI getSequenceAtAbsoluteIndex(int i);
+
+  /**
    * Returns a map of lists of sequences keyed by sequence name.
    * 
    * @return
@@ -118,7 +147,9 @@ public interface AlignmentI extends AnnotatedCollectionI
   SequenceI replaceSequenceAt(int i, SequenceI seq);
 
   /**
-   * Deletes a sequence from the alignment
+   * Deletes a sequence from the alignment. Updates hidden sequences to account
+   * for the removed sequence. Do NOT use this method to delete sequences which
+   * are just hidden.
    * 
    * @param s
    *          Sequence to be deleted.
@@ -126,7 +157,9 @@ public interface AlignmentI extends AnnotatedCollectionI
   void deleteSequence(SequenceI s);
 
   /**
-   * Deletes a sequence from the alignment.
+   * Deletes a sequence from the alignment. Updates hidden sequences to account
+   * for the removed sequence. Do NOT use this method to delete sequences which
+   * are just hidden.
    * 
    * @param i
    *          Index of sequence to be deleted.
@@ -134,6 +167,14 @@ public interface AlignmentI extends AnnotatedCollectionI
   void deleteSequence(int i);
 
   /**
+   * Deletes a sequence in the alignment which has been hidden.
+   * 
+   * @param i
+   *          Index of sequence to be deleted
+   */
+  void deleteHiddenSequence(int i);
+
+  /**
    * Finds sequence in alignment using sequence name as query.
    * 
    * @param name
@@ -545,4 +586,5 @@ public interface AlignmentI extends AnnotatedCollectionI
    * @return
    */
   public int[] getVisibleStartAndEndIndex(List<int[]> hiddenCols);
+
 }
index 98a7fe2..97bc5a3 100644 (file)
@@ -690,8 +690,8 @@ public class ColumnSelection
    * left-most visible column will always be returned.
    * 
    * @param hiddenColumn
-   *          int
-   * @return int
+   *          the column index in the full alignment including hidden columns
+   * @return the position of the column in the visible alignment
    */
   public int findColumnPosition(int hiddenColumn)
   {
@@ -708,15 +708,89 @@ public class ColumnSelection
           result -= region[1] + 1 - region[0];
         }
       } while ((hiddenColumn > region[1]) && (index < hiddenColumns.size()));
-      if (hiddenColumn > region[0] && hiddenColumn < region[1])
-      {
-        return region[0] + hiddenColumn - result;
+
+      if (hiddenColumn >= region[0] && hiddenColumn <= region[1])
+       {
+         // Here the hidden column is within a region, so
+         // we want to return the position of region[0]-1, adjusted for any
+         // earlier hidden columns.
+         // Calculate the difference between the actual hidden col position
+         // and region[0]-1, and then subtract from result to convert result from
+         // the adjusted hiddenColumn value to the adjusted region[0]-1 value
+
+        // However, if the region begins at 0 we cannot return region[0]-1
+        // just return 0
+        if (region[0] == 0)
+        {
+          return 0;
+        }
+        else
+        {
+          return result - (hiddenColumn - region[0] + 1);
+        }
       }
     }
     return result; // return the shifted position after removing hidden columns.
   }
 
   /**
+   * Find the visible column which is a given visible number of columns to the
+   * left of another visible column. i.e. for a startColumn x, the column which
+   * is distance 1 away will be column x-1.
+   * 
+   * @param visibleDistance
+   *          the number of visible columns to offset by
+   * @param startColumn
+   *          the column to start from
+   * @return the position of the column in the visible alignment
+   */
+  public int subtractVisibleColumns(int visibleDistance, int startColumn)
+  {
+    int distance = visibleDistance;
+
+    // in case startColumn is in a hidden region, move it to the left
+    int start = adjustForHiddenColumns(findColumnPosition(startColumn));
+
+    // get index of hidden region to left of start
+    int index = getHiddenIndexLeft(start);
+    if (index == -1)
+    {
+      // no hidden regions to left of startColumn
+      return start - distance;
+    }
+
+    // walk backwards through the alignment subtracting the counts of visible
+    // columns from distance
+    int[] region;
+    int gap = 0;
+    int nextstart = start;
+
+    while ((index > -1) && (distance - gap > 0))
+    {
+      // subtract the gap to right of region from distance
+      distance -= gap;
+      start = nextstart;
+
+      // calculate the next gap
+      region = hiddenColumns.get(index);
+      gap = start - region[1];
+
+      // set start to just to left of current region
+      nextstart = region[0] - 1;
+      index--;
+    }
+
+    if (distance - gap > 0)
+    {
+      // fell out of loop because there are no more hidden regions
+      distance -= gap;
+      return nextstart - distance;
+    }
+    return start - distance;
+
+  }
+
+  /**
    * Use this method to determine where the next hiddenRegion starts
    * 
    * @param hiddenRegion
@@ -805,6 +879,35 @@ public class ColumnSelection
 
   }
 
+  /**
+   * This method returns the index of the hidden region to the left of a column
+   * position. If the column is in a hidden region it returns the index of the
+   * region to the left. If there is no hidden region to the left it returns -1.
+   * 
+   * @param pos
+   *          int
+   */
+  private int getHiddenIndexLeft(int pos)
+  {
+    if (hiddenColumns != null)
+    {
+      int index = hiddenColumns.size() - 1;
+      do
+      {
+        int[] region = hiddenColumns.elementAt(index);
+        if (pos > region[1])
+        {
+          return index;
+        }
+
+        index--;
+      } while (index > -1);
+    }
+
+    return -1;
+
+  }
+
   public void hideSelectedColumns()
   {
     synchronized (selection)
index 9e2cf72..6950c28 100755 (executable)
@@ -154,8 +154,8 @@ public class HiddenSequences
       hiddenSequences = new SequenceI[alignment.getHeight()];
     }
 
-    int alignmentIndex = alignment.findIndex(sequence);
-    alignmentIndex = adjustForHiddenSeqs(alignmentIndex);
+    int absAlignmentIndex = alignment.findIndex(sequence);
+    int alignmentIndex = adjustForHiddenSeqs(absAlignmentIndex);
 
     if (hiddenSequences[alignmentIndex] != null)
     {
@@ -164,7 +164,7 @@ public class HiddenSequences
 
     hiddenSequences[alignmentIndex] = sequence;
 
-    alignment.deleteSequence(sequence);
+    alignment.deleteHiddenSequence(absAlignmentIndex);
   }
 
   public List<SequenceI> showAll(
@@ -246,6 +246,12 @@ public class HiddenSequences
     return hiddenSequences == null ? null : hiddenSequences[alignmentIndex];
   }
 
+  /**
+   * Convert absolute alignment index to visible alignment index
+   * 
+   * @param alignmentIndex
+   * @return
+   */
   public int findIndexWithoutHiddenSeqs(int alignmentIndex)
   {
     if (hiddenSequences == null)
@@ -254,8 +260,14 @@ public class HiddenSequences
     }
     int index = 0;
     int hiddenSeqs = 0;
+    int diff = 0;
     if (hiddenSequences.length <= alignmentIndex)
     {
+      // if the alignmentIndex runs past the end of hidden sequences
+      // and therefore actually past the end of the alignment
+      // store the difference to add back on at the end, so that behaviour
+      // is consistent with hidden columns behaviour (used by overview panel)
+      diff = alignmentIndex - hiddenSequences.length + 1;
       alignmentIndex = hiddenSequences.length - 1;
     }
 
@@ -268,9 +280,50 @@ public class HiddenSequences
       index++;
     }
 
-    return (alignmentIndex - hiddenSeqs);
+    return (alignmentIndex - hiddenSeqs + diff);
+  }
+
+  /**
+   * Find the visible row which is a given visible number of rows above another
+   * visible row. i.e. for a startRow x, the row which is distance 1 away will
+   * be row x-1.
+   * 
+   * @param visibleDistance
+   *          the number of visible rows to offset by
+   * @param startRow
+   *          the row to start from
+   * @return the position of the row in the visible alignment
+   */
+  public int subtractVisibleRows(int visibleDistance, int startRow)
+  {
+    // walk upwards through the alignment
+    // count all the non-null sequences until we have visibleDistance counted
+    // then return the next visible sequence
+    if (hiddenSequences == null)
+    {
+      return startRow - visibleDistance;
+    }
+
+    int index = startRow;
+    int count = 0;
+    while ((index > -1) && (count < visibleDistance))
+    {
+      if (hiddenSequences[index] == null)
+      {
+        // count visible sequences
+        count++;
+      }
+      index--;
+    }
+    return index;
   }
 
+  /**
+   * Convert alignment index from visible alignment to absolute alignment
+   * 
+   * @param alignmentIndex
+   * @return
+   */
   public int adjustForHiddenSeqs(int alignmentIndex)
   {
     if (hiddenSequences == null)
index b5fc817..ab1ac0e 100644 (file)
@@ -86,6 +86,7 @@ import jalview.schemes.ResidueProperties;
 import jalview.schemes.TCoffeeColourScheme;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
 import jalview.ws.DBRefFetcher;
 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
 import jalview.ws.jws1.Discoverer;
@@ -160,6 +161,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
   AlignViewport viewport;
 
+  ViewportRanges vpRanges;
+
   public AlignViewControllerI avc;
 
   List<AlignmentPanel> alignPanels = new ArrayList<AlignmentPanel>();
@@ -331,6 +334,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       progressBar = new ProgressBar(this.statusPanel, this.statusBar);
     }
 
+    vpRanges = viewport.getRanges();
     avc = new jalview.controller.AlignViewController(this, viewport,
             alignPanel);
     if (viewport.getAlignmentConservationAnnotation() == null)
@@ -640,8 +644,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                   new String[] { (viewport.cursorMode ? "on" : "off") }));
           if (viewport.cursorMode)
           {
-            alignPanel.getSeqPanel().seqCanvas.cursorX = viewport.startRes;
-            alignPanel.getSeqPanel().seqCanvas.cursorY = viewport.startSeq;
+            alignPanel.getSeqPanel().seqCanvas.cursorX = vpRanges
+                    .getStartRes();
+            alignPanel.getSeqPanel().seqCanvas.cursorY = vpRanges
+                    .getStartSeq();
           }
           alignPanel.getSeqPanel().seqCanvas.repaint();
           break;
@@ -679,8 +685,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
           else
           {
-            alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
-                    - viewport.endSeq + viewport.startSeq);
+            alignPanel.setScrollValues(vpRanges.getStartRes(),
+                    2 * vpRanges.getStartSeq() - vpRanges.getEndSeq());
           }
           break;
         case KeyEvent.VK_PAGE_DOWN:
@@ -690,8 +696,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
           else
           {
-            alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
-                    + viewport.endSeq - viewport.startSeq);
+            alignPanel.setScrollValues(vpRanges.getStartRes(),
+                    vpRanges.getEndSeq());
           }
           break;
         }
@@ -2141,7 +2147,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       {
 
         // propagate alignment changed.
-        viewport.setEndSeq(alignment.getHeight());
+        vpRanges.setEndSeq(alignment.getHeight());
         if (annotationAdded)
         {
           // Duplicate sequence annotation in all views.
@@ -2545,7 +2551,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       {
         trimRegion = new TrimRegionCommand("Remove Left", true, seqs,
                 column, viewport.getAlignment());
-        viewport.setStartRes(0);
+        vpRanges.setStartRes(0);
       }
       else
       {
@@ -2612,13 +2618,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // This is to maintain viewport position on first residue
     // of first sequence
     SequenceI seq = viewport.getAlignment().getSequenceAt(0);
-    int startRes = seq.findPosition(viewport.startRes);
+    int startRes = seq.findPosition(vpRanges.getStartRes());
     // ShiftList shifts;
     // viewport.getAlignment().removeGaps(shifts=new ShiftList());
     // edit.alColumnChanges=shifts.getInverse();
     // if (viewport.hasHiddenColumns)
     // viewport.getColumnSelection().compensateForEdits(shifts);
-    viewport.setStartRes(seq.findIndex(startRes) - 1);
+    vpRanges.setStartRes(seq.findIndex(startRes) - 1);
     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
             .getSequences());
 
@@ -2651,12 +2657,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // This is to maintain viewport position on first residue
     // of first sequence
     SequenceI seq = viewport.getAlignment().getSequenceAt(0);
-    int startRes = seq.findPosition(viewport.startRes);
+    int startRes = seq.findPosition(vpRanges.getStartRes());
 
     addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
             viewport.getAlignment()));
 
-    viewport.setStartRes(seq.findIndex(startRes) - 1);
+    vpRanges.setStartRes(seq.findIndex(startRes) - 1);
 
     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
             .getSequences());
index e0efa7c..602e3a1 100644 (file)
@@ -46,12 +46,12 @@ import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
 import jalview.schemes.ResidueColourScheme;
 import jalview.schemes.UserColourScheme;
-import jalview.structure.CommandListener;
 import jalview.structure.SelectionSource;
 import jalview.structure.StructureSelectionManager;
 import jalview.structure.VamsasSource;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
 import jalview.ws.params.AutoCalcSetting;
 
 import java.awt.Container;
@@ -72,7 +72,7 @@ import javax.swing.JInternalFrame;
  * @version $Revision: 1.141 $
  */
 public class AlignViewport extends AlignmentViewport implements
-        SelectionSource, CommandListener
+        SelectionSource
 {
   Font font;
 
@@ -238,10 +238,7 @@ public class AlignViewport extends AlignmentViewport implements
 
   void init()
   {
-    this.startRes = 0;
-    this.endRes = alignment.getWidth() - 1;
-    this.startSeq = 0;
-    this.endSeq = alignment.getHeight() - 1;
+    ranges = new ViewportRanges(this.alignment);
     applyViewProperties();
 
     String fontName = Cache.getDefault("FONT_NAME", "SansSerif");
@@ -855,7 +852,7 @@ public class AlignViewport extends AlignmentViewport implements
       }
     }
 
-    setEndSeq(getAlignment().getHeight());
+    ranges.setEndSeq(getAlignment().getHeight());
     firePropertyChange("alignment", null, getAlignment().getSequences());
   }
 
index e61b042..ac137b9 100644 (file)
@@ -35,6 +35,7 @@ import jalview.schemes.ResidueProperties;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BorderLayout;
 import java.awt.Color;
@@ -69,6 +70,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
 {
   public AlignViewport av;
 
+  ViewportRanges vpRanges;
+
   OverviewPanel overviewPanel;
 
   private SeqPanel seqPanel;
@@ -91,9 +94,9 @@ public class AlignmentPanel extends GAlignmentPanel implements
   // this value is set false when selection area being dragged
   boolean fastPaint = true;
 
-  int hextent = 0;
+  private int hextent = 0;
 
-  int vextent = 0;
+  private int vextent = 0;
 
   /*
    * Flag set while scrolling to follow complementary cDNA/protein scroll. When
@@ -113,6 +116,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
   {
     alignFrame = af;
     this.av = av;
+    vpRanges = av.getRanges();
     setSeqPanel(new SeqPanel(av, this));
     setIdPanel(new IdPanel(av, this));
 
@@ -377,7 +381,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
        */
       if (centre)
       {
-        int offset = (av.getEndRes() - av.getStartRes() + 1) / 2 - 1;
+        int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2 - 1;
         start = Math.max(start - offset, 0);
         end = end + offset - 1;
       }
@@ -413,7 +417,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
       // + av.getStartSeq() + ", ends=" + av.getEndSeq());
       if (!av.getWrapAlignment())
       {
-        if ((startv = av.getStartRes()) >= start)
+        if ((startv = vpRanges.getStartRes()) >= start)
         {
           /*
            * Scroll left to make start of search results visible
@@ -421,7 +425,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
           // setScrollValues(start - 1, seqIndex); // plus one residue
           setScrollValues(start, seqIndex);
         }
-        else if ((endv = av.getEndRes()) <= end)
+        else if ((endv = vpRanges.getEndRes()) <= end)
         {
           /*
            * Scroll right to make end of search results visible
@@ -429,19 +433,20 @@ public class AlignmentPanel extends GAlignmentPanel implements
           // setScrollValues(startv + 1 + end - endv, seqIndex); // plus one
           setScrollValues(startv + end - endv, seqIndex);
         }
-        else if ((starts = av.getStartSeq()) > seqIndex)
+        else if ((starts = vpRanges.getStartSeq()) > seqIndex)
         {
           /*
            * Scroll up to make start of search results visible
            */
-          setScrollValues(av.getStartRes(), seqIndex);
+          setScrollValues(vpRanges.getStartRes(), seqIndex);
         }
-        else if ((ends = av.getEndSeq()) <= seqIndex)
+        else if ((ends = vpRanges.getEndSeq()) <= seqIndex)
         {
           /*
            * Scroll down to make end of search results visible
            */
-          setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1);
+          setScrollValues(vpRanges.getStartRes(), starts + seqIndex - ends
+                  + 1);
         }
         /*
          * Else results are already visible - no need to scroll
@@ -464,10 +469,11 @@ public class AlignmentPanel extends GAlignmentPanel implements
   {
     int cwidth = getSeqPanel().seqCanvas
             .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
-    if (res < av.getStartRes() || res >= (av.getStartRes() + cwidth))
+    if (res < vpRanges.getStartRes()
+            || res >= (vpRanges.getStartRes() + cwidth))
     {
       vscroll.setValue((res / cwidth));
-      av.startRes = vscroll.getValue() * cwidth;
+      vpRanges.setStartRes(vscroll.getValue() * cwidth);
     }
 
   }
@@ -591,7 +597,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
     fontChanged();
     setAnnotationVisible(av.isShowAnnotation());
     boolean wrap = av.getWrapAlignment();
-    av.startSeq = 0;
+    vpRanges.setStartSeq(0);
     scalePanelHolder.setVisible(!wrap);
     hscroll.setVisible(!wrap);
     idwidthAdjuster.setVisible(!wrap);
@@ -688,7 +694,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
    */
   public void setScrollValues(int x, int y)
   {
-    // System.err.println("Scroll " + this.av.viewName + " to " + x + "," + y);
     if (av == null || av.getAlignment() == null)
     {
       return;
@@ -698,12 +703,10 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
     if (av.hasHiddenColumns())
     {
+      // reset the width to exclude hidden columns
       width = av.getColumnSelection().findColumnPosition(width);
     }
 
-    av.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
-            .getCharWidth())) - 1);
-
     hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
     vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight();
 
@@ -737,6 +740,10 @@ public class AlignmentPanel extends GAlignmentPanel implements
       x = 0;
     }
 
+    // update endRes after x has (possibly) been adjusted
+    vpRanges.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
+            .getCharWidth())) - 1);
+
     /*
      * each scroll adjustment triggers adjustmentValueChanged, which resets the
      * 'do not scroll complement' flag; ensure it is the same for both
@@ -757,14 +764,14 @@ public class AlignmentPanel extends GAlignmentPanel implements
   @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
-    int oldX = av.getStartRes();
-    int oldY = av.getStartSeq();
+    int oldX = vpRanges.getStartRes();
+    int oldY = vpRanges.getStartSeq();
 
     if (evt.getSource() == hscroll)
     {
       int x = hscroll.getValue();
-      av.setStartRes(x);
-      av.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
+      vpRanges.setStartRes(x);
+      vpRanges.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
               .getCharWidth())) - 1);
     }
 
@@ -778,8 +785,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
         {
           int rowSize = getSeqPanel().seqCanvas
                   .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
-          av.setStartRes(offy * rowSize);
-          av.setEndRes((offy + 1) * rowSize);
+          vpRanges.setStartRes(offy * rowSize);
+          vpRanges.setEndRes((offy + 1) * rowSize);
         }
         else
         {
@@ -791,16 +798,18 @@ public class AlignmentPanel extends GAlignmentPanel implements
             @Override
             public void run()
             {
-              setScrollValues(av.getStartRes(), av.getStartSeq());
+              setScrollValues(vpRanges.getStartRes(),
+                      vpRanges.getStartSeq());
             }
           });
         }
       }
       else
       {
-        av.setStartSeq(offy);
-        av.setEndSeq(offy
-                + (getSeqPanel().seqCanvas.getHeight() / av.getCharHeight()));
+        vpRanges.setStartSeq(offy);
+        vpRanges.setEndSeq(offy
+                + (getSeqPanel().seqCanvas.getHeight() / av.getCharHeight())
+                - 1);
       }
     }
 
@@ -809,8 +818,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
       overviewPanel.setBoxPosition();
     }
 
-    int scrollX = av.startRes - oldX;
-    int scrollY = av.startSeq - oldY;
+    int scrollX = vpRanges.getStartRes() - oldX;
+    int scrollY = vpRanges.getStartSeq() - oldY;
 
     if (av.getWrapAlignment() || !fastPaint)
     {
@@ -820,13 +829,13 @@ public class AlignmentPanel extends GAlignmentPanel implements
     {
       // Make sure we're not trying to draw a panel
       // larger than the visible window
-      if (scrollX > av.endRes - av.startRes)
+      if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
       {
-        scrollX = av.endRes - av.startRes;
+        scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
       }
-      else if (scrollX < av.startRes - av.endRes)
+      else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
       {
-        scrollX = av.startRes - av.endRes;
+        scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
       }
 
       if (scrollX != 0 || scrollY != 0)
@@ -926,7 +935,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
     }
     else
     {
-      setScrollValues(av.getStartRes(), av.getStartSeq());
+      setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
     }
   }
 
index b1f0edb..84f3e6c 100755 (executable)
@@ -55,7 +55,6 @@ import java.util.List;
 
 import javax.swing.JColorChooser;
 import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.Scrollable;
@@ -708,7 +707,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       return;
     }
 
-    int column = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+    int column = (evt.getX() / av.getCharWidth())
+            + av.getRanges().getStartRes();
 
     if (av.hasHiddenColumns())
     {
@@ -905,7 +905,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         return;
       }
     }
-    imgWidth = (av.endRes - av.startRes + 1) * av.getCharWidth();
+    imgWidth = (av.getRanges().getEndRes() - av.getRanges().getStartRes() + 1)
+            * av.getCharWidth();
     if (imgWidth < 1)
     {
       return;
@@ -946,7 +947,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       imageFresh = true;
     }
 
-    drawComponent(gg, av.startRes, av.endRes + 1);
+    drawComponent(gg, av.getRanges().getStartRes(), av.getRanges()
+            .getEndRes() + 1);
     imageFresh = false;
     g.drawImage(image, 0, 0, this);
   }
@@ -976,8 +978,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     gg.copyArea(0, 0, imgWidth, getHeight(),
             -horizontal * av.getCharWidth(), 0);
     long mtime = System.currentTimeMillis();
-    int sr = av.startRes;
-    int er = av.endRes + 1;
+    int sr = av.getRanges().getStartRes();
+    int er = av.getRanges().getEndRes() + 1;
     int transX = 0;
 
     if (horizontal > 0) // scrollbar pulled right, image to the left
index 37be8bc..aad0776 100755 (executable)
@@ -21,6 +21,7 @@
 package jalview.gui;
 
 import jalview.datamodel.SequenceI;
+import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BorderLayout;
 import java.awt.Color;
@@ -158,33 +159,35 @@ public class IdCanvas extends JPanel
       return;
     }
 
+    ViewportRanges ranges = av.getRanges();
+
     gg.copyArea(0, 0, getWidth(), imgHeight, 0,
             -vertical * av.getCharHeight());
 
-    int ss = av.startSeq;
-    int es = av.endSeq;
+    int ss = ranges.getStartSeq();
+    int es = ranges.getEndSeq();
     int transY = 0;
 
     if (vertical > 0) // scroll down
     {
       ss = es - vertical;
 
-      if (ss < av.startSeq)
+      if (ss < ranges.getStartSeq())
       { // ie scrolling too fast, more than a page at a time
-        ss = av.startSeq;
+        ss = ranges.getStartSeq();
       }
       else
       {
-        transY = imgHeight - (vertical * av.getCharHeight());
+        transY = imgHeight - ((vertical + 1) * av.getCharHeight());
       }
     }
-    else if (vertical < 0)
+    else if (vertical < 0) // scroll up
     {
       es = ss - vertical;
 
-      if (es > av.endSeq)
+      if (es > ranges.getEndSeq())
       {
-        es = av.endSeq;
+        es = ranges.getEndSeq();
       }
     }
 
@@ -240,7 +243,7 @@ public class IdCanvas extends JPanel
     gg.setColor(Color.white);
     gg.fillRect(0, 0, getWidth(), imgHeight);
 
-    drawIds(av.getStartSeq(), av.endSeq);
+    drawIds(av.getRanges().getStartSeq(), av.getRanges().getEndSeq());
 
     g.drawImage(image, 0, 0, this);
   }
@@ -314,10 +317,11 @@ public class IdCanvas extends JPanel
 
       int cHeight = alheight * av.getCharHeight() + hgap + annotationHeight;
 
-      int rowSize = av.getEndRes() - av.getStartRes();
+      int rowSize = av.getRanges().getEndRes()
+              - av.getRanges().getStartRes();
 
       // Draw the rest of the panels
-      for (int ypos = hgap, row = av.startRes; (ypos <= getHeight())
+      for (int ypos = hgap, row = av.getRanges().getStartRes(); (ypos <= getHeight())
               && (row < maxwidth); ypos += cHeight, row += rowSize)
       {
         for (int i = starty; i < alheight; i++)
@@ -354,7 +358,7 @@ public class IdCanvas extends JPanel
 
       SequenceI sequence;
       // Now draw the id strings
-      for (int i = starty; i < endy; i++)
+      for (int i = starty; i <= endy; i++)
       {
         sequence = av.getAlignment().getSequenceAt(i);
 
index 6ae19f0..2074900 100755 (executable)
@@ -242,13 +242,14 @@ public class IdPanel extends JPanel implements MouseListener,
       return;
     }
 
-    if (mouseDragging && (e.getY() < 0) && (av.getStartSeq() > 0))
+    if (mouseDragging && (e.getY() < 0)
+            && (av.getRanges().getStartSeq() > 0))
     {
       scrollThread = new ScrollThread(true);
     }
 
     if (mouseDragging && (e.getY() >= getHeight())
-            && (av.getAlignment().getHeight() > av.getEndSeq()))
+            && (av.getAlignment().getHeight() > av.getRanges().getEndSeq()))
     {
       scrollThread = new ScrollThread(false);
     }
@@ -442,9 +443,10 @@ public class IdPanel extends JPanel implements MouseListener,
     int index = av.getAlignment().findIndex(list.get(0));
 
     // do we need to scroll the panel?
-    if ((av.getStartSeq() > index) || (av.getEndSeq() < index))
+    if ((av.getRanges().getStartSeq() > index)
+            || (av.getRanges().getEndSeq() < index))
     {
-      alignPanel.setScrollValues(av.getStartRes(), index);
+      alignPanel.setScrollValues(av.getRanges().getStartRes(), index);
     }
   }
 
@@ -486,11 +488,11 @@ public class IdPanel extends JPanel implements MouseListener,
         if (alignPanel.scrollUp(up))
         {
           // scroll was ok, so add new sequence to selection
-          int seq = av.getStartSeq();
+          int seq = av.getRanges().getStartSeq();
 
           if (!up)
           {
-            seq = av.getEndSeq();
+            seq = av.getRanges().getEndSeq();
           }
 
           if (seq < lastid)
index 3ac453f..e8b832d 100644 (file)
@@ -87,6 +87,7 @@ import jalview.util.Platform;
 import jalview.util.StringUtils;
 import jalview.util.jarInputStreamProvider;
 import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
 import jalview.ws.jws2.Jws2Discoverer;
@@ -755,6 +756,7 @@ public class Jalview2XML
     List<UserColourScheme> userColours = new ArrayList<UserColourScheme>();
 
     AlignViewport av = ap.av;
+    ViewportRanges vpRanges = av.getRanges();
 
     JalviewModel object = new JalviewModel();
     object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
@@ -1270,8 +1272,8 @@ public class Jalview2XML
       view.setWidth(size.width);
       view.setHeight(size.height);
 
-      view.setStartRes(av.startRes);
-      view.setStartSeq(av.startSeq);
+      view.setStartRes(vpRanges.getStartRes());
+      view.setStartSeq(vpRanges.getStartSeq());
 
       if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
       {
@@ -4448,8 +4450,8 @@ public class Jalview2XML
     af.viewport.setThresholdTextColour(view.getTextColThreshold());
     af.viewport.setShowUnconserved(view.hasShowUnconserved() ? view
             .isShowUnconserved() : false);
-    af.viewport.setStartRes(view.getStartRes());
-    af.viewport.setStartSeq(view.getStartSeq());
+    af.viewport.getRanges().setStartRes(view.getStartRes());
+    af.viewport.getRanges().setStartSeq(view.getStartSeq());
     af.alignPanel.updateLayout();
     ColourSchemeI cs = null;
     // apply colourschemes
index e751a2c..6235cbe 100755 (executable)
@@ -367,8 +367,8 @@ public class Jalview2XML_V1
 
     af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
             view.getHeight());
-    af.viewport.setStartRes(view.getStartRes());
-    af.viewport.setStartSeq(view.getStartSeq());
+    af.viewport.getRanges().setStartRes(view.getStartRes());
+    af.viewport.getRanges().setStartSeq(view.getStartSeq());
     af.viewport.setShowAnnotation(view.getShowAnnotation());
     af.viewport.setAbovePIDThreshold(view.getPidSelected());
     af.viewport.setColourText(view.getShowColourText());
index 4097c40..ac2138f 100755 (executable)
  */
 package jalview.gui;
 
+import jalview.datamodel.SequenceI;
 import jalview.renderer.AnnotationRenderer;
 import jalview.renderer.seqfeatures.FeatureColourFinder;
+import jalview.viewmodel.OverviewDimensions;
 
 import java.awt.Color;
 import java.awt.Dimension;
@@ -36,57 +38,51 @@ import java.awt.image.BufferedImage;
 import javax.swing.JPanel;
 
 /**
- * DOCUMENT ME!
+ * Panel displaying an overview of the full alignment, with an interactive box
+ * representing the viewport onto the alignment.
  * 
  * @author $author$
  * @version $Revision$
  */
 public class OverviewPanel extends JPanel implements Runnable
 {
-  BufferedImage miniMe;
+  private static final Color TRANS_GREY = new Color(100, 100, 100, 25);
 
-  AlignViewport av;
+  private final AnnotationRenderer renderer = new AnnotationRenderer();
 
-  AlignmentPanel ap;
+  private OverviewDimensions od;
 
-  final AnnotationRenderer renderer = new AnnotationRenderer();
+  private BufferedImage miniMe;
 
-  float scalew = 1f;
-
-  float scaleh = 1f;
-
-  int width;
-
-  int sequencesHeight;
-
-  int graphHeight = 20;
-
-  int boxX = -1;
+  private BufferedImage lastMiniMe = null;
 
-  int boxY = -1;
+  private AlignViewport av;
 
-  int boxWidth = -1;
+  private AlignmentPanel ap;
 
-  int boxHeight = -1;
+  //
+  private boolean resizing = false;
 
-  boolean resizing = false;
+  // This is set true if the user resizes whilst
+  // the overview is being calculated
+  private boolean resizeAgain = false;
 
   // Can set different properties in this seqCanvas than
   // main visible SeqCanvas
-  SequenceRenderer sr;
+  private SequenceRenderer sr;
 
   jalview.renderer.seqfeatures.FeatureRenderer fr;
 
   /**
    * Creates a new OverviewPanel object.
    * 
-   * @param ap
-   *          DOCUMENT ME!
+   * @param alPanel
+   *          The alignment panel which is shown in the overview panel
    */
-  public OverviewPanel(AlignmentPanel ap)
+  public OverviewPanel(AlignmentPanel alPanel)
   {
-    this.av = ap.av;
-    this.ap = ap;
+    this.av = alPanel.av;
+    this.ap = alPanel;
     setLayout(null);
 
     sr = new SequenceRenderer(av);
@@ -94,44 +90,15 @@ public class OverviewPanel extends JPanel implements Runnable
     sr.forOverview = true;
     fr = new FeatureRenderer(ap);
 
-    // scale the initial size of overviewpanel to shape of alignment
-    float initialScale = (float) av.getAlignment().getWidth()
-            / (float) av.getAlignment().getHeight();
-
-    if (av.getAlignmentConservationAnnotation() == null)
-    {
-      graphHeight = 0;
-    }
-
-    if (av.getAlignment().getWidth() > av.getAlignment().getHeight())
-    {
-      // wider
-      width = 400;
-      sequencesHeight = (int) (400f / initialScale);
-      if (sequencesHeight < 40)
-      {
-        sequencesHeight = 40;
-      }
-    }
-    else
-    {
-      // taller
-      width = (int) (400f * initialScale);
-      sequencesHeight = 300;
-
-      if (width < 120)
-      {
-        width = 120;
-      }
-    }
+    od = new OverviewDimensions(av.getRanges(), av.isShowAnnotation());
 
     addComponentListener(new ComponentAdapter()
     {
       @Override
       public void componentResized(ComponentEvent evt)
       {
-        if ((getWidth() != width)
-                || (getHeight() != (sequencesHeight + graphHeight)))
+        if ((getWidth() != od.getWidth())
+                || (getHeight() != (od.getHeight())))
         {
           updateOverviewImage();
         }
@@ -145,11 +112,10 @@ public class OverviewPanel extends JPanel implements Runnable
       {
         if (!av.getWrapAlignment())
         {
-          // TODO: feature: jv2.5 detect shift drag and update selection from
-          // it.
-          boxX = evt.getX();
-          boxY = evt.getY();
-          checkValid();
+          od.updateViewportFromMouse(evt.getX(), evt.getY(), av
+                  .getAlignment().getHiddenSequences(), av
+                  .getColumnSelection(), av.getRanges());
+          ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
         }
       }
     });
@@ -161,9 +127,10 @@ public class OverviewPanel extends JPanel implements Runnable
       {
         if (!av.getWrapAlignment())
         {
-          boxX = evt.getX();
-          boxY = evt.getY();
-          checkValid();
+          od.updateViewportFromMouse(evt.getX(), evt.getY(), av
+                  .getAlignment().getHiddenSequences(), av
+                  .getColumnSelection(), av.getRanges());
+          ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
         }
       }
     });
@@ -172,60 +139,7 @@ public class OverviewPanel extends JPanel implements Runnable
   }
 
   /**
-   * DOCUMENT ME!
-   */
-  void checkValid()
-  {
-    if (boxY < 0)
-    {
-      boxY = 0;
-    }
-
-    if (boxY > (sequencesHeight - boxHeight))
-    {
-      boxY = sequencesHeight - boxHeight + 1;
-    }
-
-    if (boxX < 0)
-    {
-      boxX = 0;
-    }
-
-    if (boxX > (width - boxWidth))
-    {
-      if (av.hasHiddenColumns())
-      {
-        // Try smallest possible box
-        boxWidth = (int) ((av.endRes - av.startRes + 1) * av.getCharWidth() * scalew);
-      }
-      boxX = width - boxWidth;
-    }
-
-    int col = (int) (boxX / scalew / av.getCharWidth());
-    int row = (int) (boxY / scaleh / av.getCharHeight());
-
-    if (av.hasHiddenColumns())
-    {
-      if (!av.getColumnSelection().isVisible(col))
-      {
-        return;
-      }
-
-      col = av.getColumnSelection().findColumnPosition(col);
-    }
-
-    if (av.hasHiddenRows())
-    {
-      row = av.getAlignment().getHiddenSequences()
-              .findIndexWithoutHiddenSeqs(row);
-    }
-
-    ap.setScrollValues(col, row);
-
-  }
-
-  /**
-   * DOCUMENT ME!
+   * Updates the overview image when the related alignment panel is updated
    */
   public void updateOverviewImage()
   {
@@ -239,24 +153,17 @@ public class OverviewPanel extends JPanel implements Runnable
 
     if ((getWidth() > 0) && (getHeight() > 0))
     {
-      width = getWidth();
-      sequencesHeight = getHeight() - graphHeight;
+      od.setWidth(getWidth());
+      od.setHeight(getHeight());
     }
 
-    setPreferredSize(new Dimension(width, sequencesHeight + graphHeight));
+    setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
 
     Thread thread = new Thread(this);
     thread.start();
     repaint();
   }
 
-  // This is set true if the user resizes whilst
-  // the overview is being calculated
-  boolean resizeAgain = false;
-
-  /**
-   * DOCUMENT ME!
-   */
   @Override
   public void run()
   {
@@ -267,146 +174,45 @@ public class OverviewPanel extends JPanel implements Runnable
       fr.transferSettings(ap.getSeqPanel().seqCanvas.getFeatureRenderer());
     }
 
-    int alwidth = av.getAlignment().getWidth();
-    int alheight = av.getAlignment().getHeight()
-            + av.getAlignment().getHiddenSequences().getSize();
-
-    setPreferredSize(new Dimension(width, sequencesHeight + graphHeight));
-
-    int fullsizeWidth = alwidth * av.getCharWidth();
-    int fullsizeHeight = alheight * av.getCharHeight();
+    // why do we need to set preferred size again? was set in
+    // updateOverviewImage
+    setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
 
-    scalew = (float) width / (float) fullsizeWidth;
-    scaleh = (float) sequencesHeight / (float) fullsizeHeight;
-
-    miniMe = new BufferedImage(width, sequencesHeight + graphHeight,
+    miniMe = new BufferedImage(od.getWidth(), od.getHeight(),
             BufferedImage.TYPE_INT_RGB);
 
     Graphics mg = miniMe.getGraphics();
     mg.setColor(Color.orange);
-    mg.fillRect(0, 0, width, miniMe.getHeight());
-
-    float sampleCol = (float) alwidth / (float) width;
-    float sampleRow = (float) alheight / (float) sequencesHeight;
-
-    int lastcol = -1, lastrow = -1;
-    Color color = Color.white;
-    int row, col;
-    jalview.datamodel.SequenceI seq;
-    final boolean hasHiddenRows = av.hasHiddenRows(), hasHiddenCols = av
-            .hasHiddenColumns();
-    boolean hiddenRow = false;
-    // get hidden row and hidden column map once at beginning.
-    // clone featureRenderer settings to avoid race conditions... if state is
-    // updated just need to refresh again
-
-    FeatureColourFinder finder = new FeatureColourFinder(fr);
-
-    for (row = 0; row < sequencesHeight; row++)
-    {
-      if (resizeAgain)
-      {
-        break;
-      }
-      if ((int) (row * sampleRow) == lastrow)
-      {
-        // No need to recalculate the colours,
-        // Just copy from the row above
-        for (col = 0; col < width; col++)
-        {
-          if (resizeAgain)
-          {
-            break;
-          }
-          miniMe.setRGB(col, row, miniMe.getRGB(col, row - 1));
-        }
-        continue;
-      }
-
-      lastrow = (int) (row * sampleRow);
-
-      hiddenRow = false;
-      if (hasHiddenRows)
-      {
-        seq = av.getAlignment().getHiddenSequences()
-                .getHiddenSequence(lastrow);
-        if (seq == null)
-        {
-          int index = av.getAlignment().getHiddenSequences()
-                  .findIndexWithoutHiddenSeqs(lastrow);
-
-          seq = av.getAlignment().getSequenceAt(index);
-        }
-        else
-        {
-          hiddenRow = true;
-        }
-      }
-      else
-      {
-        seq = av.getAlignment().getSequenceAt(lastrow);
-      }
-
-      if (seq == null)
-      {
-        System.out.println(lastrow + " null");
-        continue;
-      }
-
-      for (col = 0; col < width; col++)
-      {
-        if (resizeAgain)
-        {
-          break;
-        }
-        if ((int) (col * sampleCol) == lastcol
-                && (int) (row * sampleRow) == lastrow)
-        {
-          miniMe.setRGB(col, row, color.getRGB());
-          continue;
-        }
+    mg.fillRect(0, 0, od.getWidth(), miniMe.getHeight());
 
-        lastcol = (int) (col * sampleCol);
-
-        if (seq.getLength() > lastcol)
-        {
-          color = sr.getResidueColour(seq, lastcol, finder);
-        }
-        else
-        {
-          color = Color.WHITE;
-        }
+    // calculate sampleCol and sampleRow
+    // alignment width is max number of residues/bases
+    // alignment height is number of sequences
+    int alwidth = av.getAlignment().getWidth();
+    int alheight = av.getAlignment().getAbsoluteHeight();
 
-        if (hiddenRow
-                || (hasHiddenCols && !av.getColumnSelection().isVisible(
-                        lastcol)))
-        {
-          color = color.darker().darker();
-        }
+    // sampleCol or sampleRow is the width/height allocated to each residue
+    // in particular, sometimes we may need more than one row/col of the
+    // BufferedImage allocated
+    // sampleCol is how much of a residue to assign to each pixel
+    // sampleRow is how many sequences to assign to each pixel
+    float sampleCol = alwidth / (float) od.getWidth();
+    float sampleRow = alheight / (float) od.getSequencesHeight();
 
-        miniMe.setRGB(col, row, color.getRGB());
+    buildImage(sampleRow, sampleCol);
 
-      }
-    }
-
-    if (av.getAlignmentConservationAnnotation() != null)
+    if (av.isShowAnnotation())
     {
       renderer.updateFromAlignViewport(av);
-      for (col = 0; col < width; col++)
+      for (int col = 0; col < od.getWidth() && !resizeAgain; col++)
       {
-        if (resizeAgain)
-        {
-          break;
-        }
-        lastcol = (int) (col * sampleCol);
-        {
-          mg.translate(col, sequencesHeight);
-          renderer.drawGraph(mg, av.getAlignmentConservationAnnotation(),
-                  av.getAlignmentConservationAnnotation().annotations,
-                  (int) (sampleCol) + 1, graphHeight,
-                  (int) (col * sampleCol), (int) (col * sampleCol) + 1);
-          mg.translate(-col, -sequencesHeight);
-        }
+        mg.translate(col, od.getSequencesHeight());
+        renderer.drawGraph(mg, av.getAlignmentConservationAnnotation(),
+                av.getAlignmentConservationAnnotation().annotations,
+                (int) (sampleCol) + 1, od.getGraphHeight(),
+                (int) (col * sampleCol), (int) (col * sampleCol) + 1);
+        mg.translate(-col, -od.getSequencesHeight());
+
       }
     }
     System.gc();
@@ -426,66 +232,97 @@ public class OverviewPanel extends JPanel implements Runnable
     setBoxPosition();
   }
 
-  /**
-   * DOCUMENT ME!
+  /*
+   * Build the overview panel image
    */
-  public void setBoxPosition()
+  private void buildImage(float sampleRow, float sampleCol)
   {
-    int fullsizeWidth = av.getAlignment().getWidth() * av.getCharWidth();
-    int fullsizeHeight = (av.getAlignment().getHeight() + av.getAlignment()
-            .getHiddenSequences().getSize())
-            * av.getCharHeight();
+    int lastcol = -1;
+    int lastrow = -1;
+    int rgbColour = Color.white.getRGB();
 
-    int startRes = av.getStartRes();
-    int endRes = av.getEndRes();
+    SequenceI seq = null;
+    FeatureColourFinder finder = new FeatureColourFinder(fr);
 
-    if (av.hasHiddenColumns())
+    final boolean hasHiddenCols = av.hasHiddenColumns();
+    boolean hiddenRow = false;
+    // get hidden row and hidden column map once at beginning.
+    // clone featureRenderer settings to avoid race conditions... if state is
+    // updated just need to refresh again
+    for (int row = 0; row < od.getSequencesHeight() && !resizeAgain; row++)
     {
-      startRes = av.getColumnSelection().adjustForHiddenColumns(startRes);
-      endRes = av.getColumnSelection().adjustForHiddenColumns(endRes);
-    }
+      boolean doCopy = true;
+      int currentrow = (int) (row * sampleRow);
+      if (currentrow != lastrow)
+      {
+        doCopy = false;
 
-    int startSeq = av.startSeq;
-    int endSeq = av.endSeq;
+        lastrow = currentrow;
 
-    if (av.hasHiddenRows())
-    {
-      startSeq = av.getAlignment().getHiddenSequences()
-              .adjustForHiddenSeqs(startSeq);
+        // get the sequence which would be at alignment index 'lastrow' if no
+        // rows were hidden, and determine whether it is hidden or not
+        hiddenRow = av.getAlignment().isHidden(lastrow);
+        seq = av.getAlignment().getSequenceAtAbsoluteIndex(lastrow);
+      }
 
-      endSeq = av.getAlignment().getHiddenSequences()
-              .adjustForHiddenSeqs(endSeq);
+      for (int col = 0; col < od.getWidth() && !resizeAgain; col++)
+      {
+        if (doCopy)
+        {
+          rgbColour = miniMe.getRGB(col, row - 1);
+        }
+        else if ((int) (col * sampleCol) != lastcol
+                || (int) (row * sampleRow) != lastrow)
+        {
+          lastcol = (int) (col * sampleCol);
+          rgbColour = getColumnColourFromSequence(seq, hiddenRow,
+                  hasHiddenCols, lastcol, finder);
+        }
+        // else we just use the color we already have , so don't need to set it
 
+        miniMe.setRGB(col, row, rgbColour);
+      }
     }
+  }
 
-    scalew = (float) width / (float) fullsizeWidth;
-    scaleh = (float) sequencesHeight / (float) fullsizeHeight;
-
-    boxX = (int) (startRes * av.getCharWidth() * scalew);
-    boxY = (int) (startSeq * av.getCharHeight() * scaleh);
+  /*
+   * Find the colour of a sequence at a specified column position
+   */
+  private int getColumnColourFromSequence(
+          jalview.datamodel.SequenceI seq,
+          boolean hiddenRow, boolean hasHiddenCols, int lastcol,
+          FeatureColourFinder finder)
+  {
+    Color color = Color.white;
 
-    if (av.hasHiddenColumns())
+    if ((seq != null) && (seq.getLength() > lastcol))
     {
-      boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
+       color = sr.getResidueColour(seq, lastcol, finder);
     }
-    else
+
+    if (hiddenRow
+            || (hasHiddenCols && !av.getColumnSelection()
+                    .isVisible(lastcol)))
     {
-      boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
+      color = color.darker().darker();
     }
 
-    boxHeight = (int) ((endSeq - startSeq) * av.getCharHeight() * scaleh);
-
-    repaint();
+    return color.getRGB();
   }
 
-  private BufferedImage lastMiniMe = null;
-
   /**
-   * DOCUMENT ME!
+   * Update the overview panel box when the associated alignment panel is
+   * changed
    * 
-   * @param g
-   *          DOCUMENT ME!
    */
+  public void setBoxPosition()
+  {
+    od.setBoxPosition(av.getAlignment()
+            .getHiddenSequences(), av.getColumnSelection(), av.getRanges());
+    repaint();
+  }
+
+
   @Override
   public void paintComponent(Graphics g)
   {
@@ -500,7 +337,7 @@ public class OverviewPanel extends JPanel implements Runnable
       {
         g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this);
       }
-      g.setColor(new Color(100, 100, 100, 25));
+      g.setColor(TRANS_GREY);
       g.fillRect(0, 0, getWidth(), getHeight());
     }
     else if (lastMiniMe != null)
@@ -508,13 +345,12 @@ public class OverviewPanel extends JPanel implements Runnable
       g.drawImage(lastMiniMe, 0, 0, this);
       if (lastMiniMe != miniMe)
       {
-        g.setColor(new Color(100, 100, 100, 25));
+        g.setColor(TRANS_GREY);
         g.fillRect(0, 0, getWidth(), getHeight());
       }
     }
-    // TODO: render selected regions
+
     g.setColor(Color.red);
-    g.drawRect(boxX, boxY, boxWidth, boxHeight);
-    g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);
+    od.drawBox(g);
   }
 }
index 8961f21..de21be6 100755 (executable)
@@ -101,7 +101,7 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
   @Override
   public void mousePressed(MouseEvent evt)
   {
-    int x = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+    int x = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes();
     final int res;
 
     if (av.hasHiddenColumns())
@@ -282,7 +282,8 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
   {
     mouseDragging = false;
 
-    int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+    int res = (evt.getX() / av.getCharWidth())
+            + av.getRanges().getStartRes();
 
     if (av.hasHiddenColumns())
     {
@@ -337,7 +338,8 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
     mouseDragging = true;
     ColumnSelection cs = av.getColumnSelection();
 
-    int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+    int res = (evt.getX() / av.getCharWidth())
+            + av.getRanges().getStartRes();
     res = Math.max(0, res);
     res = cs.adjustForHiddenColumns(res);
     res = Math.min(res, av.getAlignment().getWidth() - 1);
@@ -389,7 +391,8 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
       return;
     }
 
-    int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+    int res = (evt.getX() / av.getCharWidth())
+            + av.getRanges().getStartRes();
 
     res = av.getColumnSelection().adjustForHiddenColumns(res);
 
@@ -419,7 +422,8 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
   @Override
   public void paintComponent(Graphics g)
   {
-    drawScale(g, av.getStartRes(), av.getEndRes(), getWidth(), getHeight());
+    drawScale(g, av.getRanges().getStartRes(), av.getRanges().getEndRes(),
+            getWidth(), getHeight());
   }
 
   // scalewidth will normally be screenwidth,
index 97889af..4557819 100755 (executable)
@@ -26,6 +26,7 @@ import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.ScaleRenderer;
 import jalview.renderer.ScaleRenderer.ScaleMark;
+import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BasicStroke;
 import java.awt.BorderLayout;
@@ -279,10 +280,11 @@ public class SeqCanvas extends JComponent
     gg.copyArea(horizontal * charWidth, vertical * charHeight, imgWidth,
             imgHeight, -horizontal * charWidth, -vertical * charHeight);
 
-    int sr = av.startRes;
-    int er = av.endRes;
-    int ss = av.startSeq;
-    int es = av.endSeq;
+    ViewportRanges ranges = av.getRanges();
+    int sr = ranges.getStartRes();
+    int er = ranges.getEndRes();
+    int ss = ranges.getStartSeq();
+    int es = ranges.getEndSeq();
     int transX = 0;
     int transY = 0;
 
@@ -300,22 +302,22 @@ public class SeqCanvas extends JComponent
     {
       ss = es - vertical;
 
-      if (ss < av.startSeq)
+      if (ss < ranges.getStartSeq())
       { // ie scrolling too fast, more than a page at a time
-        ss = av.startSeq;
+        ss = ranges.getStartSeq();
       }
       else
       {
-        transY = imgHeight - (vertical * charHeight);
+        transY = imgHeight - ((vertical + 1) * charHeight);
       }
     }
     else if (vertical < 0)
     {
       es = ss - vertical;
 
-      if (es > av.endSeq)
+      if (es > ranges.getEndSeq())
       {
-        es = av.endSeq;
+        es = ranges.getEndSeq();
       }
     }
 
@@ -395,13 +397,15 @@ public class SeqCanvas extends JComponent
     gg.setColor(Color.white);
     gg.fillRect(0, 0, imgWidth, imgHeight);
 
+    ViewportRanges ranges = av.getRanges();
     if (av.getWrapAlignment())
     {
-      drawWrappedPanel(gg, getWidth(), getHeight(), av.startRes);
+      drawWrappedPanel(gg, getWidth(), getHeight(), ranges.getStartRes());
     }
     else
     {
-      drawPanel(gg, av.startRes, av.endRes, av.startSeq, av.endSeq, 0);
+      drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(),
+              ranges.getStartSeq(), ranges.getEndSeq(), 0);
     }
 
     g.drawImage(lcimg, 0, 0, this);
@@ -503,7 +507,7 @@ public class SeqCanvas extends JComponent
 
     av.setWrappedWidth(cWidth);
 
-    av.endRes = av.startRes + cWidth;
+    av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth);
 
     int endx;
     int ypos = hgap;
@@ -718,7 +722,7 @@ public class SeqCanvas extends JComponent
 
     // / First draw the sequences
     // ///////////////////////////
-    for (int i = startSeq; i < endSeq; i++)
+    for (int i = startSeq; i <= endSeq; i++)
     {
       nextSeq = av.getAlignment().getSequenceAt(i);
       if (nextSeq == null)
@@ -802,7 +806,7 @@ public class SeqCanvas extends JComponent
         int top = -1;
         int bottom = -1;
 
-        for (i = startSeq; i < endSeq; i++)
+        for (i = startSeq; i <= endSeq; i++)
         {
           sx = (group.getStartRes() - startRes) * charWidth;
           sy = offset + ((i - startSeq) * charHeight);
index 37b4852..db7aa36 100644 (file)
@@ -209,7 +209,7 @@ public class SeqPanel extends JPanel implements MouseListener,
       }
 
       wrappedBlock = y / cHeight;
-      wrappedBlock += av.getStartRes() / cwidth;
+      wrappedBlock += av.getRanges().getStartRes() / cwidth;
 
       res = wrappedBlock * cwidth + x / av.getCharWidth();
 
@@ -222,11 +222,11 @@ public class SeqPanel extends JPanel implements MouseListener,
         // right-hand gutter
         x = seqCanvas.getX() + seqCanvas.getWidth();
       }
-      res = (x / av.getCharWidth()) + av.getStartRes();
-      if (res > av.getEndRes())
+      res = (x / av.getCharWidth()) + av.getRanges().getStartRes();
+      if (res > av.getRanges().getEndRes())
       {
         // moused off right
-        res = av.getEndRes();
+        res = av.getRanges().getEndRes();
       }
     }
 
@@ -262,7 +262,9 @@ public class SeqPanel extends JPanel implements MouseListener,
     }
     else
     {
-      seq = Math.min((y / av.getCharHeight()) + av.getStartSeq(), av
+      seq = Math.min((y / av.getCharHeight())
+              + av.getRanges().getStartSeq(),
+              av
               .getAlignment().getHeight() - 1);
     }
 
@@ -385,18 +387,18 @@ public class SeqPanel extends JPanel implements MouseListener,
     }
     else
     {
-      while (seqCanvas.cursorY < av.startSeq)
+      while (seqCanvas.cursorY < av.getRanges().getStartSeq())
       {
         ap.scrollUp(true);
       }
-      while (seqCanvas.cursorY + 1 > av.endSeq)
+      while (seqCanvas.cursorY + 1 > av.getRanges().getEndSeq())
       {
         ap.scrollUp(false);
       }
       if (!av.getWrapAlignment())
       {
         while (seqCanvas.cursorX < av.getColumnSelection()
-                .adjustForHiddenColumns(av.startRes))
+                .adjustForHiddenColumns(av.getRanges().getStartRes()))
         {
           if (!ap.scrollRight(false))
           {
@@ -404,7 +406,7 @@ public class SeqPanel extends JPanel implements MouseListener,
           }
         }
         while (seqCanvas.cursorX > av.getColumnSelection()
-                .adjustForHiddenColumns(av.endRes))
+                .adjustForHiddenColumns(av.getRanges().getEndRes()))
         {
           if (!ap.scrollRight(true))
           {
@@ -1772,9 +1774,9 @@ public class SeqPanel extends JPanel implements MouseListener,
       changeStartRes = true;
     }
 
-    if (res < av.getStartRes())
+    if (res < av.getRanges().getStartRes())
     {
-      res = av.getStartRes();
+      res = av.getRanges().getStartRes();
     }
 
     if (changeEndRes)
@@ -1908,13 +1910,15 @@ public class SeqPanel extends JPanel implements MouseListener,
       {
         if (evt != null)
         {
-          if (mouseDragging && (evt.getY() < 0) && (av.getStartSeq() > 0))
+          if (mouseDragging && (evt.getY() < 0)
+                  && (av.getRanges().getStartSeq() > 0))
           {
             running = ap.scrollUp(true);
           }
 
           if (mouseDragging && (evt.getY() >= getHeight())
-                  && (av.getAlignment().getHeight() > av.getEndSeq()))
+                  && (av.getAlignment().getHeight() > av.getRanges()
+                          .getEndSeq()))
           {
             running = ap.scrollUp(false);
           }
index 6f84a2e..3a27c7d 100644 (file)
@@ -307,7 +307,7 @@ public class AnnotationRenderer
   public void updateFromAlignViewport(AlignViewportI av)
   {
     charWidth = av.getCharWidth();
-    endRes = av.getEndRes();
+    endRes = av.getRanges().getEndRes();
     charHeight = av.getCharHeight();
     hasHiddenColumns = av.hasHiddenColumns();
     validCharWidth = av.isValidCharWidth();
index 94d0dd1..3547757 100644 (file)
@@ -78,6 +78,8 @@ import jalview.workers.StrucConsensusThread;
 public abstract class AlignmentViewport implements AlignViewportI,
         CommandListener, VamsasSource
 {
+  protected ViewportRanges ranges;
+
   protected ViewStyleI viewStyle = new ViewStyle();
 
   /**
@@ -1293,15 +1295,6 @@ public abstract class AlignmentViewport implements AlignViewportI,
    */
   private boolean followHighlight = true;
 
-  // TODO private with getters and setters?
-  public int startRes;
-
-  public int endRes;
-
-  public int startSeq;
-
-  public int endSeq;
-
   /**
    * Property change listener for changes in alignment
    * 
@@ -2672,63 +2665,10 @@ public abstract class AlignmentViewport implements AlignViewportI,
     this.followHighlight = b;
   }
 
-  public int getStartRes()
-  {
-    return startRes;
-  }
-
   @Override
-  public int getEndRes()
-  {
-    return endRes;
-  }
-
-  public int getStartSeq()
-  {
-    return startSeq;
-  }
-
-  public void setStartRes(int res)
-  {
-    this.startRes = res;
-  }
-
-  public void setStartSeq(int seq)
-  {
-    this.startSeq = seq;
-  }
-
-  public void setEndRes(int res)
-  {
-    if (res > alignment.getWidth() - 1)
-    {
-      // log.System.out.println(" Corrected res from " + res + " to maximum " +
-      // (alignment.getWidth()-1));
-      res = alignment.getWidth() - 1;
-    }
-    if (res < 0)
-    {
-      res = 0;
-    }
-    this.endRes = res;
-  }
-
-  public void setEndSeq(int seq)
-  {
-    if (seq > alignment.getHeight())
-    {
-      seq = alignment.getHeight();
-    }
-    if (seq < 0)
-    {
-      seq = 0;
-    }
-    this.endSeq = seq;
-  }
-
-  public int getEndSeq()
+  public ViewportRanges getRanges()
   {
-    return endSeq;
+    return ranges;
   }
 
   /**
@@ -2768,7 +2708,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
      * locate 'middle' column (true middle if an odd number visible, left of
      * middle if an even number visible)
      */
-    int middleColumn = getStartRes() + (getEndRes() - getStartRes()) / 2;
+    int middleColumn = ranges.getStartRes()
+            + (ranges.getEndRes() - ranges.getStartRes()) / 2;
     final HiddenSequences hiddenSequences = getAlignment()
             .getHiddenSequences();
 
@@ -2778,7 +2719,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
      */
     int lastSeq = alignment.getHeight() - 1;
     List<AlignedCodonFrame> seqMappings = null;
-    for (int seqNo = getStartSeq(); seqNo < lastSeq; seqNo++, seqOffset++)
+    for (int seqNo = ranges.getStartSeq(); seqNo < lastSeq; seqNo++, seqOffset++)
     {
       sequence = getAlignment().getSequenceAt(seqNo);
       if (hiddenSequences != null && hiddenSequences.isHidden(sequence))
diff --git a/src/jalview/viewmodel/OverviewDimensions.java b/src/jalview/viewmodel/OverviewDimensions.java
new file mode 100644 (file)
index 0000000..43680b5
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.viewmodel;
+
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenSequences;
+
+import java.awt.Graphics;
+
+public class OverviewDimensions
+{
+  // Default width and height values
+  private static final int DEFAULT_GRAPH_HEIGHT = 20;
+
+  private static final int MAX_WIDTH = 400;
+
+  private static final int MIN_WIDTH = 120;
+
+  private static final int MIN_SEQ_HEIGHT = 40;
+
+  private static final int MAX_SEQ_HEIGHT = 300;
+
+  // width of the overview panel
+  private int width;
+
+  // height of sequences part of the overview panel
+  private int sequencesHeight;
+
+  // height of the graphs part of the overview panel
+  private int graphHeight = DEFAULT_GRAPH_HEIGHT;
+
+  // dimensions of box outlining current extent of view in alignment panel
+  // location of left side of box
+  private int boxX = -1;
+
+  // location of bottom of box
+  private int boxY = -1;
+
+  // width of box
+  private int boxWidth = -1;
+
+  // height of box
+  private int boxHeight = -1;
+
+  // scroll position in viewport corresponding to boxX
+  private int scrollCol = -1;
+
+  // scroll position in viewport corresponding to boxY
+  private int scrollRow = -1;
+
+  /**
+   * 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)
+  {
+    // scale the initial size of overviewpanel to shape of alignment
+    float initialScale = (float) ranges.getAbsoluteAlignmentWidth()
+            / (float) ranges.getAbsoluteAlignmentHeight();
+
+    if (!showAnnotationPanel)
+    {
+      graphHeight = 0;
+    }
+
+    if (ranges.getAbsoluteAlignmentWidth() > ranges
+            .getAbsoluteAlignmentHeight())
+    {
+      // wider
+      width = MAX_WIDTH;
+      sequencesHeight = Math.round(MAX_WIDTH / initialScale);
+      if (sequencesHeight < MIN_SEQ_HEIGHT)
+      {
+        sequencesHeight = MIN_SEQ_HEIGHT;
+      }
+    }
+    else
+    {
+      // taller
+      width = Math.round(MAX_WIDTH * initialScale);
+      sequencesHeight = MAX_SEQ_HEIGHT;
+
+      if (width < MIN_WIDTH)
+      {
+        width = MIN_WIDTH;
+      }
+    }
+  }
+
+  /**
+   * Check box dimensions and scroll positions and correct if necessary
+   * 
+   * @param mousex
+   *          x position in overview panel
+   * @param mousey
+   *          y position in overview panel
+   * @param hiddenSeqs
+   *          hidden sequences
+   * @param hiddenCols
+   *          hidden columns
+   * @param ranges
+   *          viewport position properties
+   */
+  public void updateViewportFromMouse(int mousex, int mousey,
+          HiddenSequences hiddenSeqs, ColumnSelection hiddenCols,
+          ViewportRanges ranges)
+  {
+    int x = mousex;
+    int y = mousey;
+
+    int alwidth = ranges.getAbsoluteAlignmentWidth();
+    int alheight = ranges.getAbsoluteAlignmentHeight();
+
+    if (x < 0)
+    {
+      x = 0;
+    }
+
+    if (y < 0)
+    {
+      y = 0;
+    }
+
+    //
+    // Convert x value to residue position
+    //
+
+    // need to determine where scrollCol should be, given x
+    // to do this also need to know width of viewport, and some hidden column
+    // correction
+
+    // convert x to residues - this is an absolute position
+    int xAsRes = Math.round((float) x * alwidth / width);
+
+    // get viewport width in residues
+    int vpwidth = ranges.getEndRes() - ranges.getStartRes() + 1;
+
+    // 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
+    // absolute position
+    // so convert back after getting visible region position
+    int visXAsRes = hiddenCols.findColumnPosition(xAsRes);
+
+    // check in case we went off the edge of the alignment
+    int visAlignWidth = hiddenCols.findColumnPosition(alwidth - 1);
+    if (visXAsRes + vpwidth - 1 > visAlignWidth)
+    {
+      // 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)
+      {
+        visXAsRes = hiddenCols.findColumnPosition(hiddenCols
+                .subtractVisibleColumns(vpwidth - 1, alwidth - 1));
+      }
+      else
+      {
+        visXAsRes = scrollCol;
+      }
+    }
+
+    //
+    // Convert y value to sequence position
+    //
+
+    // convert y to residues
+    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;
+
+    // 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
+    // position,
+    // so convert back after getting visible region position
+    yAsSeq = hiddenSeqs.adjustForHiddenSeqs(hiddenSeqs
+            .findIndexWithoutHiddenSeqs(yAsSeq));
+
+    // check in case we went off the edge of the alignment
+    int visAlignHeight = hiddenSeqs.findIndexWithoutHiddenSeqs(alheight);
+    int visYAsRes = hiddenSeqs.findIndexWithoutHiddenSeqs(yAsSeq);
+    if (visYAsRes + vpheight - 1 > visAlignHeight)
+    {
+      // went past the end of the alignment, adjust backwards
+      if ((scrollRow + vpheight - 1) < visAlignHeight)
+      {
+        visYAsRes = hiddenSeqs.findIndexWithoutHiddenSeqs(hiddenSeqs
+                .subtractVisibleRows(vpheight - 1, alheight - 1));
+      }
+      else
+      {
+        visYAsRes = scrollRow;
+      }
+    }
+
+    // update scroll values
+    scrollCol = visXAsRes;
+    scrollRow = visYAsRes;
+
+  }
+
+  /**
+   * Update the overview panel box when the associated alignment panel is
+   * changed
+   * 
+   * @param hiddenSeqs
+   *          hidden sequences
+   * @param hiddenCols
+   *          hidden columns
+   * @param ranges
+   *          viewport position properties
+   */
+  public void setBoxPosition(HiddenSequences hiddenSeqs,
+          ColumnSelection hiddenCols, ViewportRanges ranges)
+  {
+    int alwidth = ranges.getAbsoluteAlignmentWidth();
+    int alheight = ranges.getAbsoluteAlignmentHeight();
+
+    // work with absolute values of startRes and endRes
+    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());
+
+    // boxX, boxY is the x,y location equivalent to startRes, startSeq
+    boxX = Math.round((float) startRes * width / alwidth);
+    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);
+    // boxHeight is the height in sequences translated to pixels
+    boxHeight = Math.round((float) (endSeq - startSeq + 1)
+            * sequencesHeight
+            / alheight);
+  }
+
+  /**
+   * Draw the overview panel's viewport box on a graphics object
+   * 
+   * @param g
+   *          the graphics object to draw on
+   */
+  public void drawBox(Graphics g)
+  {
+    g.drawRect(boxX, boxY, boxWidth, boxHeight);
+    g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);
+  }
+
+  public int getScrollCol()
+  {
+    return scrollCol;
+  }
+
+  public int getScrollRow()
+  {
+    return scrollRow;
+  }
+
+  // TODO should be removed, when unit test has mock Graphics object available
+  // to check boxX/boxY
+  public int getBoxX()
+  {
+    return boxX;
+  }
+
+  // TODO should be removed, when unit test has mock Graphics object available
+  // to check boxX/boxY
+  public int getBoxY()
+  {
+    return boxY;
+  }
+
+  // TODO should be removed, when unit test has mock Graphics object available
+  public int getBoxWidth()
+  {
+    return boxWidth;
+  }
+
+  // TODO should be removed, when unit test has mock Graphics object available
+  public int getBoxHeight()
+  {
+    return boxHeight;
+  }
+
+  public void setWidth(int w)
+  {
+    width = w;
+  }
+
+  public void setHeight(int h)
+  {
+    sequencesHeight = h - graphHeight;
+  }
+
+  public int getWidth()
+  {
+    return width;
+  }
+
+  public int getHeight()
+  {
+    return sequencesHeight + graphHeight;
+  }
+
+  public int getSequencesHeight()
+  {
+    return sequencesHeight;
+  }
+
+  public int getGraphHeight()
+  {
+    return graphHeight;
+  }
+}
diff --git a/src/jalview/viewmodel/ViewportProperties.java b/src/jalview/viewmodel/ViewportProperties.java
new file mode 100644 (file)
index 0000000..246806e
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.viewmodel;
+
+public abstract class ViewportProperties
+{
+
+}
diff --git a/src/jalview/viewmodel/ViewportRanges.java b/src/jalview/viewmodel/ViewportRanges.java
new file mode 100644 (file)
index 0000000..c91d2d9
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.viewmodel;
+
+import jalview.datamodel.AlignmentI;
+
+/**
+ * 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
+{
+  // start residue of viewport
+  private int startRes;
+
+  // end residue of viewport
+  private int endRes;
+
+  // start sequence of viewport
+  private int startSeq;
+
+  // end sequence of viewport
+  private int endSeq;
+
+  // alignment
+  private AlignmentI al;
+
+  /**
+   * Constructor
+   * 
+   * @param alignment
+   *          the viewport's alignment
+   */
+  public ViewportRanges(AlignmentI alignment)
+  {
+    // initial values of viewport settings
+    this.startRes = 0;
+    this.endRes = alignment.getWidth() - 1;
+    this.startSeq = 0;
+    this.endSeq = alignment.getHeight() - 1;
+    this.al = alignment;
+  }
+
+  /**
+   * Get alignment width in cols, including hidden cols
+   */
+  public int getAbsoluteAlignmentWidth()
+  {
+    return al.getWidth();
+  }
+
+  /**
+   * Get alignment height in rows, including hidden rows
+   */
+  public int getAbsoluteAlignmentHeight()
+  {
+    return al.getHeight() + al.getHiddenSequences().getSize();
+  }
+
+  /**
+   * Set first residue visible in the viewport
+   * 
+   * @param res
+   *          residue position
+   */
+  public void setStartRes(int res)
+  {
+    if (res > al.getWidth() - 1)
+    {
+      res = al.getWidth() - 1;
+    }
+    else if (res < 0)
+    {
+      res = 0;
+    }
+    this.startRes = res;
+  }
+
+  /**
+   * Set last residue visible in the viewport
+   * 
+   * @param res
+   *          residue position
+   */
+  public void setEndRes(int res)
+  {
+    if (res >= al.getWidth())
+    {
+      res = al.getWidth() - 1;
+    }
+    else if (res < 0)
+    {
+      res = 0;
+    }
+    this.endRes = res;
+  }
+
+  /**
+   * Set the first sequence visible in the viewport
+   * 
+   * @param seq
+   *          sequence position
+   */
+  public void setStartSeq(int seq)
+  {
+    if (seq > al.getHeight() - 1)
+    {
+      seq = al.getHeight() - 1;
+    }
+    else if (seq < 0)
+    {
+      seq = 0;
+    }
+    this.startSeq = seq;
+  }
+
+  /**
+   * Set the last sequence visible in the viewport
+   * 
+   * @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;
+  }
+
+  /**
+   * Get start residue of viewport
+   */
+  public int getStartRes()
+  {
+    return startRes;
+  }
+
+  /**
+   * Get end residue of viewport
+   */
+  public int getEndRes()
+  {
+    return endRes;
+  }
+
+  /**
+   * Get start sequence of viewport
+   */
+  public int getStartSeq()
+  {
+    return startSeq;
+  }
+
+  /**
+   * Get end sequence of viewport
+   */
+  public int getEndSeq()
+  {
+    return endSeq;
+  }
+}
index 676a4b6..4d3dd2f 100644 (file)
@@ -617,8 +617,8 @@ public class DasSequenceFeatureFetcher
     }
     af.getFeatureRenderer().featuresAdded();
 
-    int start = af.getViewport().getStartSeq();
-    int end = af.getViewport().getEndSeq();
+    int start = af.getViewport().getRanges().getStartSeq();
+    int end = af.getViewport().getRanges().getEndSeq();
     int index;
     for (index = start; index < end; index++)
     {
index 7af77f5..68933bd 100644 (file)
@@ -27,6 +27,7 @@ import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.analysis.AlignmentGenerator;
 import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
 import jalview.gui.JvOptionPane;
 import jalview.io.DataSourceType;
@@ -1196,4 +1197,67 @@ public class AlignmentTest
     assertNull(a.findGroup(seq2, 8));
   }
 
+  @Test(groups = { "Functional" })
+  public void testDeleteSequenceByIndex()
+  {
+    // create random alignment
+    AlignmentGenerator gen = new AlignmentGenerator(false);
+    AlignmentI a = gen.generate(20, 15, 123, 5, 5);
+
+    // delete sequence 10, alignment reduced by 1
+    int height = a.getAbsoluteHeight();
+    a.deleteSequence(10);
+    assertEquals(a.getAbsoluteHeight(), height - 1);
+
+    // try to delete -ve index, nothing happens
+    a.deleteSequence(-1);
+    assertEquals(a.getAbsoluteHeight(), height - 1);
+
+    // try to delete beyond end of alignment, nothing happens
+    a.deleteSequence(14);
+    assertEquals(a.getAbsoluteHeight(), height - 1);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testDeleteSequenceBySeq()
+  {
+    // create random alignment
+    AlignmentGenerator gen = new AlignmentGenerator(false);
+    AlignmentI a = gen.generate(20, 15, 123, 5, 5);
+
+    // delete sequence 10, alignment reduced by 1
+    int height = a.getAbsoluteHeight();
+    SequenceI seq = a.getSequenceAt(10);
+    a.deleteSequence(seq);
+    assertEquals(a.getAbsoluteHeight(), height - 1);
+
+    // try to delete non-existent sequence, nothing happens
+    seq = new Sequence("cds", "GCCTCGGAT");
+    assertEquals(a.getAbsoluteHeight(), height - 1);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testDeleteHiddenSequence()
+  {
+    // create random alignment
+    AlignmentGenerator gen = new AlignmentGenerator(false);
+    AlignmentI a = gen.generate(20, 15, 123, 5, 5);
+
+    // delete a sequence which is hidden, check it is NOT removed from hidden
+    // sequences
+    int height = a.getAbsoluteHeight();
+    SequenceI seq = a.getSequenceAt(2);
+    a.getHiddenSequences().hideSequence(seq);
+    assertEquals(a.getHiddenSequences().getSize(), 1);
+    a.deleteSequence(2);
+    assertEquals(a.getAbsoluteHeight(), height - 1);
+    assertEquals(a.getHiddenSequences().getSize(), 1);
+
+    // delete a sequence which is not hidden, check hiddenSequences are not
+    // affected
+    a.deleteSequence(10);
+    assertEquals(a.getAbsoluteHeight(), height - 2);
+    assertEquals(a.getHiddenSequences().getSize(), 1);
+  }
+
 }
index 1d819c9..4d3f611 100644 (file)
@@ -105,9 +105,97 @@ public class ColumnSelectionTest
     cs.hideColumns(4, 4);
     assertEquals(4, cs.findColumnPosition(5));
 
+    // hiding column 4 moves column 4 to position 3
+    assertEquals(3, cs.findColumnPosition(4));
+
     // hiding columns 1 and 2 moves column 5 to column 2
     cs.hideColumns(1, 2);
     assertEquals(2, cs.findColumnPosition(5));
+
+    // check with > 1 hidden column regions
+    // where some columns are in the hidden regions
+    ColumnSelection cs2 = new ColumnSelection();
+    cs2.hideColumns(5, 10);
+    cs2.hideColumns(20, 27);
+    cs2.hideColumns(40, 44);
+
+    // hiding columns 5-10 and 20-27 moves column 8 to column 4
+    assertEquals(4, cs2.findColumnPosition(8));
+
+    // and moves column 24 to 13
+    assertEquals(13, cs2.findColumnPosition(24));
+
+    // and moves column 28 to 14
+    assertEquals(14, cs2.findColumnPosition(28));
+
+    // and moves column 40 to 25
+    assertEquals(25, cs2.findColumnPosition(40));
+
+    // check when hidden columns start at 0 that the visible column
+    // is returned as 0
+    ColumnSelection cs3 = new ColumnSelection();
+    cs3.hideColumns(0, 4);
+    assertEquals(0, cs3.findColumnPosition(2));
+
+  }
+
+  /**
+   * Test the method that finds the visible column position a given distance
+   * before another column
+   */
+  @Test(groups = { "Functional" })
+  public void testFindColumnNToLeft()
+  {
+    ColumnSelection cs = new ColumnSelection();
+
+    // test that without hidden columns, findColumnNToLeft returns
+    // position n to left of provided position
+    int pos = cs.subtractVisibleColumns(3, 10);
+    assertEquals(7, pos);
+
+    // 0 returns same position
+    pos = cs.subtractVisibleColumns(0, 10);
+    assertEquals(10, pos);
+
+    // overflow to left returns negative number
+    pos = cs.subtractVisibleColumns(3, 0);
+    assertEquals(-3, pos);
+
+    // test that with hidden columns to left of result column
+    // behaviour is the same as above
+    cs.hideColumns(1, 3);
+
+    // position n to left of provided position
+    pos = cs.subtractVisibleColumns(3, 10);
+    assertEquals(7, pos);
+
+    // 0 returns same position
+    pos = cs.subtractVisibleColumns(0, 10);
+    assertEquals(10, pos);
+
+    // test with one set of hidden columns between start and required position
+    cs.hideColumns(12, 15);
+    pos = cs.subtractVisibleColumns(8, 17);
+    assertEquals(5, pos);
+
+    // test with two sets of hidden columns between start and required position
+    cs.hideColumns(20, 21);
+    pos = cs.subtractVisibleColumns(8, 23);
+    assertEquals(9, pos);
+
+    // repeat last 2 tests with no hidden columns to left of required position
+    cs.revealAllHiddenColumns();
+
+    // test with one set of hidden columns between start and required position
+    cs.hideColumns(12, 15);
+    pos = cs.subtractVisibleColumns(8, 17);
+    assertEquals(5, pos);
+
+    // test with two sets of hidden columns between start and required position
+    cs.hideColumns(20, 21);
+    pos = cs.subtractVisibleColumns(8, 23);
+    assertEquals(9, pos);
+
   }
 
   /**
index cae3536..7795988 100644 (file)
@@ -49,7 +49,7 @@ public class HiddenSequencesTest
     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
   }
 
-  static int SEQ_COUNT = 10;
+  static int SEQ_COUNT = 25;
 
   SequenceI[] seqs;
 
@@ -62,8 +62,9 @@ public class HiddenSequencesTest
     seqs = new SequenceI[SEQ_COUNT];
     for (int i = 0; i < SEQ_COUNT; i++)
     {
-      // sequence lengths are 1, 2, ... 10
-      seqs[i] = new Sequence("Seq" + i, "abcdefghijk".substring(0, i + 1));
+      // sequence lengths are 1, 2, ... 25
+      seqs[i] = new Sequence("Seq" + i,
+              "abcdefghijklmnopqrstuvwxy".substring(0, i + 1));
     }
   }
 
@@ -89,7 +90,7 @@ public class HiddenSequencesTest
     /*
      * alignment is now seq0/2/3/4/7/8/9
      */
-    assertEquals(7, al.getHeight());
+    assertEquals(SEQ_COUNT - 3, al.getHeight());
     assertEquals(0, hs.adjustForHiddenSeqs(0));
     assertEquals(2, hs.adjustForHiddenSeqs(1));
     assertEquals(3, hs.adjustForHiddenSeqs(2));
@@ -193,7 +194,7 @@ public class HiddenSequencesTest
     /*
      * alignment is now seq0/2/3/4/7/8/9
      */
-    assertEquals(7, al.getHeight());
+    assertEquals(SEQ_COUNT - 3, al.getHeight());
     assertEquals(0, hs.findIndexWithoutHiddenSeqs(0));
     assertEquals(0, hs.findIndexWithoutHiddenSeqs(1));
     assertEquals(1, hs.findIndexWithoutHiddenSeqs(2));
@@ -207,6 +208,76 @@ public class HiddenSequencesTest
   }
 
   /**
+   * Test the method that finds the visible row position a given distance before
+   * another row
+   */
+  @Test(groups = { "Functional" })
+  public void testFindIndexNFromRow()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = new HiddenSequences(al);
+
+    // test that without hidden rows, findIndexNFromRow returns
+    // position n above provided position
+    int pos = hs.subtractVisibleRows(3, 10);
+    assertEquals(7, pos);
+
+    // 0 returns same position
+    pos = hs.subtractVisibleRows(0, 10);
+    assertEquals(10, pos);
+
+    // overflow to top returns negative number
+    pos = hs.subtractVisibleRows(3, 0);
+    assertEquals(-3, pos);
+
+    // test that with hidden rows above result row
+    // behaviour is the same as above
+    hs.hideSequence(seqs[1]);
+    hs.hideSequence(seqs[2]);
+    hs.hideSequence(seqs[3]);
+
+    // position n above provided position
+    pos = hs.subtractVisibleRows(3, 10);
+    assertEquals(7, pos);
+
+    // 0 returns same position
+    pos = hs.subtractVisibleRows(0, 10);
+    assertEquals(10, pos);
+
+    // test with one set of hidden rows between start and required position
+    hs.hideSequence(seqs[12]);
+    hs.hideSequence(seqs[13]);
+    hs.hideSequence(seqs[14]);
+    hs.hideSequence(seqs[15]);
+    pos = hs.subtractVisibleRows(8, 17);
+    assertEquals(5, pos);
+
+    // test with two sets of hidden rows between start and required position
+    hs.hideSequence(seqs[20]);
+    hs.hideSequence(seqs[21]);
+    pos = hs.subtractVisibleRows(8, 23);
+    assertEquals(9, pos);
+
+    // repeat last 2 tests with no hidden columns to left of required position
+    hs.showAll(null);
+
+    // test with one set of hidden rows between start and required position
+    hs.hideSequence(seqs[12]);
+    hs.hideSequence(seqs[13]);
+    hs.hideSequence(seqs[14]);
+    hs.hideSequence(seqs[15]);
+    pos = hs.subtractVisibleRows(8, 17);
+    assertEquals(5, pos);
+
+    // test with two sets of hidden rows between start and required position
+    hs.hideSequence(seqs[20]);
+    hs.hideSequence(seqs[21]);
+    pos = hs.subtractVisibleRows(8, 23);
+    assertEquals(9, pos);
+
+  }
+
+  /**
    * Test the method that reconstructs (sort of) the full alignment including
    * hidden sequences
    */
@@ -289,7 +360,7 @@ public class HiddenSequencesTest
     assertTrue(al.getSequences().contains(seqs[1]));
     HiddenSequences hs = al.getHiddenSequences();
     assertEquals(0, hs.getSize());
-    assertEquals(10, al.getHeight());
+    assertEquals(SEQ_COUNT, al.getHeight());
 
     /*
      * hide the second sequence in the alignment
@@ -299,7 +370,7 @@ public class HiddenSequencesTest
     assertTrue(hs.isHidden(seqs[1]));
     assertFalse(al.getSequences().contains(seqs[1]));
     assertEquals(1, hs.getSize());
-    assertEquals(9, al.getHeight());
+    assertEquals(SEQ_COUNT - 1, al.getHeight());
     assertSame(seqs[2], al.getSequenceAt(1));
 
     /*
@@ -312,7 +383,7 @@ public class HiddenSequencesTest
     assertFalse(al.getSequences().contains(seqs[1]));
     assertFalse(al.getSequences().contains(seqs[2]));
     assertEquals(2, hs.getSize());
-    assertEquals(8, al.getHeight());
+    assertEquals(SEQ_COUNT - 2, al.getHeight());
 
     /*
      * perform 'reveal' on what is now the second sequence in the alignment
@@ -323,7 +394,54 @@ public class HiddenSequencesTest
     assertTrue(revealed.contains(seqs[1]));
     assertTrue(revealed.contains(seqs[2]));
     assertEquals(0, hs.getSize());
-    assertEquals(10, al.getHeight());
+    assertEquals(SEQ_COUNT, al.getHeight());
+  }
+
+  /**
+   * Test the method that adds a sequence to the hidden sequences and deletes it
+   * from the alignment, and its converse, where the first hidden sequences are
+   * at the bottom of the alignment (JAL-2437)
+   */
+  @Test(groups = "Functional")
+  public void testHideShowLastSequences()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertTrue(al.getSequences().contains(seqs[1]));
+    HiddenSequences hs = al.getHiddenSequences();
+    assertEquals(0, hs.getSize());
+    assertEquals(SEQ_COUNT, al.getHeight());
+
+    /*
+     * hide the last sequence in the alignment
+     */
+    hs.hideSequence(seqs[SEQ_COUNT - 1]);
+    assertFalse(hs.isHidden(seqs[SEQ_COUNT - 2]));
+    assertTrue(hs.isHidden(seqs[SEQ_COUNT - 1]));
+    assertFalse(al.getSequences().contains(seqs[SEQ_COUNT - 1]));
+    assertEquals(1, hs.getSize());
+    assertEquals(SEQ_COUNT - 1, al.getHeight());
+
+    /*
+     * hide the third last sequence in the alignment
+     */
+    hs.hideSequence(seqs[SEQ_COUNT - 3]);
+    assertFalse(hs.isHidden(seqs[SEQ_COUNT - 2]));
+    assertTrue(hs.isHidden(seqs[SEQ_COUNT - 3]));
+    assertFalse(al.getSequences().contains(seqs[SEQ_COUNT - 3]));
+    assertEquals(2, hs.getSize());
+    assertEquals(SEQ_COUNT - 2, al.getHeight());
+
+    /*
+     * reveal all the sequences, which should be reinstated in the same order as they started in
+     */
+    hs.showAll(null);
+    assertFalse(hs.isHidden(seqs[SEQ_COUNT - 3]));
+    assertFalse(hs.isHidden(seqs[SEQ_COUNT - 1]));
+    assertEquals(seqs[SEQ_COUNT - 3], al.getSequences().get(SEQ_COUNT - 3));
+    assertEquals(seqs[SEQ_COUNT - 2], al.getSequences().get(SEQ_COUNT - 2));
+    assertEquals(seqs[SEQ_COUNT - 1], al.getSequences().get(SEQ_COUNT - 1));
+    assertEquals(0, hs.getSize());
+    assertEquals(SEQ_COUNT, al.getHeight());
   }
 
   @Test(groups = "Functional")
diff --git a/test/jalview/gui/AlignmentPanelTest.java b/test/jalview/gui/AlignmentPanelTest.java
new file mode 100644 (file)
index 0000000..c580a88
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.gui;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.bin.Cache;
+import jalview.bin.Jalview;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+import jalview.viewmodel.ViewportRanges;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class AlignmentPanelTest
+{
+  SequenceI seq1 = new Sequence(
+          "Seq1",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq2 = new Sequence(
+          "Seq2",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq3 = new Sequence(
+          "Seq3",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq4 = new Sequence(
+          "Seq4",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq5 = new Sequence(
+          "Seq5",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq6 = new Sequence(
+          "Seq6",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq7 = new Sequence(
+          "Seq7",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq8 = new Sequence(
+          "Seq8",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq9 = new Sequence(
+          "Seq9",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq10 = new Sequence(
+          "Seq10",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq11 = new Sequence(
+          "Seq11",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq12 = new Sequence(
+          "Seq12",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq13 = new Sequence(
+          "Seq13",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq14 = new Sequence(
+          "Seq14",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq15 = new Sequence(
+          "Seq15",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq16 = new Sequence(
+          "Seq16",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq17 = new Sequence(
+          "Seq17",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq18 = new Sequence(
+          "Seq18",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq19 = new Sequence(
+          "Seq19",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq20 = new Sequence(
+          "Seq20",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq21 = new Sequence(
+          "Seq21",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq22 = new Sequence(
+          "Seq22",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  SequenceI seq23 = new Sequence(
+          "Seq23",
+          "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+  AlignFrame af;
+
+  @BeforeMethod(alwaysRun = true)
+  public void setUp()
+  {
+    Jalview.main(new String[] { "-nonews", "-props",
+        "test/jalview/testProps.jvprops" });
+
+    Cache.applicationProperties.setProperty("SHOW_IDENTITY",
+            Boolean.TRUE.toString());
+    af = new FileLoader().LoadFileWaitTillLoaded("examples/uniref50.fa",
+            DataSourceType.FILE);
+
+    /*
+     * wait for Consensus thread to complete
+     */
+    synchronized (this)
+    {
+      while (af.getViewport().getConsensusSeq() == null)
+      {
+        try
+        {
+          wait(50);
+        } catch (InterruptedException e)
+        {
+        }
+      }
+    }
+  }
+
+
+  /**
+   * Test side effect that end residue is set correctly by setScrollValues, with
+   * or without hidden columns
+   */
+  @Test(groups = "Functional")
+  public void TestSetScrollValues()
+  {
+    ViewportRanges ranges = af.getViewport().getRanges();
+
+    int oldres = ranges.getEndRes();
+    af.alignPanel.setScrollValues(-1, 5);
+
+    // setting -ve x value does not change residue
+    assertEquals(ranges.getEndRes(), oldres);
+
+    af.alignPanel.setScrollValues(0, 5);
+
+    // setting 0 as x value does not change residue
+    assertEquals(ranges.getEndRes(), oldres);
+
+    af.alignPanel.setScrollValues(5, 5);
+    // setting x value to 5 extends endRes by 5 residues
+    assertEquals(ranges.getEndRes(), oldres + 5);
+
+    // scroll to position after hidden columns sets endres to oldres (width) +
+    // position
+    int scrollpos = 60;
+    af.getViewport().hideColumns(30, 50);
+    af.alignPanel.setScrollValues(scrollpos, 5);
+    assertEquals(ranges.getEndRes(), oldres + scrollpos);
+
+    // scroll to position within hidden columns, still sets endres to oldres +
+    // position
+    // not sure if this is actually correct behaviour but this is what Jalview
+    // currently does
+    scrollpos = 40;
+    af.getViewport().showAllHiddenColumns();
+    af.getViewport().hideColumns(30, 50);
+    af.alignPanel.setScrollValues(scrollpos, 5);
+    assertEquals(ranges.getEndRes(), oldres + scrollpos);
+
+    // scroll to position within <width> distance of the end of the alignment
+    // endRes should be set to width of alignment - 1
+    scrollpos = 130;
+    af.getViewport().showAllHiddenColumns();
+    af.alignPanel.setScrollValues(scrollpos, 5);
+    assertEquals(ranges.getEndRes(), af.getViewport()
+            .getAlignment().getWidth() - 1);
+
+    // now hide some columns, and scroll to position within <width>
+    // distance of the end of the alignment
+    // endRes should be set to width of alignment - 1 - the number of hidden
+    // columns
+    af.getViewport().hideColumns(30, 50);
+    af.alignPanel.setScrollValues(scrollpos, 5);
+    assertEquals(ranges.getEndRes(), af.getViewport()
+            .getAlignment().getWidth() - 1 - 21); // 21 is the number of hidden
+                                                  // columns
+  }
+}
diff --git a/test/jalview/viewmodel/OverviewDimensionsTest.java b/test/jalview/viewmodel/OverviewDimensionsTest.java
new file mode 100644 (file)
index 0000000..398fec3
--- /dev/null
@@ -0,0 +1,1037 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.viewmodel;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.analysis.AlignmentGenerator;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceCollectionI;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+
+import java.util.Hashtable;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+@Test(singleThreaded = true)
+public class OverviewDimensionsTest
+{
+  AlignmentI al;
+  OverviewDimensions od;
+
+  // cached widths and heights
+  int boxWidth;
+  int boxHeight;
+  int viewHeight;
+  int viewWidth;
+  int alheight;
+  int alwidth;
+
+  ViewportRanges vpranges;
+
+  Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences = new Hashtable<SequenceI, SequenceCollectionI>();
+
+  ColumnSelection hiddenCols = new ColumnSelection();
+
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    // create random alignment
+    AlignmentGenerator gen = new AlignmentGenerator(false);
+    al = gen.generate(157, 525, 123, 5, 5);
+  }
+
+  @BeforeMethod(alwaysRun = true)
+  public void setUp()
+  {
+    if (!hiddenRepSequences.isEmpty())
+    {
+      al.getHiddenSequences().showAll(hiddenRepSequences);
+    }
+    hiddenCols.revealAllHiddenColumns();
+    
+    vpranges = new ViewportRanges(al);
+    vpranges.setStartRes(0);
+    vpranges.setEndRes(62);
+    vpranges.setStartSeq(0);
+    vpranges.setEndSeq(17);
+
+    viewHeight = vpranges.getEndSeq() - vpranges.getStartSeq() + 1;
+    viewWidth = vpranges.getEndRes() - vpranges.getStartRes() + 1;
+
+    ColumnSelection hiddenCols = new ColumnSelection();
+
+    od = new OverviewDimensions(vpranges, true);
+    // Initial box sizing - default path through code
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+
+    mouseClick(od, 0, 0);
+    moveViewport(0, 0);
+
+    // calculate before hidden columns so we get absolute values
+    alheight = vpranges.getAbsoluteAlignmentHeight();
+    alwidth = vpranges.getAbsoluteAlignmentWidth();
+
+    boxWidth = Math.round((float) (vpranges.getEndRes()
+            - vpranges.getStartRes() + 1)
+            * od.getWidth() / alwidth);
+    boxHeight = Math.round((float) (vpranges.getEndSeq()
+            - vpranges.getStartSeq() + 1)
+            * od.getSequencesHeight() / alheight);
+  }
+
+  @AfterClass(alwaysRun = true)
+  public void cleanUp()
+  {
+    al = null;
+  }
+
+  /**
+   * Test that the OverviewDimensions constructor sets width and height
+   * correctly
+   */
+  @Test(groups = { "Functional" })
+  public void testConstructor()
+  {
+    SequenceI seqa = new Sequence("Seq1", "ABC");
+    SequenceI seqb = new Sequence("Seq2", "ABC");
+    SequenceI seqc = new Sequence("Seq3", "ABC");
+    SequenceI seqd = new Sequence("Seq4", "ABC");
+    SequenceI seqe = new Sequence("Seq5",
+            "ABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+    int defaultGraphHeight = 20;
+    int maxWidth = 400;
+    int minWidth = 120;
+    int maxSeqHeight = 300;
+    int minSeqHeight = 40;
+
+    // test for alignment with width > height
+    SequenceI[] seqs1 = new SequenceI[] { seqa, seqb };
+    Alignment al1 = new Alignment(seqs1);
+    ViewportRanges props = new ViewportRanges(al1);
+
+    OverviewDimensions od = new OverviewDimensions(props, true);
+    int scaledHeight = 267;
+    assertEquals(od.getGraphHeight(), defaultGraphHeight);
+    assertEquals(od.getSequencesHeight(), scaledHeight);
+    assertEquals(od.getWidth(), maxWidth);
+    assertEquals(od.getHeight(), scaledHeight + defaultGraphHeight);
+
+    // test for alignment with width < height
+    SequenceI[] seqs2 = new SequenceI[] { seqa, seqb, seqc, seqd };
+    Alignment al2 = new Alignment(seqs2);
+    props = new ViewportRanges(al2);
+
+    od = new OverviewDimensions(props, true);
+    int scaledWidth = 300;
+    assertEquals(od.getGraphHeight(), defaultGraphHeight);
+    assertEquals(od.getSequencesHeight(), maxSeqHeight);
+    assertEquals(od.getWidth(), scaledWidth);
+    assertEquals(od.getHeight(), scaledWidth + defaultGraphHeight);
+
+    // test for alignment with width > height and sequence height scaled below
+    // min value
+    SequenceI[] seqs3 = new SequenceI[] { seqe };
+    Alignment al3 = new Alignment(seqs3);
+    props = new ViewportRanges(al3);
+
+    od = new OverviewDimensions(props, true);
+    assertEquals(od.getGraphHeight(), defaultGraphHeight);
+    assertEquals(od.getSequencesHeight(), minSeqHeight);
+    assertEquals(od.getWidth(), maxWidth);
+    assertEquals(od.getHeight(), minSeqHeight + defaultGraphHeight);
+
+    // test for alignment with width < height and width scaled below min value
+    SequenceI[] seqs4 = new SequenceI[] { seqa, seqb, seqc, seqd, seqa,
+        seqb, seqc, seqd, seqa, seqb, seqc, seqd, seqa, seqb, seqc, seqd };
+    Alignment al4 = new Alignment(seqs4);
+    props = new ViewportRanges(al4);
+
+    od = new OverviewDimensions(props, true);
+    assertEquals(od.getGraphHeight(), defaultGraphHeight);
+    assertEquals(od.getSequencesHeight(), maxSeqHeight);
+    assertEquals(od.getWidth(), minWidth);
+    assertEquals(od.getHeight(), maxSeqHeight + defaultGraphHeight);
+
+    Alignment al5 = new Alignment(seqs4);
+    props = new ViewportRanges(al5);
+
+    od = new OverviewDimensions(props, false);
+    assertEquals(od.getGraphHeight(), 0);
+    assertEquals(od.getSequencesHeight(), maxSeqHeight);
+    assertEquals(od.getWidth(), minWidth);
+    assertEquals(od.getHeight(), maxSeqHeight);
+  }
+
+  /**
+   * Test that validation after mouse adjustments to boxX and boxY sets box
+   * dimensions and scroll values correctly, when there are no hidden rows or
+   * columns.
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromMouseClick()
+  {
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
+            vpranges);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 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(),
+            Math.round((float) 10 * alheight / od.getSequencesHeight()));
+    assertEquals(od.getScrollCol(), 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(),
+            Math.round((float) 6 * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(), 0);
+
+    // overly large boxX value reset to width-boxWidth
+    mouseClick(od, 100, 6);
+    assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+    assertEquals(od.getBoxY(), 6);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(),
+            Math.round((float) od.getBoxY() * alheight
+                    / od.getSequencesHeight()));
+
+    // overly large boxY value reset to sequenceHeight - boxHeight
+    mouseClick(od, 10, 520);
+    assertEquals(od.getBoxX(), 10);
+    assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight());
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            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(),
+            Math.round((float) od.getBoxY() * alheight
+                    / od.getSequencesHeight()) - 1);
+
+    // click past end of alignment, as above
+    mouseClick(od, 3000, 5);
+    assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(),
+            Math.round((float) od.getBoxY() * alheight
+                    / od.getSequencesHeight()));
+
+    // move viewport so startRes non-zero and then mouseclick
+    moveViewportH(50);
+
+    // click at viewport position
+    int oldboxx = od.getBoxX();
+    int oldboxy = od.getBoxY();
+    mouseClick(od, od.getBoxX() + 5, od.getBoxY() + 2);
+    assertEquals(od.getBoxX(), oldboxx + 5);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+    assertEquals(od.getBoxY(), oldboxy + 2);
+    assertEquals(od.getScrollRow(),
+            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(od.getBoxY(), 0);
+    assertEquals(od.getScrollRow(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /**
+   * Test setting of the box position, when there are hidden cols at the start
+   * of the alignment
+   */
+  @Test(groups = { "Functional" })
+  public void testFromMouseWithHiddenColsAtStart()
+  {
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
+            vpranges);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+
+    // hide cols at start and check updated box position is correct
+    // changes boxX but not boxwidth
+    int lastHiddenCol = 30;
+    hiddenCols.hideColumns(0, lastHiddenCol);
+
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    assertEquals(od.getBoxX(),
+            Math.round((float) (lastHiddenCol + 1) * od.getWidth()
+                    / alwidth));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // try to click in hidden cols, check box does not move
+    int xpos = 10;
+    mouseClick(od, xpos, 0);
+    assertEquals(
+            od.getBoxX(),
+            Math.round((float) (lastHiddenCol + 1) * od.getWidth()
+                    / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollRow(), 0);
+    assertEquals(od.getScrollCol(), 0);
+
+    // click to right of hidden columns, box moves to click point
+    testBoxIsAtClickPoint(40, 0);
+    assertEquals(od.getScrollRow(), 0);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) 40 * alwidth / od.getWidth())
+                    - (lastHiddenCol + 1));
+
+    // click to right of hidden columns such that box runs over right hand side
+    // of alignment
+    // box position is adjusted away from the edge
+    // overly large boxX value reset to width-boxWidth
+    xpos = 100;
+    mouseClick(od, xpos, 5);
+    assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+    assertEquals(od.getBoxY(), 5);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) od.getBoxX() * alwidth / od.getWidth())
+                    - (lastHiddenCol + 1));
+    assertEquals(od.getScrollRow(),
+            Math.round((float) od.getBoxY() * alheight
+                    / od.getSequencesHeight()));
+  }
+
+  /**
+   * Test setting of the box position, when there are hidden cols in the middle
+   * of the alignment
+   */
+  @Test(groups = { "Functional" })
+  public void testFromMouseWithHiddenColsInMiddle()
+  {
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
+            vpranges);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+    
+    // hide columns 63-73, no change to box position or dimensions
+    int firstHidden = 63;
+    int lastHidden = 73;
+    hiddenCols.hideColumns(firstHidden, lastHidden);
+
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+
+    // move box so that it overlaps with hidden cols on one side
+    // box width changes, boxX and scrollCol as for unhidden case
+    int xpos = 55 - boxWidth; // 55 is position in overview approx halfway
+                              // between cols 60 and 70
+    mouseClick(od, xpos, 0);
+    assertEquals(od.getBoxX(), xpos);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(
+            od.getBoxWidth(),
+            Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
+                    * od.getWidth() / alwidth));
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round(xpos * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(), 0);
+
+    // move box so that it completely covers hidden cols
+    // box width changes, boxX and scrollCol as for hidden case
+    xpos = 33;
+    mouseClick(od, xpos, 0);
+    assertEquals(od.getBoxX(), xpos);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(
+            od.getBoxWidth(),
+            Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
+                    * od.getWidth() / alwidth));
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) xpos * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(), 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
+    // hidden region
+    xpos = 50;
+    mouseClick(od, xpos, 0);
+    assertEquals(od.getBoxX(),
+            Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(
+            od.getBoxWidth(),
+            boxWidth
+                    + Math.round((float) (lastHidden - firstHidden + 1)
+                            * od.getWidth() / alwidth));
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(), firstHidden - 1);
+    assertEquals(od.getScrollRow(), 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(),
+            Math.round(xpos * alwidth / od.getWidth())
+                    - (lastHidden - firstHidden + 1));
+    
+    // move box so it goes beyond full width of alignment
+    // boxX, scrollCol adjusted back, box width normal
+    xpos = 3000;
+    mouseClick(od, xpos, 5);
+    assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+    assertEquals(od.getBoxY(), 5);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round(((float) od.getBoxX() * alwidth / od.getWidth())
+                    - (lastHidden - firstHidden + 1)));
+    assertEquals(od.getScrollRow(),
+            Math.round((float) od.getBoxY() * alheight
+                    / od.getSequencesHeight()));
+
+  }
+
+  /**
+   * Test setting of the box position, when there are hidden cols at the end of
+   * the alignment
+   */
+  @Test(groups = { "Functional" })
+  public void testFromMouseWithHiddenColsAtEnd()
+  {
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
+            vpranges);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+
+    // hide columns 140-164, no change to box position or dimensions
+    int firstHidden = 140;
+    int lastHidden = 164;
+    hiddenCols.hideColumns(firstHidden, lastHidden);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 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(),
+            Math.round((float) xpos * alwidth / od.getWidth()));
+
+    // click to left of hidden cols, with overlap
+    // boxX and scrollCol adjusted for hidden cols, width normal
+    xpos = Math.round((float) 145 * od.getWidth() / alwidth) - boxWidth;
+    mouseClick(od, xpos, 0);
+    assertEquals(od.getBoxX(),
+            Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)
+                    - boxWidth + 1);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(), 0);
+
+    // click in hidden cols
+    // boxX and scrollCol adjusted for hidden cols, width normal
+    xpos = 115;
+    assertEquals(od.getBoxX(),
+            Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)
+                    - boxWidth + 1);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(), 0);
+
+    // click off end of alignment
+    // boxX and scrollCol adjusted for hidden cols, width normal
+    xpos = 3000;
+    assertEquals(od.getBoxX(),
+            Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)
+                    - boxWidth + 1);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(), 0);
+  }
+
+  /**
+   * Test that the box position is set correctly when set from the viewport,
+   * with no hidden rows or columns
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromViewport()
+  {
+    // move viewport to start of alignment
+    moveViewport(0, 0);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to right
+    moveViewportH(70);
+    assertEquals(od.getBoxX(),
+            Math.round((float) 70 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport down
+    moveViewportV(100);
+    assertEquals(od.getBoxX(),
+            Math.round((float) 70 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(),
+            Math.round(100 * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to bottom right
+    moveViewport(98, 508);
+    assertEquals(od.getBoxX(),
+            Math.round((float) 98 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(),
+            Math.round((float) 508 * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /**
+   * Test that the box position is set correctly when there are hidden columns
+   * at the start
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromViewportHiddenColsAtStart()
+  {
+    int firstHidden = 0;
+    int lastHidden = 20;
+    hiddenCols.hideColumns(firstHidden, lastHidden);
+
+    // move viewport to start of alignment
+    moveViewport(0, 0);
+    assertEquals(od.getBoxX(),
+            Math.round((float) (lastHidden + 1) * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to end of alignment - need to make startRes by removing
+    // hidden cols because of how viewport/overview are implemented
+    moveViewport(98 - lastHidden - 1, 0);
+    assertEquals(od.getBoxX(),
+            Math.round((float) 98 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /**
+   * Test that the box position is set correctly when there are hidden columns
+   * in the middle
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromViewportHiddenColsInMiddle()
+  {
+    int firstHidden = 68;
+    int lastHidden = 78;
+    hiddenCols.hideColumns(firstHidden, lastHidden);
+
+    // move viewport before hidden columns
+    moveViewport(3, 0);
+
+    assertEquals(od.getBoxX(),
+            Math.round((float) 3 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    System.out.println(od.getBoxWidth());
+    assertEquals(od.getBoxWidth(), boxWidth);
+    System.out.println(od.getBoxWidth());
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to left of hidden columns with overlap
+    moveViewport(10, 0);
+    assertEquals(od.getBoxX(),
+            Math.round((float) 10 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(
+            od.getBoxWidth(),
+            boxWidth
+                    + Math.round((float) (lastHidden - firstHidden + 1)
+                            * od.getWidth() / alwidth));
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to straddle hidden columns
+    moveViewport(63, 0);
+    assertEquals(od.getBoxX(),
+            Math.round((float) 63 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(
+            od.getBoxWidth(),
+            boxWidth
+                    + Math.round((lastHidden - firstHidden + 1)
+                            * od.getWidth() / alwidth));
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to right of hidden columns, no overlap
+    moveViewport(80 - (lastHidden - firstHidden + 1), 0);
+    assertEquals(od.getBoxX(),
+            Math.round((float) 80 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+  }
+
+  /**
+   * Test that the box position is set correctly when there are hidden columns
+   * at the end
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromViewportHiddenColsAtEnd()
+  {
+    int firstHidden = 152;
+    int lastHidden = 164;
+    hiddenCols.hideColumns(firstHidden, lastHidden);
+
+    // move viewport before hidden columns
+    moveViewport(3, 0);
+    assertEquals(od.getBoxX(),
+            Math.round((float) 3 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to hidden columns
+    // viewport can't actually extend into hidden cols,
+    // so move to the far right edge of the viewport
+    moveViewport(firstHidden - viewWidth, 0);
+    assertEquals(od.getBoxX(),
+            Math.round((float) (firstHidden - viewWidth)
+                    * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /**
+   * Test that the box position is set correctly when there are hidden rows at
+   * the start
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromViewportHiddenRowsAtStart()
+  {
+    int firstHidden = 0;
+    int lastHidden = 20;
+    hideSequences(firstHidden, lastHidden);
+
+    // move viewport to start of alignment:
+    // box moves to below hidden rows, height remains same
+    moveViewport(0, 0);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(),
+            Math.round((float) (lastHidden + 1) * od.getSequencesHeight()
+                    / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to end of alignment
+    moveViewport(0, 525 - viewHeight - lastHidden - 1);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(
+            od.getBoxY(),
+            Math.round((float) (525 - viewHeight) * od.getSequencesHeight()
+                    / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /**
+   * Test that the box position is set correctly when there are hidden rows in
+   * the middle
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromViewportHiddenRowsInMiddle()
+  {
+    int firstHidden = 200;
+    int lastHidden = 210;
+    hideSequences(firstHidden, lastHidden);
+
+    // move viewport to start of alignment:
+    // box, height etc as in non-hidden case
+    moveViewport(0, 0);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to straddle hidden rows
+    moveViewport(0, 198);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), Math.round ((float)198 * od.getSequencesHeight()
+            / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(
+            od.getBoxHeight(),
+            Math.round((float) (viewHeight + lastHidden - firstHidden + 1)
+                    * od.getSequencesHeight() / alheight));
+  }
+
+  /**
+   * Test that the box position is set correctly when there are hidden rows at
+   * the bottom
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromViewportHiddenRowsAtEnd()
+  {
+    int firstHidden = 500;
+    int lastHidden = 524;
+    hideSequences(firstHidden, lastHidden);
+
+    // move viewport to start of alignment:
+    // box, height etc as in non-hidden case
+    moveViewport(0, 0);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to end of alignment
+    // viewport sits above hidden rows and does not include them
+    moveViewport(0, firstHidden - viewHeight - 1);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(
+            od.getBoxY(),
+            Math.round((float) (firstHidden - viewHeight - 1)
+                    * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+  }
+
+  /**
+   * Test setting of the box position, when there are hidden rows at the start
+   * of the alignment
+   */
+  @Test(groups = { "Functional" })
+  public void testFromMouseWithHiddenRowsAtStart()
+  {
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
+            vpranges);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+
+    // hide rows at start and check updated box position is correct
+    // changes boxY but not boxheight
+    int lastHiddenRow = 30;
+    hideSequences(0, lastHiddenRow);
+
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(),
+            Math.round((float) (lastHiddenRow + 1)
+                    * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // click in hidden rows - same result
+    mouseClick(od, 0, 0);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(
+            od.getBoxY(),
+            Math.round((float) (lastHiddenRow + 1)
+                    * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // click below hidden rows
+    mouseClick(od, 0, 150);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 150);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /**
+   * Test setting of the box position, when there are hidden rows at the middle
+   * of the alignment
+   */
+  @Test(groups = { "Functional" })
+  public void testFromMouseWithHiddenRowsInMiddle()
+  {
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
+            vpranges);
+
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+
+    // hide rows in middle and check updated box position is correct
+    // no changes
+    int firstHiddenRow = 50;
+    int lastHiddenRow = 54;
+    hideSequences(firstHiddenRow, lastHiddenRow);
+
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // click above hidden rows, so that box overlaps
+    int ypos = 35; // column value in residues
+    mouseClick(od, 0,
+            Math.round((float) ypos * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(),
+            Math.round((float) ypos * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(
+            od.getBoxHeight(),
+            boxHeight
+                    + Math.round((float) (lastHiddenRow - firstHiddenRow + 1)
+                            * od.getSequencesHeight() / alheight));
+
+    // click so that box straddles hidden rows
+    ypos = 44; // column value in residues
+    mouseClick(od, 0,
+            Math.round((float) ypos * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(),
+            Math.round((float) ypos * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(
+            od.getBoxHeight(),
+            boxHeight
+                    + Math.round((float) (lastHiddenRow - firstHiddenRow + 1)
+                            * od.getSequencesHeight() / alheight));
+  }
+
+  /**
+   * Test setting of the box position, when there are hidden rows at the end of
+   * the alignment
+   */
+  @Test(groups = { "Functional" })
+  public void testFromMouseWithHiddenRowsAtEnd()
+  {
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
+            vpranges);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+
+    // hide rows at end and check updated box position is correct
+    // no changes
+    int firstHidden = 500;
+    int lastHidden = 524;
+    hideSequences(firstHidden, lastHidden);
+
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // click above hidden rows
+    int ypos = 40; // row 40
+    mouseClick(od, 0,
+            Math.round((float) ypos * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(),
+            Math.round((float) ypos * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // click above hidden rows so box overlaps
+    // boxY moved upwards, boxHeight remains same
+    ypos = 497; // row 497
+    mouseClick(od, 0,
+            Math.round((float) ypos * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(
+            od.getBoxY(),
+            Math.round((float) (firstHidden - viewHeight)
+                    * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // click within hidden rows
+    ypos = 505;
+    mouseClick(od, 0,
+            Math.round((float) ypos * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(
+            od.getBoxY(),
+            Math.round((firstHidden - viewHeight) * od.getSequencesHeight()
+                    / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /*
+   * Move viewport horizontally: startRes + previous width gives new horizontal extent. Vertical extent stays the same.
+   */
+  private void moveViewportH(int startRes)
+  {
+    vpranges.setStartRes(startRes);
+    vpranges.setEndRes(startRes + viewWidth - 1);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+  }
+
+  /*
+   * Move viewport vertically: startSeq and endSeq give new vertical extent. Horizontal extent stays the same.
+   */
+  private void moveViewportV(int startSeq)
+  {
+    vpranges.setStartSeq(startSeq);
+    vpranges.setEndSeq(startSeq + viewHeight - 1);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+  }
+
+  /*
+   * Move viewport horizontally and vertically.
+   */
+  private void moveViewport(int startRes, int startSeq)
+  {
+    vpranges.setStartRes(startRes);
+    vpranges.setEndRes(startRes + viewWidth - 1);
+    vpranges.setStartSeq(startSeq);
+    vpranges.setEndSeq(startSeq + viewHeight - 1);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+  }
+
+  /*
+   * Mouse click as position x,y in overview window
+   */
+  private void mouseClick(OverviewDimensions od, int x, int y)
+  {
+    od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols,
+            vpranges);
+
+    // 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, vpranges);
+  }
+  
+  /*
+   * Test that the box is positioned with the top left corner at xpos, ypos
+   * and with the original width and height
+   */
+  private void testBoxIsAtClickPoint(int xpos, int ypos)
+  {
+    mouseClick(od, xpos, ypos);
+    assertEquals(od.getBoxX(), xpos);
+    assertEquals(od.getBoxY(), ypos);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+  }
+
+  /*
+   * Hide sequences between start and end
+   */
+  private void hideSequences(int start, int end)
+  {
+    SequenceI[] allseqs = al.getSequencesArray();
+    SequenceGroup theseSeqs = new SequenceGroup();
+    
+    for (int i = start; i <= end; i++)
+    {
+      theseSeqs.addSequence(allseqs[i], false);
+      al.getHiddenSequences().hideSequence(allseqs[i]);
+    }
+
+    hiddenRepSequences.put(allseqs[start], theseSeqs);
+  }
+}
diff --git a/test/jalview/viewmodel/ViewportRangesTest.java b/test/jalview/viewmodel/ViewportRangesTest.java
new file mode 100644 (file)
index 0000000..cfd03cd
--- /dev/null
@@ -0,0 +1,100 @@
+package jalview.viewmodel;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.analysis.AlignmentGenerator;
+import jalview.datamodel.AlignmentI;
+
+import org.testng.annotations.Test;
+
+public class ViewportRangesTest {
+
+  AlignmentGenerator gen = new AlignmentGenerator(false);
+
+  AlignmentI al = gen.generate(20, 30, 1, 5, 5);
+
+  @Test
+  public void testViewportRanges() 
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    
+    assertEquals(vr.getStartRes(),0);
+    assertEquals(vr.getEndRes(), al.getWidth()-1);
+    assertEquals(vr.getStartSeq(), 0);
+    assertEquals(vr.getEndSeq(), al.getHeight() - 1);
+  }
+
+  @Test
+  public void testGetAbsoluteAlignmentHeight()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+
+    assertEquals(vr.getAbsoluteAlignmentHeight(), al.getHeight());
+
+    al.getHiddenSequences().hideSequence(al.getSequenceAt(3));
+    assertEquals(vr.getAbsoluteAlignmentHeight(), al.getHeight() + 1);
+  }
+
+  @Test
+  public void testGetAbsoluteAlignmentWidth()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    assertEquals(vr.getAbsoluteAlignmentWidth(), al.getWidth());
+  }
+
+  @Test
+  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
+  public void testSetEndSeq()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setEndSeq(-1);
+    assertEquals(vr.getEndSeq(), 0);
+
+    vr.setEndSeq(al.getHeight());
+    assertEquals(vr.getEndSeq(), al.getHeight() - 1);
+
+    vr.setEndRes(al.getHeight() - 1);
+    assertEquals(vr.getEndSeq(), al.getHeight() - 1);
+  }
+
+  @Test
+  public void testSetStartRes()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setStartRes(-1);
+    assertEquals(vr.getStartRes(), 0);
+
+    vr.setStartRes(al.getWidth());
+    assertEquals(vr.getStartRes(), al.getWidth() - 1);
+
+    vr.setStartRes(al.getWidth() - 1);
+    assertEquals(vr.getStartRes(), al.getWidth() - 1);
+  }
+
+  @Test
+  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() - 1);
+    assertEquals(vr.getStartSeq(), al.getHeight() - 1);
+  }
+}
index 98ca303..f1dafcb 100644 (file)
  */
 package jalview.ws.seqfetcher;
 
+import static org.testng.Assert.assertTrue;
+
+import jalview.bin.Cache;
 import jalview.gui.JvOptionPane;
 
-import org.testng.AssertJUnit;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
@@ -36,15 +38,12 @@ public class DasSequenceFetcher
     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
   }
 
-  @Test(groups = { "Functional" })
+  @Test(groups = { "Network" })
   public void testDasRegistryContact()
   {
-    jalview.bin.Cache.getDasSourceRegistry().refreshSources();
-    AssertJUnit
-            .assertTrue(
-                    "Expected to find at least one DAS source at the registry. Check config.",
-                    jalview.bin.Cache.getDasSourceRegistry().getSources()
-                            .size() > 0);
+    Cache.getDasSourceRegistry().refreshSources();
+    assertTrue(Cache.getDasSourceRegistry().getSources().isEmpty(),
+            "Expected to find no DAS sources at the registry. Check config.");
   }
 
 }
index d805e47..7f8adc9 100644 (file)
@@ -38,6 +38,8 @@ import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
 
 import org.testng.Assert;
 import org.testng.FileAssert;
@@ -280,7 +282,19 @@ public class SiftsClientTest
               "A", testSeq, null);
       Assert.assertEquals(testSeq.getStart(), 1);
       Assert.assertEquals(testSeq.getEnd(), 147);
-      Assert.assertEquals(actualMapping, expectedMapping);
+      // Can't do Assert.assertEquals(actualMapping, expectedMapping);
+      // because this fails in our version of TestNG
+      Assert.assertEquals(actualMapping.size(), expectedMapping.size());
+      Iterator<Map.Entry<Integer, int[]>> it = expectedMapping.entrySet()
+              .iterator();
+      while (it.hasNext())
+      {
+        Map.Entry<Integer, int[]> pair = it.next();
+        Assert.assertTrue(actualMapping.containsKey(pair.getKey()));
+        Assert.assertEquals(actualMapping.get(pair.getKey()),
+                pair.getValue());
+      }
+
     } catch (Exception e)
     {
       e.printStackTrace();
@@ -399,7 +413,21 @@ groups = { "Network" },
 
     Assert.assertEquals(strucMapping.getMappingDetailsOutput(),
             expectedMappingOutput);
-    Assert.assertEquals(strucMapping.getMapping(), expectedMapping);
+
+    // Can't do Assert.assertEquals(strucMapping.getMapping(), expectedMapping);
+    // because this fails in our version of TestNG
+    Assert.assertEquals(strucMapping.getMapping().size(),
+            expectedMapping.size());
+    Iterator<Map.Entry<Integer, int[]>> it = expectedMapping.entrySet()
+            .iterator();
+    while (it.hasNext())
+    {
+      Map.Entry<Integer, int[]> pair = it.next();
+      Assert.assertTrue(strucMapping.getMapping()
+              .containsKey(pair.getKey()));
+      Assert.assertEquals(strucMapping.getMapping().get(pair.getKey()),
+              pair.getValue());
+    }
   }
 
   @Test(groups = { "Network" })