Merge remote-tracking branch 'origin/develop' into
authorkiramt <k.mourao@dundee.ac.uk>
Wed, 19 Apr 2017 11:01:30 +0000 (12:01 +0100)
committerkiramt <k.mourao@dundee.ac.uk>
Wed, 19 Apr 2017 11:01:30 +0000 (12:01 +0100)
features/JAL-2388OverviewWindow

Conflicts:
resources/lang/Messages_es.properties

27 files changed:
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/appletgui/AlignViewport.java
src/jalview/appletgui/OverviewCanvas.java [new file with mode: 0644]
src/jalview/appletgui/OverviewPanel.java
src/jalview/datamodel/AlignmentColsCollection.java [new file with mode: 0644]
src/jalview/datamodel/AlignmentRowsCollection.java [new file with mode: 0644]
src/jalview/datamodel/AllColsIterator.java [new file with mode: 0644]
src/jalview/datamodel/AllRowsIterator.java [new file with mode: 0644]
src/jalview/datamodel/HiddenSequences.java
src/jalview/datamodel/VisibleColsIterator.java [new file with mode: 0644]
src/jalview/datamodel/VisibleRowsIterator.java [new file with mode: 0644]
src/jalview/gui/AlignViewport.java
src/jalview/gui/OverviewCanvas.java [new file with mode: 0644]
src/jalview/gui/OverviewPanel.java
src/jalview/gui/OverviewRenderer.java [new file with mode: 0644]
src/jalview/gui/SequenceRenderer.java
src/jalview/viewmodel/AlignmentViewport.java
src/jalview/viewmodel/OverviewDimensions.java
src/jalview/viewmodel/OverviewDimensionsAllVisible.java [new file with mode: 0644]
src/jalview/viewmodel/OverviewDimensionsWithHidden.java [new file with mode: 0644]
src/jalview/viewmodel/ViewportRanges.java
test/jalview/datamodel/AllColsIteratorTest.java [new file with mode: 0644]
test/jalview/datamodel/AllRowsIteratorTest.java [new file with mode: 0644]
test/jalview/datamodel/VisibleColsIteratorTest.java [new file with mode: 0644]
test/jalview/datamodel/VisibleRowsIteratorTest.java [new file with mode: 0644]
test/jalview/viewmodel/OverviewDimensionsTest.java

index 1184c1f..a7723e9 100644 (file)
@@ -1297,3 +1297,4 @@ warn.name_cannot_be_duplicate = User-defined URL names must be unique and cannot
 label.invalid_name = Invalid Name !
 label.output_seq_details = Output Sequence Details to list all database references
 label.urllinks = Links
+label.togglehidden = Toggle hidden columns on/off
\ No newline at end of file
index a878ab7..4c665ff 100644 (file)
@@ -1287,3 +1287,4 @@ warn.name_cannot_be_duplicate = Los nombres URL definidos por el usuario deben s
 label.invalid_name = Nombre inválido !
 label.output_seq_details = Seleccionar Detalles de la secuencia para ver todas
 label.urllinks = Enlaces
+label.togglehidden = Toggle hidden columns on/off
\ No newline at end of file
index 065c503..b289be7 100644 (file)
@@ -39,7 +39,6 @@ import jalview.structure.SelectionSource;
 import jalview.structure.StructureSelectionManager;
 import jalview.structure.VamsasSource;
 import jalview.viewmodel.AlignmentViewport;
-import jalview.viewmodel.ViewportRanges;
 
 import java.awt.Font;
 
@@ -71,11 +70,10 @@ public class AlignViewport extends AlignmentViewport implements
 
   public AlignViewport(AlignmentI al, JalviewLite applet)
   {
-    super();
+    super(al);
     calculator = new jalview.workers.AlignCalcManager();
     this.applet = applet;
-    alignment = al;
-    ranges = new ViewportRanges(this.alignment);
+
     // we always pad gaps
     this.setPadGaps(true);
 
diff --git a/src/jalview/appletgui/OverviewCanvas.java b/src/jalview/appletgui/OverviewCanvas.java
new file mode 100644 (file)
index 0000000..51819cd
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * 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.appletgui;
+
+import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
+import jalview.viewmodel.OverviewDimensions;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Image;
+
+import javax.swing.JComponent;
+
+public class OverviewCanvas extends JComponent
+{
+  // This is set true if the alignment view changes whilst
+  // the overview is being calculated
+  private volatile boolean restart = false;
+
+  private volatile boolean updaterunning = false;
+
+  private OverviewDimensions od;
+
+  private Image miniMe;
+
+  private Image offscreen;
+
+  private AlignViewport av;
+
+  // Can set different properties in this seqCanvas than
+  // main visible SeqCanvas
+  private SequenceRenderer sr;
+
+  private FeatureRenderer fr;
+
+  private Frame nullFrame;
+
+  public OverviewCanvas(OverviewDimensions overviewDims,
+          AlignViewport alignvp)
+  {
+    od = overviewDims;
+    av = alignvp;
+
+    nullFrame = new Frame();
+    nullFrame.addNotify();
+
+    sr = new SequenceRenderer(av);
+    sr.graphics = nullFrame.getGraphics();
+    sr.renderGaps = false;
+    sr.forOverview = true;
+    fr = new FeatureRenderer(av);
+  }
+
+  /*
+   * Signals to drawing code that the associated alignment viewport
+   * has changed and a redraw will be required
+   */
+  public boolean restartDraw()
+  {
+    synchronized (this)
+    {
+      if (updaterunning)
+      {
+        restart = true;
+      }
+      else
+      {
+        updaterunning = true;
+      }
+      return restart;
+    }
+  }
+
+  public void draw(boolean showSequenceFeatures, boolean showAnnotation,
+          AlignmentPanel ap)
+  {
+    miniMe = null;
+
+    if (av.isShowSequenceFeatures())
+    {
+      fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer());
+    }
+
+    setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
+
+    miniMe = nullFrame.createImage(od.getWidth(), od.getHeight());
+    offscreen = nullFrame.createImage(od.getWidth(), od.getHeight());
+
+    Graphics mg = miniMe.getGraphics();
+
+    int alwidth = av.getAlignment().getWidth();
+    int alheight = av.getAlignment().getAbsoluteHeight();
+    float sampleCol = alwidth / (float) od.getWidth();
+    float sampleRow = alheight / (float) od.getSequencesHeight();
+
+    buildImage(sampleRow, sampleCol, mg);
+
+    // check for conservation annotation to make sure overview works for DNA too
+    if (showAnnotation)
+    {
+      for (int col = 0; col < od.getWidth() && !restart; col++)
+      {
+        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();
+
+    if (restart)
+    {
+      restart = false;
+      draw(showSequenceFeatures, showAnnotation, ap);
+    }
+    else
+    {
+      updaterunning = false;
+    }
+  }
+
+  /*
+   * Build the overview panel image
+   */
+  private void buildImage(float sampleRow, float sampleCol, Graphics mg)
+  {
+    int lastcol = 0;
+    int lastrow = 0;
+    int xstart = 0;
+    int ystart = 0;
+    Color color = Color.yellow;
+    int sameRow = 0;
+    int sameCol = 0;
+
+    SequenceI seq = null;
+    FeatureColourFinder finder = new FeatureColourFinder(fr);
+
+    final boolean hasHiddenCols = av.hasHiddenColumns();
+    boolean hiddenRow = false;
+
+    for (int row = 0; row < od.getSequencesHeight() && !restart; row++)
+    {
+      if ((int) (row * sampleRow) == lastrow)
+      {
+        sameRow++;
+      }
+      else
+      {
+        // 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);
+
+        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;
+      }
+    }
+  }
+
+  /*
+   * 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)
+    {
+      color = sr.getResidueColour(seq, lastcol, finder);
+    }
+
+    if (hiddenRow
+            || (hasHiddenCols && !av.getColumnSelection()
+                    .isVisible(lastcol)))
+    {
+      color = color.darker().darker();
+    }
+    return color;
+  }
+
+  @Override
+  public void update(Graphics g)
+  {
+    paint(g);
+  }
+
+  @Override
+  public void paint(Graphics g)
+  {
+    Graphics og = offscreen.getGraphics();
+    if (miniMe != null)
+    {
+      og.drawImage(miniMe, 0, 0, this);
+      og.setColor(Color.red);
+      od.drawBox(og);
+      g.drawImage(offscreen, 0, 0, this);
+    }
+  }
+
+}
index 3ef2936..de192fa 100755 (executable)
  */
 package jalview.appletgui;
 
-import jalview.datamodel.SequenceI;
-import jalview.renderer.seqfeatures.FeatureColourFinder;
-import jalview.viewmodel.OverviewDimensions;
+import jalview.viewmodel.OverviewDimensionsWithHidden;
 
-import java.awt.Color;
+import java.awt.BorderLayout;
 import java.awt.Dimension;
-import java.awt.Frame;
-import java.awt.Graphics;
-import java.awt.Image;
 import java.awt.Panel;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
@@ -39,47 +34,29 @@ import java.awt.event.MouseMotionListener;
 public class OverviewPanel extends Panel implements Runnable,
         MouseMotionListener, MouseListener
 {
-  private OverviewDimensions od;
+  private OverviewDimensionsWithHidden od;
 
-  private Image miniMe;
-
-  private Image offscreen;
+  private OverviewCanvas oviewCanvas;
 
   private AlignViewport av;
 
   private AlignmentPanel ap;
 
-  private 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
-  private SequenceRenderer sr;
-
-  private FeatureRenderer fr;
-
-  private Frame nullFrame;
+  private boolean updateRunning = false;
 
   public OverviewPanel(AlignmentPanel alPanel)
   {
     this.av = alPanel.av;
     this.ap = alPanel;
     setLayout(null);
-    nullFrame = new Frame();
-    nullFrame.addNotify();
-
-    sr = new SequenceRenderer(av);
-    sr.graphics = nullFrame.getGraphics();
-    sr.renderGaps = false;
-    sr.forOverview = true;
-    fr = new FeatureRenderer(av);
 
-    od = new OverviewDimensions(av.getRanges(),
+    od = new OverviewDimensionsWithHidden(av.getRanges(),
             (av.isShowAnnotation() && av.getSequenceConsensusHash() != null));
 
+    oviewCanvas = new OverviewCanvas(od, av);
+    setLayout(new BorderLayout());
+    add(oviewCanvas, BorderLayout.CENTER);
+
     setSize(new Dimension(od.getWidth(), od.getHeight()));
     addComponentListener(new ComponentAdapter()
     {
@@ -155,19 +132,6 @@ public class OverviewPanel extends Panel implements Runnable,
    */
   public void updateOverviewImage()
   {
-    if (resizing)
-    {
-      resizeAgain = true;
-      return;
-    }
-
-    if (av.isShowSequenceFeatures())
-    {
-      fr.transferSettings(ap.seqPanel.seqCanvas.fr);
-    }
-
-    resizing = true;
-
     if ((getSize().width > 0) && (getSize().height > 0))
     {
       od.setWidth(getSize().width);
@@ -175,156 +139,26 @@ public class OverviewPanel extends Panel implements Runnable,
     }
     setSize(new Dimension(od.getWidth(), od.getHeight()));
 
+    if (updateRunning)
+    {
+      oviewCanvas.restartDraw();
+      return;
+    }
+
+    updateRunning = true;
     Thread thread = new Thread(this);
     thread.start();
     repaint();
+    updateRunning = false;
   }
 
   @Override
   public void run()
   {
-    miniMe = null;
-
-    if (av.isShowSequenceFeatures())
-    {
-      fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer());
-    }
-
-    if (getSize().width > 0 && getSize().height > 0)
-    {
-      od.setWidth(getSize().width);
-      od.setHeight(getSize().height);
-    }
-
-    setSize(new Dimension(od.getWidth(), od.getHeight()));
-
-    miniMe = nullFrame.createImage(od.getWidth(), od.getHeight());
-    offscreen = nullFrame.createImage(od.getWidth(), od.getHeight());
-
-    Graphics mg = miniMe.getGraphics();
-
-    int alwidth = av.getAlignment().getWidth();
-    int alheight = av.getAlignment().getAbsoluteHeight();
-    float sampleCol = alwidth / (float) od.getWidth();
-    float sampleRow = alheight / (float) od.getSequencesHeight();
-
-    buildImage(sampleRow, sampleCol, mg);
-
-    // check for conservation annotation to make sure overview works for DNA too
-    if (av.isShowAnnotation()
-            && (av.getAlignmentConservationAnnotation() != null))
-    {
-      for (int col = 0; col < od.getWidth() && !resizeAgain; col++)
-      {
-        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();
-
-    resizing = false;
-
+    oviewCanvas.draw(av.isShowSequenceFeatures(),
+            (av.isShowAnnotation() && av
+                    .getAlignmentConservationAnnotation() != null), ap);
     setBoxPosition();
-
-    if (resizeAgain)
-    {
-      resizeAgain = false;
-      updateOverviewImage();
-    }
-  }
-
-  /*
-   * Build the overview panel image
-   */
-  private void buildImage(float sampleRow, float sampleCol, Graphics mg)
-  {
-    int lastcol = 0;
-    int lastrow = 0;
-    int xstart = 0;
-    int ystart = 0;
-    Color color = Color.yellow;
-    int sameRow = 0;
-    int sameCol = 0;
-
-    SequenceI seq = null;
-    FeatureColourFinder finder = new FeatureColourFinder(fr);
-
-    final boolean hasHiddenCols = av.hasHiddenColumns();
-    boolean hiddenRow = false;
-
-    for (int row = 0; row <= od.getSequencesHeight() && !resizeAgain; row++)
-    {
-      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;
-      }
-    }
-  }
-
-  /*
-   * 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)
-    {
-      color = sr.getResidueColour(seq, lastcol, finder);
-    }
-
-    if (hiddenRow
-            || (hasHiddenCols && !av.getColumnSelection()
-                    .isVisible(lastcol)))
-    {
-      color = color.darker().darker();
-    }
-    return color;
   }
 
   /**
@@ -338,24 +172,4 @@ public class OverviewPanel extends Panel implements Runnable,
             .getHiddenSequences(), av.getColumnSelection(), av.getRanges());
     repaint();
   }
-
-  @Override
-  public void update(Graphics g)
-  {
-    paint(g);
-  }
-
-  @Override
-  public void paint(Graphics g)
-  {
-    Graphics og = offscreen.getGraphics();
-    if (miniMe != null)
-    {
-      og.drawImage(miniMe, 0, 0, this);
-      og.setColor(Color.red);
-      od.drawBox(og);
-      g.drawImage(offscreen, 0, 0, this);
-    }
-  }
-
 }
diff --git a/src/jalview/datamodel/AlignmentColsCollection.java b/src/jalview/datamodel/AlignmentColsCollection.java
new file mode 100644 (file)
index 0000000..3a9f598
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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.datamodel;
+
+import java.util.Iterator;
+
+public class AlignmentColsCollection implements Iterable<Integer>
+{
+  int start;
+  int end;
+  ColumnSelection hidden;
+  
+  public AlignmentColsCollection(int s, int e, ColumnSelection colsel)
+  {
+    start = s;
+    end = e;
+    hidden = colsel;
+  }
+  
+  @Override
+  public Iterator<Integer> iterator()
+  {
+    return new AllColsIterator(start,end,hidden);
+  }
+  
+  /**
+   * Answers if the column at the the current position is hidden.
+   */
+  public boolean isHidden(int c)
+  {
+    return !hidden.isVisible(c);
+  }
+}
diff --git a/src/jalview/datamodel/AlignmentRowsCollection.java b/src/jalview/datamodel/AlignmentRowsCollection.java
new file mode 100644 (file)
index 0000000..e22d8fc
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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.datamodel;
+
+import java.util.Iterator;
+
+public class AlignmentRowsCollection implements Iterable<Integer>
+{
+  int start;
+
+  int end;
+
+  AlignmentI alignment;
+
+  HiddenSequences hidden;
+
+  public AlignmentRowsCollection(int s, int e, AlignmentI al)
+  {
+    start = s;
+    end = e;
+    alignment = al;
+    hidden = al.getHiddenSequences();
+  }
+
+  @Override
+  public Iterator<Integer> iterator()
+  {
+    return new AllRowsIterator(start, end, alignment);
+  }
+
+  /**
+   * Answers if the sequence at the position is hidden.
+   */
+  public boolean isHidden(int seq)
+  {
+    return hidden.isHidden(seq);
+  }
+
+  public SequenceI getSequence(int seq)
+  {
+    return alignment.getSequenceAtAbsoluteIndex(seq);
+  }
+}
+
diff --git a/src/jalview/datamodel/AllColsIterator.java b/src/jalview/datamodel/AllColsIterator.java
new file mode 100644 (file)
index 0000000..4e1ff2e
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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.datamodel;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * An iterator which iterates over all columns or rows in an alignment, whether
+ * hidden or visible.
+ * 
+ * @author kmourao
+ *
+ */
+public class AllColsIterator implements Iterator<Integer>
+{
+  private int last;
+
+  private int next;
+
+  private int current;
+
+  ColumnSelection hidden;
+
+  public AllColsIterator(int firstcol, int lastcol,
+          ColumnSelection hiddenCols)
+  {
+    last = lastcol;
+    next = firstcol;
+    current = firstcol;
+    hidden = hiddenCols;
+  }
+
+  @Override
+  public boolean hasNext()
+  {
+    return current + 1 <= last;
+  }
+
+  @Override
+  public Integer next()
+  {
+    if (current + 1 > last)
+    {
+      throw new NoSuchElementException();
+    }
+    current = next;
+    next++;
+
+    return current;
+  }
+
+  @Override
+  public void remove()
+  {
+    throw new UnsupportedOperationException();
+  }
+}
+
diff --git a/src/jalview/datamodel/AllRowsIterator.java b/src/jalview/datamodel/AllRowsIterator.java
new file mode 100644 (file)
index 0000000..aefed60
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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.datamodel;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * An iterator which iterates over all columns or rows in an alignment, whether
+ * hidden or visible.
+ * 
+ * @author kmourao
+ *
+ */
+public class AllRowsIterator implements Iterator<Integer>
+{
+  private int last;
+
+  private int next;
+
+  private int current;
+
+  private AlignmentI al;
+
+  public AllRowsIterator(int firstrow, int lastrow, AlignmentI alignment)
+  {
+    last = lastrow;
+    current = firstrow;
+    next = firstrow;
+    al = alignment;
+  }
+
+  @Override
+  public boolean hasNext()
+  {
+    return current + 1 <= last;
+  }
+
+  @Override
+  public Integer next()
+  {
+    if (current + 1 > last)
+    {
+      throw new NoSuchElementException();
+    }
+    current = next;
+    next++;
+
+    return current;
+  }
+
+  @Override
+  public void remove()
+  {
+    throw new UnsupportedOperationException();
+  }
+}
+
+
index 6950c28..1daaf43 100755 (executable)
@@ -403,4 +403,20 @@ public class HiddenSequences
 
     return false;
   }
+
+  /**
+   * Answers if a sequence is hidden
+   * 
+   * @param seq
+   *          (absolute) index to test
+   * @return true if sequence at index seq is hidden
+   */
+  public boolean isHidden(int seq)
+  {
+    if (hiddenSequences != null)
+    {
+      return (hiddenSequences[seq] != null);
+    }
+    return false;
+  }
 }
diff --git a/src/jalview/datamodel/VisibleColsIterator.java b/src/jalview/datamodel/VisibleColsIterator.java
new file mode 100644 (file)
index 0000000..2a69a82
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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.datamodel;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * An iterator which iterates over all visible columns in an alignment
+ * 
+ * @author kmourao
+ *
+ */
+public class VisibleColsIterator implements Iterator<Integer>
+{
+  private int last;
+
+  private int current;
+
+  private int next;
+
+  private List<int[]> hidden;
+
+  private int lasthiddenregion;
+
+  public VisibleColsIterator(int firstcol, int lastcol,
+          ColumnSelection hiddenCols)
+  {
+    last = lastcol;
+    current = firstcol;
+    next = firstcol;
+    hidden = hiddenCols.getHiddenColumns();
+    lasthiddenregion = -1;
+
+    if (hidden != null)
+    {
+      int i = 0;
+      for (i = 0; i < hidden.size(); ++i)
+      {
+        if (current >= hidden.get(i)[0] && current <= hidden.get(i)[1])
+        {
+          // current is hidden, move to right
+          current = hidden.get(i)[1] + 1;
+          next = current;
+        }
+        if (current < hidden.get(i)[0])
+        {
+          break;
+        }
+      }
+      lasthiddenregion = i - 1;
+
+      for (i = hidden.size() - 1; i >= 0; --i)
+      {
+        if (last >= hidden.get(i)[0] && last <= hidden.get(i)[1])
+        {
+          // last is hidden, move to left
+          last = hidden.get(i)[0] - 1;
+        }
+        if (last > hidden.get(i)[1])
+        {
+          break;
+        }
+      }
+    }
+  }
+
+  @Override
+  public boolean hasNext()
+  {
+    return next <= last;
+  }
+
+  @Override
+  public Integer next()
+  {
+    if (next > last)
+    {
+      throw new NoSuchElementException();
+    }
+    current = next;
+    if ((hidden != null) && (lasthiddenregion + 1 < hidden.size()))
+    {
+      // still some more hidden regions
+      if (next + 1 < hidden.get(lasthiddenregion + 1)[0])
+      {
+        // next+1 is still before the next hidden region
+        next++;
+      }
+      else if ((next + 1 >= hidden.get(lasthiddenregion + 1)[0])
+              && (next + 1 <= hidden.get(lasthiddenregion + 1)[1]))
+      {
+        // next + 1 is in the next hidden region
+        next = hidden.get(lasthiddenregion + 1)[1] + 1;
+        lasthiddenregion++;
+      }
+    }
+    else
+    {
+      // finished with hidden regions, just increment normally
+      next++;
+    }
+    return current;
+  }
+
+  @Override
+  public void remove()
+  {
+    throw new UnsupportedOperationException();
+  }
+}
+
diff --git a/src/jalview/datamodel/VisibleRowsIterator.java b/src/jalview/datamodel/VisibleRowsIterator.java
new file mode 100644 (file)
index 0000000..0259fd3
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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.datamodel;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * An iterator which iterates over all visible rows in an alignment
+ * 
+ * @author kmourao
+ *
+ */
+public class VisibleRowsIterator implements Iterator<Integer>
+{
+  private int last;
+
+  private int current;
+
+  private int next;
+
+  private HiddenSequences hidden;
+
+  private AlignmentI al;
+
+  /**
+   * Create an iterator for all visible rows in the alignment
+   * 
+   * @param firstrow
+   *          absolute row index to start from
+   * @param lastrow
+   *          absolute row index to end at
+   * @param alignment
+   *          alignment to work with
+   */
+  public VisibleRowsIterator(int firstrow, int lastrow, AlignmentI alignment)
+  {
+    al = alignment;
+    current = firstrow;
+    last = lastrow;
+    hidden = al.getHiddenSequences();
+    while (hidden.isHidden(last) && last > current)
+    {
+      last--;
+    }
+    current = firstrow;
+    while (hidden.isHidden(current) && current < last)
+    {
+      current++;
+    }
+    next = current;
+  }
+
+  @Override
+  public boolean hasNext()
+  {
+    return next <= last;
+  }
+
+  @Override
+  public Integer next()
+  {
+    if (next > last)
+    {
+      throw new NoSuchElementException();
+    }
+    current = next;
+    do
+    {
+      next++;
+    } while (hidden.isHidden(next) && next <= last);
+    return current;
+  }
+
+  @Override
+  public void remove()
+  {
+    throw new UnsupportedOperationException();
+  }
+}
+
index 602e3a1..ef3593c 100644 (file)
@@ -51,7 +51,6 @@ 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;
@@ -105,7 +104,7 @@ public class AlignViewport extends AlignmentViewport implements
    */
   public AlignViewport(AlignmentI al)
   {
-    setAlignment(al);
+    super(al);
     init();
   }
 
@@ -123,6 +122,7 @@ public class AlignViewport extends AlignmentViewport implements
 
   public AlignViewport(AlignmentI al, String seqsetid, String viewid)
   {
+    super(al);
     sequenceSetID = seqsetid;
     viewId = viewid;
     // TODO remove these once 2.4.VAMSAS release finished
@@ -135,8 +135,8 @@ public class AlignViewport extends AlignmentViewport implements
     {
       Cache.log.debug("Setting viewport's view id : " + viewId);
     }
-    setAlignment(al);
     init();
+
   }
 
   /**
@@ -149,7 +149,7 @@ public class AlignViewport extends AlignmentViewport implements
    */
   public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns)
   {
-    setAlignment(al);
+    super(al);
     if (hiddenColumns != null)
     {
       colSel = hiddenColumns;
@@ -184,6 +184,7 @@ public class AlignViewport extends AlignmentViewport implements
   public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns,
           String seqsetid, String viewid)
   {
+    super(al);
     sequenceSetID = seqsetid;
     viewId = viewid;
     // TODO remove these once 2.4.VAMSAS release finished
@@ -196,7 +197,7 @@ public class AlignViewport extends AlignmentViewport implements
     {
       Cache.log.debug("Setting viewport's view id : " + viewId);
     }
-    setAlignment(al);
+
     if (hiddenColumns != null)
     {
       colSel = hiddenColumns;
@@ -238,7 +239,6 @@ public class AlignViewport extends AlignmentViewport implements
 
   void init()
   {
-    ranges = new ViewportRanges(this.alignment);
     applyViewProperties();
 
     String fontName = Cache.getDefault("FONT_NAME", "SansSerif");
diff --git a/src/jalview/gui/OverviewCanvas.java b/src/jalview/gui/OverviewCanvas.java
new file mode 100644 (file)
index 0000000..e4c2056
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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 jalview.api.AlignViewportI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
+import jalview.viewmodel.OverviewDimensions;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+
+import javax.swing.JComponent;
+
+
+public class OverviewCanvas extends JComponent
+{
+  private static final Color TRANS_GREY = new Color(100, 100, 100, 25);
+
+  // This is set true if the alignment view changes whilst
+  // the overview is being calculated
+  private volatile boolean restart = false;
+
+  private volatile boolean updaterunning = false;
+
+  private BufferedImage miniMe;
+
+  private BufferedImage lastMiniMe = null;
+
+  // Can set different properties in this seqCanvas than
+  // main visible SeqCanvas
+  private SequenceRenderer sr;
+
+  private jalview.renderer.seqfeatures.FeatureRenderer fr;
+
+  OverviewDimensions od;
+
+  AlignViewportI av;
+
+  public OverviewCanvas(OverviewDimensions overviewDims,
+          AlignViewportI alignvp)
+  {
+    od = overviewDims;
+    av = alignvp;
+
+    sr = new SequenceRenderer(av);
+    sr.renderGaps = false;
+    sr.forOverview = true;
+    fr = new jalview.renderer.seqfeatures.FeatureRenderer(av);
+  }
+
+  public void resetOviewDims(OverviewDimensions overviewDims)
+  {
+    od = overviewDims;
+  }
+
+  /*
+   * Signals to drawing code that the associated alignment viewport
+   * has changed and a redraw will be required
+   */
+  public boolean restartDraw()
+  {
+    synchronized (this)
+    {
+      if (updaterunning)
+      {
+        restart = true;
+      }
+      else
+      {
+        updaterunning = true;
+      }
+      return restart;
+    }
+  }
+
+  public void draw(boolean showSequenceFeatures, boolean showAnnotation,
+          FeatureRenderer transferRenderer)
+  {
+    miniMe = null;
+
+    if (showSequenceFeatures)
+    {
+      fr.transferSettings(transferRenderer);
+    }
+    FeatureColourFinder finder = new FeatureColourFinder(fr);
+
+    // why do we need to set preferred size again? was set in
+    // updateOverviewImage
+    setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
+
+    OverviewRenderer or = new OverviewRenderer(sr, finder, od);
+    miniMe = or.draw(od.getRows(av.getRanges(), av.getAlignment()),
+            od.getColumns(av.getRanges(), av.getColumnSelection()));
+
+    Graphics mg = miniMe.getGraphics();
+
+    if (showAnnotation)
+    {
+      mg.translate(0, od.getSequencesHeight());
+      or.drawGraph(mg, av.getAlignmentConservationAnnotation(),
+              av.getCharWidth(), od.getGraphHeight(),
+              od.getColumns(av.getRanges(), av.getColumnSelection()));
+      mg.translate(0, -od.getSequencesHeight());
+    }
+    System.gc();
+
+    if (restart)
+    {
+      restart = false;
+      draw(showSequenceFeatures, showAnnotation, transferRenderer);
+    }
+    else
+    {
+      updaterunning = false;
+      lastMiniMe = miniMe;
+    }
+  }
+
+  @Override
+  public void paintComponent(Graphics g)
+  {
+    if (restart)
+    {
+      if (lastMiniMe == null)
+      {
+        g.setColor(Color.white);
+        g.fillRect(0, 0, getWidth(), getHeight());
+      }
+      else
+      {
+        g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this);
+      }
+      g.setColor(TRANS_GREY);
+      g.fillRect(0, 0, getWidth(), getHeight());
+    }
+    else if (lastMiniMe != null)
+    {
+      g.drawImage(lastMiniMe, 0, 0, this);
+      if (lastMiniMe != miniMe)
+      {
+        g.setColor(TRANS_GREY);
+        g.fillRect(0, 0, getWidth(), getHeight());
+      }
+    }
+
+    g.setColor(Color.red);
+    od.drawBox(g);
+  }
+
+}
index c530fdc..8a416bd 100755 (executable)
  */
 package jalview.gui;
 
-import jalview.datamodel.SequenceI;
-import jalview.renderer.AnnotationRenderer;
-import jalview.renderer.seqfeatures.FeatureColourFinder;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
 import jalview.viewmodel.OverviewDimensions;
+import jalview.viewmodel.OverviewDimensionsAllVisible;
+import jalview.viewmodel.OverviewDimensionsWithHidden;
 
-import java.awt.Color;
+import java.awt.BorderLayout;
 import java.awt.Dimension;
-import java.awt.Graphics;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseMotionAdapter;
-import java.awt.image.BufferedImage;
 
+import javax.swing.JMenuItem;
 import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
 
 /**
  * Panel displaying an overview of the full alignment, with an interactive box
@@ -46,32 +50,15 @@ import javax.swing.JPanel;
  */
 public class OverviewPanel extends JPanel implements Runnable
 {
-  private static final Color TRANS_GREY = new Color(100, 100, 100, 25);
-
-  private final AnnotationRenderer renderer = new AnnotationRenderer();
-
   private OverviewDimensions od;
 
-  private BufferedImage miniMe;
-
-  private BufferedImage lastMiniMe = null;
+  private OverviewCanvas oviewCanvas;
 
   private AlignViewport av;
 
   private AlignmentPanel ap;
 
-  //
-  private 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
-  private SequenceRenderer sr;
-
-  jalview.renderer.seqfeatures.FeatureRenderer fr;
+  private boolean showHidden = true;
 
   /**
    * Creates a new OverviewPanel object.
@@ -83,17 +70,15 @@ public class OverviewPanel extends JPanel implements Runnable
   {
     this.av = alPanel.av;
     this.ap = alPanel;
-    setLayout(null);
 
-    sr = new SequenceRenderer(av);
-    sr.renderGaps = false;
-    sr.forOverview = true;
-    fr = new FeatureRenderer(ap);
-
-    od = new OverviewDimensions(av.getRanges(),
+    od = new OverviewDimensionsWithHidden(av.getRanges(),
             (av.isShowAnnotation() && av
                     .getAlignmentConservationAnnotation() != null));
 
+    oviewCanvas = new OverviewCanvas(od, av);
+    setLayout(new BorderLayout());
+    add(oviewCanvas, BorderLayout.CENTER);
+
     addComponentListener(new ComponentAdapter()
     {
       @Override
@@ -112,7 +97,8 @@ public class OverviewPanel extends JPanel implements Runnable
       @Override
       public void mouseDragged(MouseEvent evt)
       {
-        if (!av.getWrapAlignment())
+        if (!SwingUtilities.isRightMouseButton(evt)
+                && !av.getWrapAlignment())
         {
           od.updateViewportFromMouse(evt.getX(), evt.getY(), av
                   .getAlignment().getHiddenSequences(), av
@@ -127,7 +113,14 @@ public class OverviewPanel extends JPanel implements Runnable
       @Override
       public void mousePressed(MouseEvent evt)
       {
-        if (!av.getWrapAlignment())
+        if (SwingUtilities.isRightMouseButton(evt))
+        {
+          if (!Platform.isAMac())
+          {
+            showPopupMenu(evt);
+          }
+        }
+        else if (!av.getWrapAlignment())
         {
           od.updateViewportFromMouse(evt.getX(), evt.getY(), av
                   .getAlignment().getHiddenSequences(), av
@@ -135,183 +128,95 @@ public class OverviewPanel extends JPanel implements Runnable
           ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
         }
       }
+
+      @Override
+      public void mouseClicked(MouseEvent evt)
+      {
+        if (SwingUtilities.isRightMouseButton(evt))
+        {
+          showPopupMenu(evt);
+        }
+      }
     });
 
+
     updateOverviewImage();
   }
 
-  /**
-   * Updates the overview image when the related alignment panel is updated
+  /*
+   * Displays the popup menu and acts on user input
    */
-  public void updateOverviewImage()
+  private void showPopupMenu(MouseEvent e)
   {
-    if (resizing)
+    JPopupMenu popup = new JPopupMenu();
+    ActionListener menuListener = new ActionListener()
     {
-      resizeAgain = true;
-      return;
-    }
-
-    resizing = true;
-
-    if ((getWidth() > 0) && (getHeight() > 0))
-    {
-      od.setWidth(getWidth());
-      od.setHeight(getHeight());
-    }
-
-    setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
-
-    Thread thread = new Thread(this);
-    thread.start();
-    repaint();
-  }
-
-  @Override
-  public void run()
-  {
-    miniMe = null;
-
-    if (av.isShowSequenceFeatures())
-    {
-      fr.transferSettings(ap.getSeqPanel().seqCanvas.getFeatureRenderer());
-    }
-
-    // why do we need to set preferred size again? was set in
-    // updateOverviewImage
-    setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
-
-    miniMe = new BufferedImage(od.getWidth(), od.getHeight(),
-            BufferedImage.TYPE_INT_RGB);
-
-    Graphics mg = miniMe.getGraphics();
-    mg.setColor(Color.orange);
-    mg.fillRect(0, 0, od.getWidth(), miniMe.getHeight());
-
-    // 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();
-
-    // 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();
-
-    buildImage(sampleRow, sampleCol);
-
-    // check for conservation annotation to make sure overview works for DNA too
-    if (av.isShowAnnotation()
-            && (av.getAlignmentConservationAnnotation() != null))
-    {
-      renderer.updateFromAlignViewport(av);
-      for (int col = 0; col < od.getWidth() && !resizeAgain; col++)
+      @Override
+      public void actionPerformed(ActionEvent event)
       {
-        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());
-
+        // switch on/off the hidden columns view
+        toggleHiddenColumns();
       }
-    }
-    System.gc();
-
-    resizing = false;
+    };
+    JMenuItem item;
+    popup.add(item = new JMenuItem(MessageManager
+            .getString("label.togglehidden")));
+    item.addActionListener(menuListener);
+    popup.show(this, e.getX(), e.getY());
+  }
 
-    if (resizeAgain)
+  private void toggleHiddenColumns()
+  {
+    if (showHidden)
     {
-      resizeAgain = false;
-      updateOverviewImage();
+      showHidden = false;
+      od = new OverviewDimensionsAllVisible(av.getRanges(),
+              (av.isShowAnnotation() && av
+                      .getAlignmentConservationAnnotation() != null));
     }
     else
     {
-      lastMiniMe = miniMe;
+      showHidden = true;
+      od = new OverviewDimensionsWithHidden(av.getRanges(),
+              (av.isShowAnnotation() && av
+                      .getAlignmentConservationAnnotation() != null));
     }
-
-    setBoxPosition();
+    oviewCanvas.resetOviewDims(od);
+    updateOverviewImage();
   }
 
-  /*
-   * Build the overview panel image
+  /**
+   * Updates the overview image when the related alignment panel is updated
    */
-  private void buildImage(float sampleRow, float sampleCol)
+  public void updateOverviewImage()
   {
-    int lastcol = -1;
-    int lastrow = -1;
-    int rgbColour = Color.white.getRGB();
-
-    SequenceI seq = null;
-    FeatureColourFinder finder = new FeatureColourFinder(fr);
-
-    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++)
+    if ((getWidth() > 0) && (getHeight() > 0))
     {
-      boolean doCopy = true;
-      int currentrow = (int) (row * sampleRow);
-      if (currentrow != lastrow)
-      {
-        doCopy = false;
-
-        lastrow = currentrow;
-
-        // 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);
-      }
-
-      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);
-      }
+      od.setWidth(getWidth());
+      od.setHeight(getHeight());
     }
-  }
 
-  /*
-   * 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;
+    setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
 
-    if ((seq != null) && (seq.getLength() > lastcol))
+    if (oviewCanvas.restartDraw())
     {
-       color = sr.getResidueColour(seq, lastcol, finder);
+      return;
     }
 
-    if (hiddenRow
-            || (hasHiddenCols && !av.getColumnSelection()
-                    .isVisible(lastcol)))
-    {
-      color = color.darker().darker();
-    }
+    Thread thread = new Thread(this);
+    thread.start();
+    repaint();
 
-    return color.getRGB();
+  }
+
+  @Override
+  public void run()
+  {
+    oviewCanvas.draw(av.isShowSequenceFeatures(),
+            (av.isShowAnnotation() && av
+                    .getAlignmentConservationAnnotation() != null), ap
+                    .getSeqPanel().seqCanvas.getFeatureRenderer());
+    setBoxPosition();
   }
 
   /**
@@ -325,36 +230,4 @@ public class OverviewPanel extends JPanel implements Runnable
             .getHiddenSequences(), av.getColumnSelection(), av.getRanges());
     repaint();
   }
-
-
-  @Override
-  public void paintComponent(Graphics g)
-  {
-    if (resizing || resizeAgain)
-    {
-      if (lastMiniMe == null)
-      {
-        g.setColor(Color.white);
-        g.fillRect(0, 0, getWidth(), getHeight());
-      }
-      else
-      {
-        g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this);
-      }
-      g.setColor(TRANS_GREY);
-      g.fillRect(0, 0, getWidth(), getHeight());
-    }
-    else if (lastMiniMe != null)
-    {
-      g.drawImage(lastMiniMe, 0, 0, this);
-      if (lastMiniMe != miniMe)
-      {
-        g.setColor(TRANS_GREY);
-        g.fillRect(0, 0, getWidth(), getHeight());
-      }
-    }
-
-    g.setColor(Color.red);
-    od.drawBox(g);
-  }
 }
diff --git a/src/jalview/gui/OverviewRenderer.java b/src/jalview/gui/OverviewRenderer.java
new file mode 100644 (file)
index 0000000..87937ba
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * 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 jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentColsCollection;
+import jalview.datamodel.AlignmentRowsCollection;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
+import jalview.viewmodel.OverviewDimensions;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+
+public class OverviewRenderer
+{
+  private FeatureColourFinder finder;
+
+  private SequenceRenderer sr;
+
+  // image to render on
+  private BufferedImage miniMe;
+
+  // raw number of pixels to allocate to each column
+  private float pixelsPerCol;
+
+  // raw number of pixels to allocate to each row
+  private float pixelsPerSeq;
+
+  public OverviewRenderer(SequenceRenderer seqRenderer,
+          FeatureColourFinder colfinder, OverviewDimensions od)
+  {
+    sr = seqRenderer;
+    finder = colfinder;
+
+    pixelsPerCol = od.getPixelsPerCol();
+    pixelsPerSeq = od.getPixelsPerSeq();
+    miniMe = new BufferedImage(od.getWidth(), od.getHeight(),
+            BufferedImage.TYPE_INT_RGB);
+  }
+
+  /**
+   * Draw alignment rows and columns onto an image
+   * 
+   * @param rit
+   *          Iterator over rows to be drawn
+   * @param cit
+   *          Iterator over columns to be drawn
+   * @return image containing the drawing
+   */
+  public BufferedImage draw(AlignmentRowsCollection rows,
+          AlignmentColsCollection cols)
+  {
+    int rgbcolor = Color.white.getRGB();
+    int seqIndex = 0;
+    int pixelRow = 0;
+    for (int alignmentRow : rows)
+    {
+      // get details of this alignment row
+      boolean hidden = rows.isHidden(alignmentRow);
+      SequenceI seq = rows.getSequence(alignmentRow);
+
+      // calculate where this row extends to in pixels
+      int endRow = Math.min(Math.round((seqIndex + 1) * pixelsPerSeq) - 1,
+              miniMe.getHeight() - 1);
+
+      int colIndex = 0;
+      int pixelCol = 0;
+      for (int alignmentCol : cols)
+      {
+        // calculate where this column extends to in pixels
+        int endCol = Math.min(
+                Math.round((colIndex + 1) * pixelsPerCol) - 1,
+                miniMe.getWidth() - 1);
+
+        // determine the colour based on the sequence and column position
+        rgbcolor = getColumnColourFromSequence(seq,
+                hidden || cols.isHidden(alignmentCol), alignmentCol, finder);
+
+        // fill in the appropriate number of pixels
+        for (int row = pixelRow; row <= endRow; ++row)
+        {
+          for (int col = pixelCol; col <= endCol; ++col)
+          {
+            miniMe.setRGB(col, row, rgbcolor);
+          }
+        }
+
+        pixelCol = endCol + 1;
+        colIndex++;
+      }
+      pixelRow = endRow + 1;
+      seqIndex++;
+    }
+    return miniMe;
+  }
+
+  /*
+   * Find the colour of a sequence at a specified column position
+   */
+  private int getColumnColourFromSequence(jalview.datamodel.SequenceI seq,
+          boolean isHidden, int lastcol, FeatureColourFinder finder)
+  {
+    Color color = Color.white;
+
+    if ((seq != null) && (seq.getLength() > lastcol))
+    {
+      color = sr.getResidueColour(seq, lastcol, finder);
+    }
+
+    if (isHidden)
+    {
+      color = color.darker().darker();
+    }
+
+    return color.getRGB();
+  }
+
+  public void drawGraph(Graphics g, AlignmentAnnotation _aa, int charWidth,
+          int y, AlignmentColsCollection cols)
+  {
+    Annotation[] aa_annotations = _aa.annotations;
+    g.setColor(Color.white);
+    g.fillRect(0, 0, miniMe.getWidth(), y);
+    // g.setColor(new Color(0, 0, 180));
+
+    int height;
+
+    int colIndex = 0;
+    int pixelCol = 0;
+    for (int alignmentCol : cols)
+    {
+      int endCol = Math.min(Math.round((colIndex + 1) * pixelsPerCol) - 1,
+              miniMe.getWidth() - 1);
+
+      if (alignmentCol < aa_annotations.length
+              && aa_annotations[alignmentCol] != null)
+      {
+        if (aa_annotations[alignmentCol].colour == null)
+        {
+          g.setColor(Color.black);
+        }
+        else
+        {
+          g.setColor(aa_annotations[alignmentCol].colour);
+        }
+
+        height = (int) ((aa_annotations[alignmentCol].value / _aa.graphMax) * y);
+        if (height > y)
+        {
+          height = y;
+        }
+
+        g.fillRect(pixelCol, y - height, endCol - pixelCol + 1, height);
+      }
+      pixelCol = endCol + 1;
+      colIndex++;
+    }
+  }
+}
index 1c0420d..2a2a0cf 100755 (executable)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import jalview.api.AlignViewportI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.ResidueShaderI;
@@ -34,7 +35,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
 {
   final static int CHAR_TO_UPPER = 'A' - 'a';
 
-  AlignViewport av;
+  AlignViewportI av;
 
   FontMetrics fm;
 
@@ -57,7 +58,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
    * 
    * @param viewport
    */
-  public SequenceRenderer(AlignViewport viewport)
+  public SequenceRenderer(AlignViewportI viewport)
   {
     this.av = viewport;
   }
@@ -181,7 +182,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
 
     drawBoxes(seq, start, end, y1);
 
-    if (av.validCharWidth)
+    if (av.isValidCharWidth())
     {
       drawText(seq, start, end, y1);
     }
index 47dceec..e0ffe33 100644 (file)
@@ -78,7 +78,7 @@ import jalview.workers.StrucConsensusThread;
 public abstract class AlignmentViewport implements AlignViewportI,
         CommandListener, VamsasSource
 {
-  protected ViewportRanges ranges;
+  final protected ViewportRanges ranges;
 
   protected ViewStyleI viewStyle = new ViewStyle();
 
@@ -95,6 +95,17 @@ public abstract class AlignmentViewport implements AlignViewportI,
   protected Deque<CommandI> redoList = new ArrayDeque<CommandI>();
 
   /**
+   * alignment displayed in the viewport. Please use get/setter
+   */
+  protected AlignmentI alignment;
+
+  public AlignmentViewport(AlignmentI al)
+  {
+    setAlignment(al);
+    ranges = new ViewportRanges(al);
+  }
+
+  /**
    * @param name
    * @see jalview.api.ViewStyleI#setFontName(java.lang.String)
    */
@@ -554,10 +565,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
     viewStyle.setSeqNameItalics(default1);
   }
 
-  /**
-   * alignment displayed in the viewport. Please use get/setter
-   */
-  protected AlignmentI alignment;
+
 
   @Override
   public AlignmentI getAlignment()
index 43680b5..50e1210 100644 (file)
@@ -1,79 +1,31 @@
-/*
- * 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.AlignmentColsCollection;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentRowsCollection;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.HiddenSequences;
 
 import java.awt.Graphics;
 
-public class OverviewDimensions
+public abstract 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;
+  private static final int DEFAULT_GRAPH_HEIGHT = 20;
+  protected static final int MAX_WIDTH = 400;
+  protected static final int MIN_WIDTH = 120;
+  protected static final int MIN_SEQ_HEIGHT = 40;
+  protected static final int MAX_SEQ_HEIGHT = 300;
+  protected int width;
+  protected int sequencesHeight;
+  protected int graphHeight = DEFAULT_GRAPH_HEIGHT;
+  protected int boxX = -1;
+  protected int boxY = -1;
+  protected int boxWidth = -1;
+  protected int boxHeight = -1;
+  protected int scrollCol = -1;
+  protected int scrollRow = -1;
 
-  /**
-   * 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)
   {
@@ -111,159 +63,6 @@ public class OverviewDimensions
   }
 
   /**
-   * 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
@@ -285,27 +84,21 @@ public class OverviewDimensions
     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;
@@ -340,4 +133,21 @@ public class OverviewDimensions
   {
     return graphHeight;
   }
-}
+
+  public abstract void updateViewportFromMouse(int mousex, int mousey,
+          HiddenSequences hiddenSeqs, ColumnSelection hiddenCols,
+          ViewportRanges ranges);
+
+  public abstract void setBoxPosition(HiddenSequences hiddenSeqs,
+          ColumnSelection hiddenCols, ViewportRanges ranges);
+
+  public abstract AlignmentColsCollection getColumns(
+          ViewportRanges ranges, ColumnSelection hiddenCols);
+
+  public abstract AlignmentRowsCollection getRows(
+          ViewportRanges ranges, AlignmentI al);
+
+  public abstract float getPixelsPerCol();
+
+  public abstract float getPixelsPerSeq();
+}
\ No newline at end of file
diff --git a/src/jalview/viewmodel/OverviewDimensionsAllVisible.java b/src/jalview/viewmodel/OverviewDimensionsAllVisible.java
new file mode 100644 (file)
index 0000000..21f0be6
--- /dev/null
@@ -0,0 +1,165 @@
+package jalview.viewmodel;
+
+import jalview.datamodel.AlignmentColsCollection;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentRowsCollection;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenSequences;
+
+public class OverviewDimensionsAllVisible extends OverviewDimensions
+{
+  private float pixelsPerCol;
+
+  private float pixelsPerSeq;
+
+  public OverviewDimensionsAllVisible(ViewportRanges ranges,
+          boolean showAnnotationPanel)
+  {
+    super(ranges, showAnnotationPanel);
+
+    int alwidth = ranges.getVisibleAlignmentWidth();
+    int alheight = ranges.getVisibleAlignmentHeight();
+
+    pixelsPerCol = (float) width / alwidth;
+    pixelsPerSeq = (float) sequencesHeight / alheight;
+  }
+
+  @Override
+  public void updateViewportFromMouse(int mousex, int mousey,
+          HiddenSequences hiddenSeqs, ColumnSelection hiddenCols,
+          ViewportRanges ranges)
+  {
+    int x = mousex;
+    int y = mousey;
+
+    int alwidth = ranges.getVisibleAlignmentWidth();
+    int alheight = ranges.getVisibleAlignmentHeight();
+
+    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;
+
+    if (xAsRes + vpwidth > alwidth)
+    {
+      // went past the end of the alignment, adjust backwards
+
+      // if last position was before the end of the alignment, need to update
+      if ((scrollCol + vpwidth - 1) < alwidth)
+      {
+        xAsRes = alwidth - vpwidth;
+      }
+      else
+      {
+        xAsRes = 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;
+
+    if (yAsSeq + vpheight > alheight)
+    {
+      // went past the end of the alignment, adjust backwards
+      if ((scrollRow + vpheight - 1) < alheight)
+      {
+        yAsSeq = alheight - vpheight;
+      }
+      else
+      {
+        yAsSeq = scrollRow;
+      }
+    }
+
+    // update scroll values
+    scrollCol = xAsRes;
+    scrollRow = yAsSeq;
+
+  }
+
+  @Override
+  public void setBoxPosition(HiddenSequences hiddenSeqs,
+          ColumnSelection hiddenCols, ViewportRanges ranges)
+  {
+    int alwidth = ranges.getVisibleAlignmentWidth();
+    int alheight = ranges.getVisibleAlignmentHeight();
+
+    // work with visible values of startRes and endRes
+    int startRes = ranges.getStartRes();
+    int endRes = ranges.getEndRes();
+
+    // work with visible values of startSeq and endSeq
+    int startSeq = ranges.getStartSeq();
+    int endSeq = ranges.getEndSeq();
+
+    // 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);
+
+  }
+
+  @Override
+  public AlignmentColsCollection getColumns(ViewportRanges ranges,
+          ColumnSelection hiddenCols)
+  {
+    return new AlignmentColsCollection(0,
+            ranges.getVisibleAlignmentWidth() - 1, hiddenCols);
+  }
+
+  @Override
+  public AlignmentRowsCollection getRows(ViewportRanges ranges,
+          AlignmentI al)
+  {
+    return new AlignmentRowsCollection(0,
+            ranges.getVisibleAlignmentHeight() - 1, al);
+  }
+
+  @Override
+  public float getPixelsPerCol()
+  {
+    return pixelsPerCol;
+  }
+
+  @Override
+  public float getPixelsPerSeq()
+  {
+    return pixelsPerSeq;
+  }
+}
diff --git a/src/jalview/viewmodel/OverviewDimensionsWithHidden.java b/src/jalview/viewmodel/OverviewDimensionsWithHidden.java
new file mode 100644 (file)
index 0000000..575167a
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * 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.AlignmentColsCollection;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentRowsCollection;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenSequences;
+
+public class OverviewDimensionsWithHidden extends OverviewDimensions
+{
+  private float pixelsPerCol;
+
+  private float pixelsPerSeq;
+
+  /**
+   * 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 OverviewDimensionsWithHidden(ViewportRanges ranges,
+          boolean showAnnotationPanel)
+  {
+    super(ranges, showAnnotationPanel);
+
+    int alwidth = ranges.getAbsoluteAlignmentWidth();
+    int alheight = ranges.getAbsoluteAlignmentHeight();
+
+    pixelsPerCol = (float) width / alwidth;
+    pixelsPerSeq = (float) sequencesHeight / alheight;
+  }
+
+  /**
+   * 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
+   */
+  @Override
+  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 visYAsSeq = hiddenSeqs.findIndexWithoutHiddenSeqs(yAsSeq);
+    if (visYAsSeq + vpheight - 1 > visAlignHeight)
+    {
+      // went past the end of the alignment, adjust backwards
+      if ((scrollRow + vpheight - 1) < visAlignHeight)
+      {
+        visYAsSeq = hiddenSeqs.findIndexWithoutHiddenSeqs(hiddenSeqs
+                .subtractVisibleRows(vpheight - 1, alheight - 1));
+      }
+      else
+      {
+        visYAsSeq = scrollRow;
+      }
+    }
+
+    // update scroll values
+    scrollCol = visXAsRes;
+    scrollRow = visYAsSeq;
+
+  }
+
+  /**
+   * 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
+   */
+  @Override
+  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);
+  }
+
+  @Override
+  public AlignmentColsCollection getColumns(ViewportRanges ranges,
+          ColumnSelection hiddenCols)
+  {
+    return new AlignmentColsCollection(0,
+            ranges.getAbsoluteAlignmentWidth() - 1,
+            hiddenCols);
+  }
+
+  @Override
+  public AlignmentRowsCollection getRows(ViewportRanges ranges,
+          AlignmentI al)
+  {
+    return new AlignmentRowsCollection(0,
+            ranges.getAbsoluteAlignmentHeight() - 1,
+            al);
+  }
+
+  @Override
+  public float getPixelsPerCol()
+  {
+    return pixelsPerCol;
+  }
+
+  @Override
+  public float getPixelsPerSeq()
+  {
+    return pixelsPerSeq;
+  }
+}
index c91d2d9..18703b4 100644 (file)
@@ -79,6 +79,23 @@ public class ViewportRanges extends ViewportProperties
   }
 
   /**
+   * Get alignment width in cols, excluding hidden cols
+   */
+  public int getVisibleAlignmentWidth()
+  {
+    // TODO need access to hidden columns here
+    return al.getWidth(); // - hidden columns
+  }
+
+  /**
+   * Get alignment height in rows, excluding hidden rows
+   */
+  public int getVisibleAlignmentHeight()
+  {
+    return al.getHeight();
+  }
+
+  /**
    * Set first residue visible in the viewport
    * 
    * @param res
diff --git a/test/jalview/datamodel/AllColsIteratorTest.java b/test/jalview/datamodel/AllColsIteratorTest.java
new file mode 100644 (file)
index 0000000..ee82340
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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.datamodel;
+
+import static org.testng.Assert.assertTrue;
+
+import java.util.NoSuchElementException;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class AllColsIteratorTest
+{
+  ColumnSelection hiddenCols;
+  
+  @BeforeClass
+  public void setup()
+  {
+   hiddenCols = new ColumnSelection();
+   hiddenCols.hideColumns(2,4);
+  }
+  
+
+  /*
+   * Test iterator iterates through collection correctly
+   */
+  @Test(groups = { "Functional" })
+  public void testHasNextAndNext()
+  {
+    AllColsIterator it = new AllColsIterator(0, 3, hiddenCols);
+    int count = 0;
+    while (it.hasNext())
+    {
+      it.next();
+      count++;
+    }
+    assertTrue(count == 4, "hasNext() is false after 4 iterations");
+  }
+
+  /*
+   * Test iterator throws NoSuchElementException at end of iteration
+   */
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { NoSuchElementException.class })
+  public void testLastNext() throws NoSuchElementException
+  {
+    AllColsIterator it = new AllColsIterator(0, 3, hiddenCols);
+    while (it.hasNext())
+    {
+      it.next();
+    }
+    it.next();
+  }
+
+  /*
+   * Test iterator throws UnsupportedOperationException on call to remove
+   */
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { UnsupportedOperationException.class })
+  public void testRemove() throws UnsupportedOperationException
+  {
+    AllColsIterator it = new AllColsIterator(0, 3, hiddenCols);
+    it.remove();
+  }
+}
diff --git a/test/jalview/datamodel/AllRowsIteratorTest.java b/test/jalview/datamodel/AllRowsIteratorTest.java
new file mode 100644 (file)
index 0000000..fd1d29d
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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.datamodel;
+
+import static org.testng.Assert.assertTrue;
+
+import jalview.analysis.AlignmentGenerator;
+
+import java.util.Hashtable;
+import java.util.NoSuchElementException;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class AllRowsIteratorTest
+{
+  AlignmentI al;
+
+  Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences = new Hashtable<SequenceI, SequenceCollectionI>();
+
+  @BeforeClass
+  public void setup()
+  {
+    // create random alignment
+    AlignmentGenerator gen = new AlignmentGenerator(false);
+    al = gen.generate(20, 15, 123, 5, 5);
+    if (!hiddenRepSequences.isEmpty())
+    {
+      al.getHiddenSequences().showAll(hiddenRepSequences);
+    }
+    hideSequences(2, 4);
+  }
+
+  /*
+   * Test iterator iterates through collection correctly
+   */
+  @Test(groups = { "Functional" })
+  public void testHasNextAndNext()
+  {
+    AllRowsIterator it = new AllRowsIterator(0, 3, al);
+    int count = 0;
+    while (it.hasNext())
+    {
+      it.next();
+      count++;
+    }
+    assertTrue(count == 4, "hasNext() is false after 4 iterations");
+  }
+
+  /*
+   * Test iterator throws NoSuchElementException at end of iteration
+   */
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { NoSuchElementException.class })
+  public void testLastNext() throws NoSuchElementException
+  {
+    AllRowsIterator it = new AllRowsIterator(0, 3, al);
+    while (it.hasNext())
+    {
+      it.next();
+    }
+    it.next();
+  }
+
+  /*
+   * Test iterator throws UnsupportedOperationException on call to remove
+   */
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { UnsupportedOperationException.class })
+  public void testRemove() throws UnsupportedOperationException
+  {
+    AllRowsIterator it = new AllRowsIterator(0, 3, al);
+    it.remove();
+  }
+
+
+  /*
+   * 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/datamodel/VisibleColsIteratorTest.java b/test/jalview/datamodel/VisibleColsIteratorTest.java
new file mode 100644 (file)
index 0000000..c07b3c9
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * 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.datamodel;
+
+import static org.testng.Assert.assertTrue;
+
+import java.util.NoSuchElementException;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class VisibleColsIteratorTest
+{
+  ColumnSelection hiddenCols;
+
+  ColumnSelection hiddenColsAtStart;
+
+  @BeforeClass
+  public void setup()
+  {
+    hiddenCols = new ColumnSelection();
+    hiddenCols.hideColumns(2, 4);
+
+    hiddenColsAtStart = new ColumnSelection();
+    hiddenColsAtStart.hideColumns(0, 2);
+  }
+
+  /*
+   * Test iterator iterates correctly through the columns
+   * when alignment has hidden cols
+   */
+  @Test(groups = { "Functional" })
+  public void testHasNextAndNextWithHidden()
+  {
+    VisibleColsIterator it = new VisibleColsIterator(0, 6, hiddenCols);
+    int count = 0;
+    while (it.hasNext())
+    {
+      it.next();
+      count++;
+    }
+    assertTrue(count == 4, "hasNext() is false after 4 iterations");
+  }
+
+  /*
+   * Test iterator iterates correctly through the columns
+   * when alignment has no hidden cols
+   */
+  @Test(groups = { "Functional" })
+  public void testHasNextAndNextNoHidden()
+  {
+    VisibleColsIterator it2 = new VisibleColsIterator(0, 3,
+            new ColumnSelection());
+    int count = 0;
+    while (it2.hasNext())
+    {
+      it2.next();
+      count++;
+    }
+    assertTrue(count == 4, "hasNext() is false after 4 iterations");
+  }
+
+  /*
+   * Test iterator iterates correctly through the columns
+   * when alignment has hidden cols at start
+   */
+  @Test(groups = { "Functional" })
+  public void testHasNextAndNextStartHidden()
+  {
+    VisibleColsIterator it3 = new VisibleColsIterator(0, 6,
+            hiddenColsAtStart);
+    int count = 0;
+    while (it3.hasNext())
+    {
+      it3.next();
+      count++;
+    }
+    assertTrue(count == 4, "hasNext() is false after 4 iterations");
+  }
+
+  /*
+   * Test iterator iterates correctly through the columns
+   * when alignment has hidden cols at end
+   */
+  @Test(groups = { "Functional" })
+  public void testHasNextAndNextEndHidden()
+  {
+    VisibleColsIterator it4 = new VisibleColsIterator(0, 4, hiddenCols);
+    int count = 0;
+    while (it4.hasNext())
+    {
+      it4.next();
+      count++;
+    }
+    assertTrue(count == 2, "hasNext() is false after 2 iterations");
+
+  }
+
+  /*
+   * Test iterator always throws NoSuchElementException at end of iteration
+   * when alignment has hidden cols
+   */
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { NoSuchElementException.class })
+  public void testLastNextWithHidden() throws NoSuchElementException
+  {
+    VisibleColsIterator it = new VisibleColsIterator(0, 3, hiddenCols);
+    while (it.hasNext())
+    {
+      it.next();
+    }
+    it.next();
+  }
+
+  /*
+   * Test iterator always throws NoSuchElementException at end of iteration
+   * when alignment has no hidden cols
+   */
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { NoSuchElementException.class })
+  public void testLastNextNoHidden() throws NoSuchElementException
+  {
+    VisibleColsIterator it2 = new VisibleColsIterator(0, 3,
+            new ColumnSelection());
+    while (it2.hasNext())
+    {
+      it2.next();
+    }
+    it2.next();
+  }
+
+  /*
+   * Test iterator always throws NoSuchElementException at end of iteration
+   * when alignment has hidden cols at start
+   */
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { NoSuchElementException.class })
+  public void testLastNextStartHidden() throws NoSuchElementException
+  {
+    VisibleColsIterator it3 = new VisibleColsIterator(0, 6,
+            hiddenColsAtStart);
+    while (it3.hasNext())
+    {
+      it3.next();
+    }
+    it3.next();
+  }
+
+  /*
+   * Test iterator always throws NoSuchElementException at end of iteration
+   * when alignment has hidden cols at end
+   */
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { NoSuchElementException.class })
+  public void testLastNextEndHidden() throws NoSuchElementException
+  {
+    VisibleColsIterator it4 = new VisibleColsIterator(0, 4, hiddenCols);
+    while (it4.hasNext())
+    {
+      it4.next();
+    }
+    it4.next();
+  }
+
+  /*
+   * Test calls to remove throw UnsupportedOperationException
+   */
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { UnsupportedOperationException.class })
+  public void testRemove() throws UnsupportedOperationException
+  {
+    VisibleColsIterator it = new VisibleColsIterator(0, 3, hiddenCols);
+    it.remove();
+  }
+}
diff --git a/test/jalview/datamodel/VisibleRowsIteratorTest.java b/test/jalview/datamodel/VisibleRowsIteratorTest.java
new file mode 100644 (file)
index 0000000..da93dab
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * 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.datamodel;
+
+import static org.testng.Assert.assertTrue;
+
+import jalview.analysis.AlignmentGenerator;
+
+import java.util.Hashtable;
+import java.util.NoSuchElementException;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class VisibleRowsIteratorTest
+{
+  AlignmentI al;
+
+  AlignmentI al2;
+
+  AlignmentI al3;
+
+  Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences = new Hashtable<SequenceI, SequenceCollectionI>();
+
+  Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences2 = new Hashtable<SequenceI, SequenceCollectionI>();
+
+  @BeforeClass
+  public void setup()
+  {
+    // create random alignment
+    AlignmentGenerator gen = new AlignmentGenerator(false);
+    al = gen.generate(20, 15, 123, 5, 5);
+    if (!hiddenRepSequences.isEmpty())
+    {
+      al.getHiddenSequences().showAll(hiddenRepSequences);
+    }
+    hideSequences(al, hiddenRepSequences, 2, 4);
+
+    al2 = gen.generate(20, 15, 123, 5, 5);
+    if (!hiddenRepSequences2.isEmpty())
+    {
+      al2.getHiddenSequences().showAll(hiddenRepSequences2);
+    }
+    hideSequences(al2, hiddenRepSequences2, 0, 2);
+
+    al3 = gen.generate(20, 15, 123, 5, 5);
+  }
+
+  /*
+   * Test iterator iterates correctly through the rows
+   * when alignment has hidden rows
+   */
+  @Test(groups = { "Functional" })
+  public void testHasNextAndNextWithHidden()
+  {
+    VisibleRowsIterator it = new VisibleRowsIterator(0, 6, al);
+    int count = 0;
+    while (it.hasNext())
+    {
+      it.next();
+      count++;
+    }
+    assertTrue(count == 4, "hasNext() is false after 4 iterations");
+  }
+
+  /*
+   * Test iterator iterates correctly through the rows
+   * when alignment has no hidden rows
+   */
+  @Test(groups = { "Functional" })
+  public void testHasNextAndNextNoHidden()
+  {
+    VisibleRowsIterator it = new VisibleRowsIterator(0, 3, al3);
+    int count = 0;
+    while (it.hasNext())
+    {
+      it.next();
+      count++;
+    }
+    assertTrue(count == 4, "hasNext() is false after 4 iterations");
+  }
+
+  /*
+   * Test iterator iterates correctly through the rows
+   * when alignment has hidden rows at start
+   */
+  @Test(groups = { "Functional" })
+  public void testHasNextAndNextStartHidden()
+  {
+    VisibleRowsIterator it = new VisibleRowsIterator(0, 6, al2);
+    int count = 0;
+    while (it.hasNext())
+    {
+      it.next();
+      count++;
+    }
+    assertTrue(count == 4, "hasNext() is false after 4 iterations");
+  }
+
+  /*
+   * Test iterator iterates correctly through the rows
+   * when alignment has hidden rows at end
+   */
+  @Test(groups = { "Functional" })
+  public void testHasNextAndNextEndHidden()
+  {
+    VisibleRowsIterator it = new VisibleRowsIterator(0, 4, al);
+    int count = 0;
+    while (it.hasNext())
+    {
+      it.next();
+      count++;
+    }
+    assertTrue(count == 2, "hasNext() is false after 2 iterations");
+  }
+
+  /*
+   * Test iterator always throws NoSuchElementException at end of iteration
+   * when alignment has hidden rows
+   */
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { NoSuchElementException.class })
+  public void testLastNextWithHidden() throws NoSuchElementException
+  {
+    VisibleRowsIterator it = new VisibleRowsIterator(0, 3, al);
+    while (it.hasNext())
+    {
+      it.next();
+    }
+    it.next();
+  }
+
+  /*
+   * Test iterator always throws NoSuchElementException at end of iteration
+   * when alignment has no hidden rows
+   */
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { NoSuchElementException.class })
+  public void testLastNextNoHidden() throws NoSuchElementException
+  {
+    VisibleRowsIterator it = new VisibleRowsIterator(0, 3, al3);
+    while (it.hasNext())
+    {
+      it.next();
+    }
+    it.next();
+  }
+
+  /*
+   * Test iterator always throws NoSuchElementException at end of iteration
+   * when alignment has hidden rows at start
+   */
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { NoSuchElementException.class })
+  public void testLastNextStartHidden() throws NoSuchElementException
+  {
+    VisibleRowsIterator it = new VisibleRowsIterator(0, 3, al2);
+    while (it.hasNext())
+    {
+      it.next();
+    }
+    it.next();
+  }
+
+  /*
+   * Test iterator always throws NoSuchElementException at end of iteration
+   * when alignment has hidden rows at end
+   */
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { NoSuchElementException.class })
+  public void testLastNextEndHidden() throws NoSuchElementException
+  {
+    VisibleRowsIterator it = new VisibleRowsIterator(0, 4, al);
+    while (it.hasNext())
+    {
+      it.next();
+    }
+    it.next();
+  }
+
+  /*
+   * Test calls to remove throw UnsupportedOperationException
+   */
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { UnsupportedOperationException.class })
+  public void testRemove() throws UnsupportedOperationException
+  {
+    VisibleRowsIterator it = new VisibleRowsIterator(0, 3, al);
+    it.remove();
+  }
+
+  /*
+   * Hide sequences between start and end
+   */
+  private void hideSequences(AlignmentI alignment,
+          Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences,
+          int start, int end)
+  {
+    SequenceI[] allseqs = alignment.getSequencesArray();
+    SequenceGroup theseSeqs = new SequenceGroup();
+
+    for (int i = start; i <= end; i++)
+    {
+      theseSeqs.addSequence(allseqs[i], false);
+      alignment.getHiddenSequences().hideSequence(allseqs[i]);
+    }
+
+    hiddenRepSequences.put(allseqs[start], theseSeqs);
+  }
+}
index 398fec3..dc414fb 100644 (file)
@@ -42,7 +42,7 @@ import org.testng.annotations.Test;
 public class OverviewDimensionsTest
 {
   AlignmentI al;
-  OverviewDimensions od;
+  OverviewDimensionsWithHidden od;
 
   // cached widths and heights
   int boxWidth;
@@ -86,7 +86,7 @@ public class OverviewDimensionsTest
 
     ColumnSelection hiddenCols = new ColumnSelection();
 
-    od = new OverviewDimensions(vpranges, true);
+    od = new OverviewDimensionsWithHidden(vpranges, true);
     // Initial box sizing - default path through code
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
 
@@ -136,7 +136,7 @@ public class OverviewDimensionsTest
     Alignment al1 = new Alignment(seqs1);
     ViewportRanges props = new ViewportRanges(al1);
 
-    OverviewDimensions od = new OverviewDimensions(props, true);
+    OverviewDimensions od = new OverviewDimensionsWithHidden(props, true);
     int scaledHeight = 267;
     assertEquals(od.getGraphHeight(), defaultGraphHeight);
     assertEquals(od.getSequencesHeight(), scaledHeight);
@@ -148,7 +148,7 @@ public class OverviewDimensionsTest
     Alignment al2 = new Alignment(seqs2);
     props = new ViewportRanges(al2);
 
-    od = new OverviewDimensions(props, true);
+    od = new OverviewDimensionsWithHidden(props, true);
     int scaledWidth = 300;
     assertEquals(od.getGraphHeight(), defaultGraphHeight);
     assertEquals(od.getSequencesHeight(), maxSeqHeight);
@@ -161,7 +161,7 @@ public class OverviewDimensionsTest
     Alignment al3 = new Alignment(seqs3);
     props = new ViewportRanges(al3);
 
-    od = new OverviewDimensions(props, true);
+    od = new OverviewDimensionsWithHidden(props, true);
     assertEquals(od.getGraphHeight(), defaultGraphHeight);
     assertEquals(od.getSequencesHeight(), minSeqHeight);
     assertEquals(od.getWidth(), maxWidth);
@@ -173,7 +173,7 @@ public class OverviewDimensionsTest
     Alignment al4 = new Alignment(seqs4);
     props = new ViewportRanges(al4);
 
-    od = new OverviewDimensions(props, true);
+    od = new OverviewDimensionsWithHidden(props, true);
     assertEquals(od.getGraphHeight(), defaultGraphHeight);
     assertEquals(od.getSequencesHeight(), maxSeqHeight);
     assertEquals(od.getWidth(), minWidth);
@@ -182,7 +182,7 @@ public class OverviewDimensionsTest
     Alignment al5 = new Alignment(seqs4);
     props = new ViewportRanges(al5);
 
-    od = new OverviewDimensions(props, false);
+    od = new OverviewDimensionsWithHidden(props, false);
     assertEquals(od.getGraphHeight(), 0);
     assertEquals(od.getSequencesHeight(), maxSeqHeight);
     assertEquals(od.getWidth(), minWidth);
@@ -988,7 +988,7 @@ public class OverviewDimensionsTest
   /*
    * Mouse click as position x,y in overview window
    */
-  private void mouseClick(OverviewDimensions od, int x, int y)
+  private void mouseClick(OverviewDimensionsWithHidden od, int x, int y)
   {
     od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols,
             vpranges);