Merge branch 'bug/JAL-2507_rnasecstrstockholm' into develop
authorJim Procter <jprocter@issues.jalview.org>
Mon, 15 May 2017 16:37:43 +0000 (17:37 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Mon, 15 May 2017 16:37:43 +0000 (17:37 +0100)
125 files changed:
examples/groovy/featureCounter.groovy [deleted file]
examples/groovy/featuresCounter.groovy [new file with mode: 0644]
examples/groovy/multipleFeatureAnnotations.groovy [deleted file]
examples/groovy/visibleFeaturesCounter.groovy [new file with mode: 0644]
help/help.jhm
help/helpTOC.xml
help/html/features/groovy.html
help/html/features/overview.html
help/html/features/splitView.html
help/html/groovy/featureCounter.html [deleted file]
help/html/groovy/featuresCounter.html [new file with mode: 0644]
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/api/AlignViewportI.java
src/jalview/api/AlignmentColsCollectionI.java [new file with mode: 0644]
src/jalview/api/AlignmentRowsCollectionI.java [new file with mode: 0644]
src/jalview/api/ComplexAlignFile.java
src/jalview/api/ViewStyleI.java
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AlignViewport.java
src/jalview/appletgui/AlignmentPanel.java
src/jalview/appletgui/AnnotationColumnChooser.java
src/jalview/appletgui/AnnotationLabels.java
src/jalview/appletgui/AnnotationPanel.java
src/jalview/appletgui/CutAndPasteTransfer.java
src/jalview/appletgui/FontChooser.java
src/jalview/appletgui/IdCanvas.java
src/jalview/appletgui/OverviewCanvas.java [new file with mode: 0644]
src/jalview/appletgui/OverviewPanel.java
src/jalview/appletgui/PCAPanel.java
src/jalview/appletgui/ScalePanel.java
src/jalview/appletgui/SeqCanvas.java
src/jalview/appletgui/SeqPanel.java
src/jalview/appletgui/TreePanel.java
src/jalview/bin/JalviewLite.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/AlignmentAnnotation.java
src/jalview/datamodel/AlignmentI.java
src/jalview/datamodel/AlignmentView.java
src/jalview/datamodel/AllColsCollection.java [new file with mode: 0644]
src/jalview/datamodel/AllColsIterator.java [new file with mode: 0644]
src/jalview/datamodel/AllRowsCollection.java [new file with mode: 0644]
src/jalview/datamodel/AllRowsIterator.java [new file with mode: 0644]
src/jalview/datamodel/CigarArray.java
src/jalview/datamodel/ColumnSelection.java
src/jalview/datamodel/HiddenColumns.java [new file with mode: 0644]
src/jalview/datamodel/HiddenSequences.java
src/jalview/datamodel/SeqCigar.java
src/jalview/datamodel/VisibleColsCollection.java [new file with mode: 0644]
src/jalview/datamodel/VisibleColsIterator.java [new file with mode: 0644]
src/jalview/datamodel/VisibleRowsCollection.java [new file with mode: 0644]
src/jalview/datamodel/VisibleRowsIterator.java [new file with mode: 0644]
src/jalview/ext/jmol/JalviewJmolBinding.java
src/jalview/ext/jmol/JmolCommands.java
src/jalview/ext/rbvi/chimera/ChimeraCommands.java
src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/AlignmentPanel.java
src/jalview/gui/AnnotationColumnChooser.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/AnnotationPanel.java
src/jalview/gui/AppVarna.java
src/jalview/gui/CutAndPasteTransfer.java
src/jalview/gui/FontChooser.java
src/jalview/gui/IdCanvas.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/OverviewCanvas.java [new file with mode: 0644]
src/jalview/gui/OverviewPanel.java
src/jalview/gui/PCAPanel.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/SeqCanvas.java
src/jalview/gui/SeqPanel.java
src/jalview/gui/SequenceRenderer.java
src/jalview/gui/SplitFrame.java
src/jalview/gui/StructureChooser.java
src/jalview/gui/StructureViewerBase.java
src/jalview/gui/TreePanel.java
src/jalview/gui/VamsasApplication.java
src/jalview/io/AnnotationFile.java
src/jalview/io/FileLoader.java
src/jalview/io/FormatAdapter.java
src/jalview/io/HTMLOutput.java
src/jalview/io/HtmlFile.java
src/jalview/io/JSONFile.java
src/jalview/javascript/JsSelectionSender.java
src/jalview/jbgui/GAlignFrame.java
src/jalview/jbgui/GFontChooser.java
src/jalview/jbgui/GStructureChooser.java
src/jalview/renderer/AnnotationRenderer.java
src/jalview/renderer/OverviewRenderer.java [new file with mode: 0644]
src/jalview/renderer/ScaleRenderer.java
src/jalview/structure/SelectionListener.java
src/jalview/structure/StructureSelectionManager.java
src/jalview/structures/models/AAStructureBindingModel.java
src/jalview/util/MappingUtils.java
src/jalview/viewmodel/AlignmentViewport.java
src/jalview/viewmodel/OverviewDimensions.java
src/jalview/viewmodel/OverviewDimensionsHideHidden.java [new file with mode: 0644]
src/jalview/viewmodel/OverviewDimensionsShowHidden.java [new file with mode: 0644]
src/jalview/viewmodel/ViewportRanges.java
src/jalview/viewmodel/styles/ViewStyle.java
src/jalview/workers/AlignmentAnnotationFactory.java
src/jalview/workers/ColumnCounterSetWorker.java [moved from src/jalview/workers/ColumnCounterWorker.java with 61% similarity]
src/jalview/workers/FeatureSetCounterI.java [moved from src/jalview/workers/FeatureCounterI.java with 76% similarity]
src/jalview/ws/jws1/JPredThread.java
src/jalview/ws/jws1/MsaWSThread.java
src/jalview/ws/jws2/MsaWSThread.java
src/jalview/ws/rest/RestClient.java
src/jalview/ws/rest/RestJobThread.java
test/jalview/analysis/DnaTest.java
test/jalview/datamodel/AllColsIteratorTest.java [new file with mode: 0644]
test/jalview/datamodel/AllRowsIteratorTest.java [new file with mode: 0644]
test/jalview/datamodel/ColumnSelectionTest.java
test/jalview/datamodel/HiddenColumnsTest.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/gui/AlignFrameTest.java
test/jalview/io/AnnotationFileIOTest.java
test/jalview/io/JSONFileTest.java
test/jalview/structures/models/AAStructureBindingModelTest.java
test/jalview/util/MappingUtilsTest.java
test/jalview/viewmodel/OverviewDimensionsHideHiddenTest.java [new file with mode: 0644]
test/jalview/viewmodel/OverviewDimensionsShowHiddenTest.java [moved from test/jalview/viewmodel/OverviewDimensionsTest.java with 95% similarity]

diff --git a/examples/groovy/featureCounter.groovy b/examples/groovy/featureCounter.groovy
deleted file mode 100644 (file)
index 9059dd0..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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.
- */
-import jalview.workers.FeatureCounterI;
-import jalview.workers.AlignmentAnnotationFactory;
-
-/*
- * Example script that registers two alignment annotation calculators
- * - one that counts residues in a column with Pfam annotation
- * - one that counts only charged residues with Pfam annotation
- *
- * To try:
- * 1. load uniref50.fa from the examples folder
- * 2. load features onto it from from examples/exampleFeatures.txt
- * 3. Open this script in the Groovy console.
- * 4. Either execute this script from the console, or via Calculate->Run Groovy Script
- * To explore further, try changing this script to count other kinds of occurrences of 
- * residue and sequence features at columns in an alignment.
- */
-
-/*
- * A closure that returns true for any Charged residue
- */
-def isCharged = { residue ->
-    switch(residue) {
-        case ['D', 'd', 'E', 'e', 'H', 'h', 'K', 'k', 'R', 'r']:
-            return true
-    }
-    false
-} 
-
-/*
- * A closure that returns 1 if sequence features include type 'Pfam', else 0
- * Argument should be a list of SequenceFeature 
- */
-def hasPfam = { features -> 
-    for (sf in features)
-    {
-        /*
-         * Here we inspect the type of the sequence feature.
-         * You can also test sf.description, sf.score, sf.featureGroup,
-         * sf.strand, sf.phase, sf.begin, sf.end
-         * or sf.getValue(attributeName) for GFF 'column 9' properties
-         */
-        if ("Pfam".equals(sf.type))
-        {
-            return true
-        }
-    }
-    false
-}
-
-/*
- * Closure that computes an annotation based on 
- * presence of particular residues and features
- * Parameters are
- * - the name (label) for the alignment annotation
- * - the description (tooltip) for the annotation
- * - a closure (groovy function) that tests whether to include a residue
- * - a closure that tests whether to increment count based on sequence features  
- */
-def getColumnCounter = { name, desc, acceptResidue, acceptFeatures ->
-    [
-     getName: { name }, 
-     getDescription: { desc },
-     getMinColour: { [0, 255, 255] }, // cyan
-     getMaxColour: { [0, 0, 255] }, // blue
-     count: 
-         { res, feats -> 
-            def c = 0
-            if (acceptResidue.call(res))
-            {
-                if (acceptFeatures.call(feats))
-                {
-                    c++
-                }
-            }
-            c
-         }
-     ] as FeatureCounterI
-}
-
-/*
- * Define an annotation row that counts any residue with Pfam domain annotation
- */
-def pfamAnnotation = getColumnCounter("Pfam", "Count of residues with Pfam domain annotation", {true}, hasPfam)
-
-/*
- * Define an annotation row that counts charged residues with Pfam domain annotation
- */
-def chargedPfamAnnotation = getColumnCounter("Pfam charged", "Count of charged residues with Pfam domain annotation", isCharged, hasPfam)
-
-/*
- * Register the annotations
- */
-AlignmentAnnotationFactory.newCalculator(pfamAnnotation) 
-AlignmentAnnotationFactory.newCalculator(chargedPfamAnnotation)
diff --git a/examples/groovy/featuresCounter.groovy b/examples/groovy/featuresCounter.groovy
new file mode 100644 (file)
index 0000000..dc4c97c
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+import jalview.workers.AlignmentAnnotationFactory;
+import jalview.workers.FeatureSetCounterI;
+
+/*
+ * Example script to compute two alignment annotations
+ * - count of Phosphorylation features
+ * - count of Turn features
+ * To try this, first load example file uniref50.fa and load on features file
+ * exampleFeatures.txt, before running this script
+ *
+ * The script only needs to be run once - it will be registered by Jalview
+ * and recalculated automatically when the alignment changes.
+ * 
+ * Note: The feature api provided by 2.10.2 is not compatible with scripts
+ * that worked with earlier Jalview versions. Apologies for the inconvenience.
+ */
+def annotator = 
+    [
+     getNames: { ['Phosphorylation', 'Turn'] as String[] }, 
+     getDescriptions:  { ['Count of Phosphorylation features', 'Count of Turn features'] as String[] },
+     getMinColour: { [0, 255, 255] as int[] }, // cyan
+     getMaxColour: { [0, 0, 255] as int[] }, // blue
+     count: 
+         { res, feats -> 
+                int phos
+                int turn
+                for (sf in feats)
+                {
+                         /*
+                          * Here we inspect the type of the sequence feature.
+                          * You can also test sf.description, sf.score, sf.featureGroup,
+                          * sf.strand, sf.phase, sf.begin, sf.end
+                          * or sf.getValue(attributeName) for GFF 'column 9' properties
+                          */
+                          if (sf.type.contains('TURN'))
+                   {
+                      turn++
+                   }
+                   if (sf.type.contains('PHOSPHORYLATION'))
+                   {
+                      phos++
+                   }
+                }
+                [phos, turn] as int[]
+         }
+     ] as FeatureSetCounterI
+    
+/*
+ * Register the annotation calculator with Jalview
+ */
+AlignmentAnnotationFactory.newCalculator(annotator) 
diff --git a/examples/groovy/multipleFeatureAnnotations.groovy b/examples/groovy/multipleFeatureAnnotations.groovy
deleted file mode 100644 (file)
index 592c7f5..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-import jalview.workers.AlignmentAnnotationFactory;
-import jalview.workers.AnnotationProviderI;
-import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.Annotation;
-import jalview.util.ColorUtils;
-import jalview.util.Comparison;
-import java.awt.Color;
-
-/*
- * Example script to compute two alignment annotations
- * - count of Phosphorylation features
- * - count of Turn features
- * To try this, first load example file uniref50.fa and load on features file
- * exampleFeatures.txt, before running this script
- *
- * The script only needs to be run once - it will be registered by Jalview
- * and recalculated automatically when the alignment changes.
- */
-
-/*
- * A closure that returns true if value includes "PHOSPHORYLATION"
- */
-def phosCounter = { type ->    type.contains("PHOSPHORYLATION") }
-
-/*
- * A closure that returns true if value includes "TURN"
- */
-def turnCounter = { type ->    type.contains("TURN") }
-
-/*
- * A closure that computes and returns an array of Annotation values,
- * one for each column of the alignment
- */
-def getAnnotations(al, fr, counter) 
-{
-    def width = al.width
-    def counts = new int[width] 
-    def max = 0
-    
-    /*
-     * count features in each column, record the maximum value
-     */
-    for (col = 0 ; col < width ; col++)
-    {
-        def count = 0
-        for (row = 0 ; row < al.height ; row++)
-        {
-            seq = al.getSequenceAt(row)
-            if (seq != null && col < seq.getLength())
-            {
-                def res = seq.getCharAt(col)
-                if (!Comparison.isGap(res))
-                {
-                    pos = seq.findPosition(col)
-                    features = fr.findFeaturesAtRes(seq, pos)
-                    for (feature in features)
-                    {
-                        if (counter.call(feature.type))
-                        {
-                            count++
-                        }
-                    }
-                }
-            }
-        }
-        counts[col] = count
-        if (count > max)
-        {
-            max = count
-        }
-    }
-    
-    /*
-     * make the Annotation objects, with a graduated colour scale 
-     * (from min value to max value) for the histogram bars 
-     */
-    def zero = '0' as char
-    def anns = new Annotation[width] 
-    for (col = 0 ; col < width ; col++)
-    {
-        def c = counts[col]
-        if (c > 0)
-        {
-            Color color = ColorUtils.getGraduatedColour(c, 0, Color.cyan,
-                max, Color.blue)
-            anns[col] = AlignmentAnnotationFactory.newAnnotation(String.valueOf(c),
-                String.valueOf(c), zero, c, color)
-        }
-    }
-    anns
-}
-
-/*
- * Define the method that performs the calculations, and builds two
- * AlignmentAnnotation objects
- */
-def annotator = 
-    [ calculateAnnotation: { al, fr ->
-        def phosAnns = getAnnotations(al, fr, phosCounter)
-        def ann1 = AlignmentAnnotationFactory.newAlignmentAnnotation("Phosphorylation", "Count of Phosphorylation features", phosAnns)
-        def turnAnns = getAnnotations(al, fr, turnCounter)
-        def ann2 = AlignmentAnnotationFactory.newAlignmentAnnotation("Turn", "Count of Turn features", turnAnns)
-        return [ann1, ann2]
-      } 
-    ] as AnnotationProviderI
-    
-/*
- * Register the annotation calculator with Jalview
- */
-AlignmentAnnotationFactory.newCalculator(annotator) 
diff --git a/examples/groovy/visibleFeaturesCounter.groovy b/examples/groovy/visibleFeaturesCounter.groovy
new file mode 100644 (file)
index 0000000..b3180f8
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+import jalview.bin.Jalview
+import jalview.workers.FeatureSetCounterI
+import jalview.workers.AlignmentAnnotationFactory
+
+/*
+ * Demonstration of FeatureSetCounterI
+ * compute annotation tracks counting number of displayed 
+ * features of each type in each column
+ */
+
+/*
+ * discover features on the current view
+ */
+def featuresDisp=Jalview.currentAlignFrame.currentView.featuresDisplayed
+if (featuresDisp == null) {
+    print 'Need at least one feature visible on alignment'
+}
+def visibleFeatures=featuresDisp.visibleFeatures.toList()
+assert 'java.util.ArrayList' == visibleFeatures.class.name
+
+/*
+ * A closure that returns an array of features present 
+ * for each feature type in visibleFeatures
+ * Argument 'features' will be a list of SequenceFeature 
+ */
+def getCounts = 
+    { features -> 
+        int[] obs = new int[visibleFeatures.size]
+        for (sf in features)
+        {
+            /*
+             * Here we inspect the type of the sequence feature.
+             * You can also test sf.description, sf.score, sf.featureGroup,
+             * sf.strand, sf.phase, sf.begin, sf.end
+             * or sf.getValue(attributeName) for GFF 'column 9' properties
+             */
+            int pos = 0
+            for (type in visibleFeatures) 
+            {
+              if (type.equals(sf.type)) 
+              {
+                  obs[pos]++
+              }
+              pos++
+            }
+        }
+        obs
+}
+  
+/*
+ * Define something that counts each visible feature type
+ */
+def columnSetCounter =
+    [
+     getNames: { visibleFeatures as String[] }, 
+     getDescriptions:  { visibleFeatures as String[] },
+     getMinColour: { [0, 255, 255] as int[] }, // cyan
+     getMaxColour: { [0, 0, 255] as int[] }, // blue
+     count: 
+         { res, feats -> 
+             getCounts.call(feats) 
+         }
+     ] as FeatureSetCounterI
+
+/*
+ * and register the counter
+ */
+AlignmentAnnotationFactory.newCalculator(columnSetCounter)
index 984c2d1..ac8fc3f 100755 (executable)
@@ -75,6 +75,7 @@
    <mapID target="jalarchive" url="html/features/jalarchive.html"/>
    <mapID target="multipleviews" url="html/features/multipleViews.html"/>
    <mapID target="splitframe" url="html/features/splitView.html"/>
+   <mapID target="splitframe.mirrorfonts" url="html/features/splitView.html#mirror"/>
    <mapID target="trees" url="html/calculations/tree.html"/>
    <mapID target="treeviewer" url="html/calculations/treeviewer.html"/>
    <mapID target="sorting" url="html/calculations/sorting.html"/>
    
    <mapID target="memory" url="html/memory.html" />
    <mapID target="groovy" url="html/features/groovy.html" />
-   <mapID target="groovy.featurecounter" url="html/groovy/featureCounter.html" />
+   <mapID target="groovy.featurescounter" url="html/groovy/featuresCounter.html" />
    <mapID target="privacy" url="html/privacy.html" />
    <mapID target="vamsas" url="html/vamsas/index.html"/>
    <mapID target="aminoAcids" url="html/misc/aminoAcids.html" />
    <mapID target="homeIcon" url="icons/Home.png" />
    <mapID target="printIcon" url="icons/print.png" />
    <mapID target="printSetupIcon" url="icons/setup.png" />
+   
+   <mapID target="overview" url="features/overview.html" />
 </map>
index 482ccdf..db47351 100755 (executable)
@@ -24,6 +24,9 @@
        <tocitem text="Jalview Documentation" target="home" expand="true">
                        <tocitem text="What's new" target="new" expand="true">
                                <tocitem text="Latest Release Notes" target="release"/>
+                               <tocitem text="Groovy Features Counter example" target="groovy.featurescounter"/>
+                               <tocitem text="Omit hidden regions in Overview" target="overview"/>
+                               <tocitem text="Split Frame View" target="splitframe.mirrorfonts" />
                </tocitem>
                
                <tocitem text="Editing Alignments" target="edit" />
                </tocitem>
                <tocitem text="Viewing RNA structures" target="varna" expand="false"/>
                <tocitem text="Opening URLs from Jalview" target="urllinks" expand="true">
-                   <tocitem text="Configuring URL Links" target="urllinkspref" />
+                   <tocitem text="Configuring URL Links" target="linkspref" />
                </tocitem>
                <tocitem text="VAMSAS Data Exchange" target="vamsas">
                        <!-- what can Jalview share with other apps -->
                <tocitem text="Preferences" target="preferences" />
                <tocitem text="Memory Settings" target="memory" expand="false"/>
                <tocitem text="Scripting with Groovy" target="groovy">
-                       <tocitem text="Groovy Feature Counter example" target="groovy.featurecounter"/>
+                       <tocitem text="Groovy Features Counter example" target="groovy.featurescounter"/>
                </tocitem>
                <tocitem text="Command Line" target="commandline" expand="false">
                        <tocitem text="Command Line Arguments" target="clarguments" />
index 254f92e..d9bf76e 100644 (file)
@@ -108,7 +108,7 @@ print currentAlFrame.getTitle();</pre>
     simplified the alignment analysis programming interface in Jalview
     2.10 to make it easy for you to add your own dynamic annotation
     tracks with Groovy. Have a look at the <a
-      href="../groovy/featureCounter.html">featureCounter.groovy</a>
+      href="../groovy/featuresCounter.html">featuresCounter.groovy</a>
     example for more information.
   </p>
 
index 9d36a1c..4f26592 100755 (executable)
   <p>The red box indicates the currently viewed region of the
     alignment, this may be moved by clicking and dragging with the
     mouse.</p>
+    <p><strong>Right-click</strong> (or CMD-Click) to open the
+    overview's popup menu. This provides an option to include hidden
+    regions in the overview (shown as dark-grey rows and columns). <br/><br/>
+    <em>The option to include/exclude hidden regions in the
+    overview was introduced in Jalview 2.10.2</em>. 
   <p>
     <img src="overview.gif" width="407" height="137">
   </p>
index 03b993c..3862c39 100644 (file)
       alignments, the <strong><a href="../menus/alwformat.html">"Format&#8594;Font"</a></strong>
       menu option has an option 'Scale protein residues to codons'. This
       option will make each protein residue the same width as a DNA
-      codon (so the alignments 'line up' vertically)
+      codon (so the alignments 'line up' vertically).<br/><br/>
+      <a name="mirror"/>The 'Use same 
+      font for cDNA and peptide' checkbox, when enabled, ensures that font or
+       font-size changes in either the cDNA or Protein alignment will also 
+       be mirrored. (<em>Added in 2.10.2</em>)
     </li>
     <li><strong>"View&#8594;Protein"</strong> (in the cDNA panel)
       or <strong>"View&#8594;Nucleotide"</strong> (in the protein panel)
diff --git a/help/html/groovy/featureCounter.html b/help/html/groovy/featureCounter.html
deleted file mode 100644 (file)
index 2ebaf45..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-<html>
-<!--
- * 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.
- -->
-<head>
-<title>Extending Jalview with Groovy - Feature Counter Example</title>
-</head>
-<body>
-  <p>
-    <strong>Extending Jalview with Groovy - A customisable
-      feature counter</strong><br /> <br />The groovy script below shows how to
-    add a new calculation track to a Jalview alignment window.
-  </p>
-  <p>As currently written, it will add two tracks to a protein
-    alignment view which count Pfam features in each column, and ones
-    where a charge residue also occur.</p>
-  <p>To try it for yourself:</p>
-  <ol>
-    <li>Copy and paste it into the groovy script console</li>
-    <li>Load the example Feredoxin project (the one that opens by
-      default when you first launched Jalview)</li>
-    <li>Select <strong>Calculations&#8594;Execute Groovy
-        Script</strong> from the alignment window's menu bar to run the script on
-      the current view.
-    </li>
-  </ol>
-  <em><a
-    href="http://www.jalview.org/examples/groovy/featureCounter.groovy">http://www.jalview.org/examples/groovy/featureCounter.groovy</a>
-    - rendered with <a href="http://hilite.me">hilite.me</a></em>
-  <!-- HTML generated using hilite.me -->
-  <div
-    style="background: #ffffff; overflow: auto; width: auto; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;">
-    <pre style="margin: 0; line-height: 125%">
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * Jalview - A Sequence Alignment Editor and Viewer (Version 2.10)</span>
-<span style="color: #888888"> * Copyright (C) 2016 The Jalview Authors</span>
-<span style="color: #888888"> * </span>
-<span style="color: #888888"> * This file is part of Jalview.</span>
-<span style="color: #888888"> * </span>
-<span style="color: #888888"> * Jalview is free software: you can redistribute it and/or</span>
-<span style="color: #888888"> * modify it under the terms of the GNU General Public License </span>
-<span style="color: #888888"> * as published by the Free Software Foundation, either version 3</span>
-<span style="color: #888888"> * of the License, or (at your option) any later version.</span>
-<span style="color: #888888"> *  </span>
-<span style="color: #888888"> * Jalview is distributed in the hope that it will be useful, but </span>
-<span style="color: #888888"> * WITHOUT ANY WARRANTY; without even the implied warranty </span>
-<span style="color: #888888"> * of MERCHANTABILITY or FITNESS FOR A PARTICULAR </span>
-<span style="color: #888888"> * PURPOSE.  See the GNU General Public License for more details.</span>
-<span style="color: #888888"> * </span>
-<span style="color: #888888"> * You should have received a copy of the GNU General Public License</span>
-<span style="color: #888888"> * along with Jalview.  If not, see &lt;http://www.gnu.org/licenses/&gt;.</span>
-<span style="color: #888888"> * The Jalview Authors are detailed in the &#39;AUTHORS&#39; file.</span>
-<span style="color: #888888"> */</span>
-<span style="color: #008800; font-weight: bold">import</span> <span
-        style="color: #0e84b5; font-weight: bold">jalview.workers.FeatureCounterI</span><span
-        style="color: #333333">;</span>
-<span style="color: #008800; font-weight: bold">import</span> <span
-        style="color: #0e84b5; font-weight: bold">jalview.workers.AlignmentAnnotationFactory</span><span
-        style="color: #333333">;</span>
-
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * Example script that registers two alignment annotation calculators</span>
-<span style="color: #888888"> * - one that counts residues in a column with Pfam annotation</span>
-<span style="color: #888888"> * - one that counts only charged residues with Pfam annotation</span>
-<span style="color: #888888"> *</span>
-<span style="color: #888888"> * To try:</span>
-<span style="color: #888888"> * 1. load uniref50.fa from the examples folder</span>
-<span style="color: #888888"> * 2. load features onto it from from examples/exampleFeatures.txt</span>
-<span style="color: #888888"> * 3. Open this script in the Groovy console.</span>
-<span style="color: #888888"> * 4. Either execute this script from the console, or via Calculate-&gt;Run Groovy Script</span>
-<span style="color: #888888"> </span>
-<span style="color: #888888"> * To explore further, try changing this script to count other kinds of occurrences of </span>
-<span style="color: #888888"> * residue and sequence features at columns in an alignment.</span>
-<span style="color: #888888"> */</span>
-
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * A closure that returns true for any Charged residue</span>
-<span style="color: #888888"> */</span>
-<span style="color: #333399; font-weight: bold">def</span> isCharged <span
-        style="color: #333333">=</span> <span style="color: #333333">{</span> residue <span
-        style="color: #333333">-&gt;</span>
-    <span style="color: #008800; font-weight: bold">switch</span><span
-        style="color: #333333">(</span>residue<span
-        style="color: #333333">)</span> <span style="color: #333333">{</span>
-        <span style="color: #008800; font-weight: bold">case</span> <span
-        style="color: #333333">[</span><span
-        style="background-color: #fff0f0">&#39;D&#39;</span><span
-        style="color: #333333">,</span> <span
-        style="background-color: #fff0f0">&#39;d&#39;</span><span
-        style="color: #333333">,</span> <span
-        style="background-color: #fff0f0">&#39;E&#39;</span><span
-        style="color: #333333">,</span> <span
-        style="background-color: #fff0f0">&#39;e&#39;</span><span
-        style="color: #333333">,</span> <span
-        style="background-color: #fff0f0">&#39;H&#39;</span><span
-        style="color: #333333">,</span> <span
-        style="background-color: #fff0f0">&#39;h&#39;</span><span
-        style="color: #333333">,</span> <span
-        style="background-color: #fff0f0">&#39;K&#39;</span><span
-        style="color: #333333">,</span> <span
-        style="background-color: #fff0f0">&#39;k&#39;</span><span
-        style="color: #333333">,</span> <span
-        style="background-color: #fff0f0">&#39;R&#39;</span><span
-        style="color: #333333">,</span> <span
-        style="background-color: #fff0f0">&#39;r&#39;</span><span
-        style="color: #333333">]:</span>
-            <span style="color: #008800; font-weight: bold">return</span> <span
-        style="color: #008800; font-weight: bold">true</span>
-    <span style="color: #333333">}</span>
-    <span style="color: #008800; font-weight: bold">false</span>
-<span style="color: #333333">}</span> 
-
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * A closure that returns 1 if sequence features include type &#39;Pfam&#39;, else 0</span>
-<span style="color: #888888"> * Argument should be a list of SequenceFeature </span>
-<span style="color: #888888"> */</span>
-<span style="color: #333399; font-weight: bold">def</span> hasPfam <span
-        style="color: #333333">=</span> <span style="color: #333333">{</span> features <span
-        style="color: #333333">-&gt;</span> 
-    <span style="color: #008800; font-weight: bold">for</span> <span
-        style="color: #333333">(</span>sf <span
-        style="color: #008800; font-weight: bold">in</span> features<span
-        style="color: #333333">)</span>
-    <span style="color: #333333">{</span>
-        <span style="color: #888888">/*</span>
-<span style="color: #888888">         * Here we inspect the type of the sequence feature.</span>
-<span style="color: #888888">         * You can also test sf.description, sf.score, sf.featureGroup,</span>
-<span style="color: #888888">         * sf.strand, sf.phase, sf.begin, sf.end</span>
-<span style="color: #888888">         * or sf.getValue(attributeName) for GFF &#39;column 9&#39; properties</span>
-<span style="color: #888888">         */</span>
-        <span style="color: #008800; font-weight: bold">if</span> <span
-        style="color: #333333">(</span><span
-        style="background-color: #fff0f0">&quot;Pfam&quot;</span><span
-        style="color: #333333">.</span><span style="color: #0000CC">equals</span><span
-        style="color: #333333">(</span>sf<span style="color: #333333">.</span><span
-        style="color: #0000CC">type</span><span style="color: #333333">))</span>
-        <span style="color: #333333">{</span>
-            <span style="color: #008800; font-weight: bold">return</span> <span
-        style="color: #008800; font-weight: bold">true</span>
-        <span style="color: #333333">}</span>
-    <span style="color: #333333">}</span>
-    <span style="color: #008800; font-weight: bold">false</span>
-<span style="color: #333333">}</span>
-
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * Closure that computes an annotation based on </span>
-<span style="color: #888888"> * presence of particular residues and features</span>
-<span style="color: #888888"> * Parameters are</span>
-<span style="color: #888888"> * - the name (label) for the alignment annotation</span>
-<span style="color: #888888"> * - the description (tooltip) for the annotation</span>
-<span style="color: #888888"> * - a closure (groovy function) that tests whether to include a residue</span>
-<span style="color: #888888"> * - a closure that tests whether to increment count based on sequence features  </span>
-<span style="color: #888888"> */</span>
-<span style="color: #333399; font-weight: bold">def</span> getColumnCounter <span
-        style="color: #333333">=</span> <span style="color: #333333">{</span> name<span
-        style="color: #333333">,</span> desc<span style="color: #333333">,</span> acceptResidue<span
-        style="color: #333333">,</span> acceptFeatures <span
-        style="color: #333333">-&gt;</span>
-    <span style="color: #333333">[</span>
-     <span style="color: #997700; font-weight: bold">getName:</span> <span
-        style="color: #333333">{</span> name <span
-        style="color: #333333">},</span> 
-     <span style="color: #997700; font-weight: bold">getDescription:</span> <span
-        style="color: #333333">{</span> desc <span
-        style="color: #333333">},</span>
-     <span style="color: #997700; font-weight: bold">getMinColour:</span> <span
-        style="color: #333333">{</span> <span style="color: #333333">[</span><span
-        style="color: #0000DD; font-weight: bold">0</span><span
-        style="color: #333333">,</span> <span
-        style="color: #0000DD; font-weight: bold">255</span><span
-        style="color: #333333">,</span> <span
-        style="color: #0000DD; font-weight: bold">255</span><span
-        style="color: #333333">]</span> <span style="color: #333333">},</span> <span
-        style="color: #888888">// cyan</span>
-     <span style="color: #997700; font-weight: bold">getMaxColour:</span> <span
-        style="color: #333333">{</span> <span style="color: #333333">[</span><span
-        style="color: #0000DD; font-weight: bold">0</span><span
-        style="color: #333333">,</span> <span
-        style="color: #0000DD; font-weight: bold">0</span><span
-        style="color: #333333">,</span> <span
-        style="color: #0000DD; font-weight: bold">255</span><span
-        style="color: #333333">]</span> <span style="color: #333333">},</span> <span
-        style="color: #888888">// blue</span>
-     <span style="color: #997700; font-weight: bold">count:</span> 
-         <span style="color: #333333">{</span> res<span
-        style="color: #333333">,</span> feats <span
-        style="color: #333333">-&gt;</span> 
-            <span style="color: #333399; font-weight: bold">def</span> c <span
-        style="color: #333333">=</span> <span
-        style="color: #0000DD; font-weight: bold">0</span>
-            <span style="color: #008800; font-weight: bold">if</span> <span
-        style="color: #333333">(</span>acceptResidue<span
-        style="color: #333333">.</span><span style="color: #0000CC">call</span><span
-        style="color: #333333">(</span>res<span style="color: #333333">))</span>
-            <span style="color: #333333">{</span>
-                <span style="color: #008800; font-weight: bold">if</span> <span
-        style="color: #333333">(</span>acceptFeatures<span
-        style="color: #333333">.</span><span style="color: #0000CC">call</span><span
-        style="color: #333333">(</span>feats<span style="color: #333333">))</span>
-                <span style="color: #333333">{</span>
-                    c<span style="color: #333333">++</span>
-                <span style="color: #333333">}</span>
-            <span style="color: #333333">}</span>
-            c
-         <span style="color: #333333">}</span>
-     <span style="color: #333333">]</span> <span
-        style="color: #008800; font-weight: bold">as</span> FeatureCounterI
-<span style="color: #333333">}</span>
-
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * Define an annotation row that counts any residue with Pfam domain annotation</span>
-<span style="color: #888888"> */</span>
-<span style="color: #333399; font-weight: bold">def</span> pfamAnnotation <span
-        style="color: #333333">=</span> getColumnCounter<span
-        style="color: #333333">(</span><span
-        style="background-color: #fff0f0">&quot;Pfam&quot;</span><span
-        style="color: #333333">,</span> <span
-        style="background-color: #fff0f0">&quot;Count of residues with Pfam domain annotation&quot;</span><span
-        style="color: #333333">,</span> <span style="color: #333333">{</span><span
-        style="color: #008800; font-weight: bold">true</span><span
-        style="color: #333333">},</span> hasPfam<span
-        style="color: #333333">)</span>
-
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * Define an annotation row that counts charged residues with Pfam domain annotation</span>
-<span style="color: #888888"> */</span>
-<span style="color: #333399; font-weight: bold">def</span> chargedPfamAnnotation <span
-        style="color: #333333">=</span> getColumnCounter<span
-        style="color: #333333">(</span><span
-        style="background-color: #fff0f0">&quot;Pfam charged&quot;</span><span
-        style="color: #333333">,</span> <span
-        style="background-color: #fff0f0">&quot;Count of charged residues with Pfam domain annotation&quot;</span><span
-        style="color: #333333">,</span> isCharged<span
-        style="color: #333333">,</span> hasPfam<span
-        style="color: #333333">)</span>
-
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * Register the annotations</span>
-<span style="color: #888888"> */</span>
-AlignmentAnnotationFactory<span style="color: #333333">.</span><span
-        style="color: #0000CC">newCalculator</span><span
-        style="color: #333333">(</span>pfamAnnotation<span
-        style="color: #333333">)</span> 
-AlignmentAnnotationFactory<span style="color: #333333">.</span><span
-        style="color: #0000CC">newCalculator</span><span
-        style="color: #333333">(</span>chargedPfamAnnotation<span
-        style="color: #333333">)</span>
-</pre>
-  </div>
-</body>
-</html>
diff --git a/help/html/groovy/featuresCounter.html b/help/html/groovy/featuresCounter.html
new file mode 100644 (file)
index 0000000..3b6705b
--- /dev/null
@@ -0,0 +1,123 @@
+<html>
+<!--
+ * 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.
+ -->
+<head>
+<title>Extending Jalview with Groovy - Feature Counter Example</title>
+</head>
+<body>
+  <p>
+    <strong>Extending Jalview with Groovy - A customisable
+      feature counter</strong><br /> <br />The groovy script below shows how to
+    add a new calculation track to a Jalview alignment window.
+  </p>
+  <p>As currently written, it will add two tracks to a protein
+    alignment view which count Pfam features in each column, and ones
+    where a charge residue also occur.</p>
+  <p>To try it for yourself:</p>
+  <ol>
+    <li>Copy and paste it into the groovy script console</li>
+    <li>Load the example Feredoxin project (the one that opens by
+      default when you first launched Jalview)</li>
+    <li>Select <strong>Calculations&#8594;Execute Groovy
+        Script</strong> from the alignment window's menu bar to run the script on
+      the current view.
+    </li>
+  </ol>
+  <strong>Please note: The 2.10.2 feature counting interface is not compatible with earlier versions.</strong><br/><br/>
+  <em><a
+    href="http://www.jalview.org/examples/groovy/featuresCounter.groovy">http://www.jalview.org/examples/groovy/featuresCounter.groovy</a>
+    - rendered with <a href="http://hilite.me">hilite.me</a></em>
+  <!-- HTML generated using hilite.me --><div style="background: #f8f8f8; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #408080; font-style: italic">/*</span>
+<span style="color: #408080; font-style: italic"> * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)</span>
+<span style="color: #408080; font-style: italic"> * Copyright (C) $$Year-Rel$$ The Jalview Authors</span>
+<span style="color: #408080; font-style: italic"> * </span>
+<span style="color: #408080; font-style: italic"> * This file is part of Jalview.</span>
+<span style="color: #408080; font-style: italic"> * </span>
+<span style="color: #408080; font-style: italic"> * Jalview is free software: you can redistribute it and/or</span>
+<span style="color: #408080; font-style: italic"> * modify it under the terms of the GNU General Public License </span>
+<span style="color: #408080; font-style: italic"> * as published by the Free Software Foundation, either version 3</span>
+<span style="color: #408080; font-style: italic"> * of the License, or (at your option) any later version.</span>
+<span style="color: #408080; font-style: italic"> *  </span>
+<span style="color: #408080; font-style: italic"> * Jalview is distributed in the hope that it will be useful, but </span>
+<span style="color: #408080; font-style: italic"> * WITHOUT ANY WARRANTY; without even the implied warranty </span>
+<span style="color: #408080; font-style: italic"> * of MERCHANTABILITY or FITNESS FOR A PARTICULAR </span>
+<span style="color: #408080; font-style: italic"> * PURPOSE.  See the GNU General Public License for more details.</span>
+<span style="color: #408080; font-style: italic"> * </span>
+<span style="color: #408080; font-style: italic"> * You should have received a copy of the GNU General Public License</span>
+<span style="color: #408080; font-style: italic"> * along with Jalview.  If not, see &lt;http://www.gnu.org/licenses/&gt;.</span>
+<span style="color: #408080; font-style: italic"> * The Jalview Authors are detailed in the &#39;AUTHORS&#39; file.</span>
+<span style="color: #408080; font-style: italic"> */</span>
+
+<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">jalview.workers.AlignmentAnnotationFactory</span><span style="color: #666666">;</span>
+<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">jalview.workers.FeatureSetCounterI</span><span style="color: #666666">;</span>
+
+<span style="color: #408080; font-style: italic">/*</span>
+<span style="color: #408080; font-style: italic"> * Example script to compute two alignment annotations</span>
+<span style="color: #408080; font-style: italic"> * - count of Phosphorylation features</span>
+<span style="color: #408080; font-style: italic"> * - count of Turn features</span>
+<span style="color: #408080; font-style: italic"> * To try this, first load example file uniref50.fa and load on features file</span>
+<span style="color: #408080; font-style: italic"> * exampleFeatures.txt, before running this script</span>
+<span style="color: #408080; font-style: italic"> *</span>
+<span style="color: #408080; font-style: italic"> * The script only needs to be run once - it will be registered by Jalview</span>
+<span style="color: #408080; font-style: italic"> * and recalculated automatically when the alignment changes.</span>
+<span style="color: #408080; font-style: italic"> * </span>
+<span style="color: #408080; font-style: italic"> * Note: The feature api provided by 2.10.2 is not compatible with scripts</span>
+<span style="color: #408080; font-style: italic"> * that worked with earlier Jalview versions. Apologies for the inconvenience.</span>
+<span style="color: #408080; font-style: italic"> */</span>
+<span style="color: #B00040">def</span> annotator <span style="color: #666666">=</span> 
+    <span style="color: #666666">[</span>
+     <span style="color: #A0A000">getNames:</span> <span style="color: #666666">{</span> <span style="color: #666666">[</span><span style="color: #BA2121">&#39;Phosphorylation&#39;</span><span style="color: #666666">,</span> <span style="color: #BA2121">&#39;Turn&#39;</span><span style="color: #666666">]</span> <span style="color: #008000; font-weight: bold">as</span> String<span style="color: #666666">[]</span> <span style="color: #666666">},</span> 
+     <span style="color: #A0A000">getDescriptions:</span>  <span style="color: #666666">{</span> <span style="color: #666666">[</span><span style="color: #BA2121">&#39;Count of Phosphorylation features&#39;</span><span style="color: #666666">,</span> <span style="color: #BA2121">&#39;Count of Turn features&#39;</span><span style="color: #666666">]</span> <span style="color: #008000; font-weight: bold">as</span> String<span style="color: #666666">[]</span> <span style="color: #666666">},</span>
+     <span style="color: #A0A000">getMinColour:</span> <span style="color: #666666">{</span> <span style="color: #666666">[0,</span> <span style="color: #666666">255,</span> <span style="color: #666666">255]</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #B00040">int</span><span style="color: #666666">[]</span> <span style="color: #666666">},</span> <span style="color: #408080; font-style: italic">// cyan</span>
+     <span style="color: #A0A000">getMaxColour:</span> <span style="color: #666666">{</span> <span style="color: #666666">[0,</span> <span style="color: #666666">0,</span> <span style="color: #666666">255]</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #B00040">int</span><span style="color: #666666">[]</span> <span style="color: #666666">},</span> <span style="color: #408080; font-style: italic">// blue</span>
+     <span style="color: #A0A000">count:</span> 
+         <span style="color: #666666">{</span> res<span style="color: #666666">,</span> feats <span style="color: #666666">-&gt;</span> 
+                <span style="color: #B00040">int</span> phos
+                <span style="color: #B00040">int</span> turn
+                <span style="color: #0000FF">for</span> <span style="color: #666666">(</span>sf <span style="color: #008000; font-weight: bold">in</span> feats<span style="color: #666666">)</span>
+                <span style="color: #666666">{</span>
+                         <span style="color: #408080; font-style: italic">/*</span>
+<span style="color: #408080; font-style: italic">                         * Here we inspect the type of the sequence feature.</span>
+<span style="color: #408080; font-style: italic">                         * You can also test sf.description, sf.score, sf.featureGroup,</span>
+<span style="color: #408080; font-style: italic">                         * sf.strand, sf.phase, sf.begin, sf.end</span>
+<span style="color: #408080; font-style: italic">                         * or sf.getValue(attributeName) for GFF &#39;column 9&#39; properties</span>
+<span style="color: #408080; font-style: italic">                         */</span>
+                          <span style="color: #008000; font-weight: bold">if</span> <span style="color: #666666">(</span>sf<span style="color: #666666">.</span><span style="color: #7D9029">type</span><span style="color: #666666">.</span><span style="color: #7D9029">contains</span><span style="color: #666666">(</span><span style="color: #BA2121">&#39;TURN&#39;</span><span style="color: #666666">))</span>
+                   <span style="color: #666666">{</span>
+                      turn<span style="color: #666666">++</span>
+                   <span style="color: #666666">}</span>
+                   <span style="color: #008000; font-weight: bold">if</span> <span style="color: #666666">(</span>sf<span style="color: #666666">.</span><span style="color: #7D9029">type</span><span style="color: #666666">.</span><span style="color: #7D9029">contains</span><span style="color: #666666">(</span><span style="color: #BA2121">&#39;PHOSPHORYLATION&#39;</span><span style="color: #666666">))</span>
+                   <span style="color: #666666">{</span>
+                      phos<span style="color: #666666">++</span>
+                   <span style="color: #666666">}</span>
+                <span style="color: #666666">}</span>
+                <span style="color: #666666">[</span>phos<span style="color: #666666">,</span> turn<span style="color: #666666">]</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #B00040">int</span><span style="color: #666666">[]</span>
+         <span style="color: #666666">}</span>
+     <span style="color: #666666">]</span> <span style="color: #008000; font-weight: bold">as</span> FeatureSetCounterI
+    
+<span style="color: #408080; font-style: italic">/*</span>
+<span style="color: #408080; font-style: italic"> * Register the annotation calculator with Jalview</span>
+<span style="color: #408080; font-style: italic"> */</span>
+AlignmentAnnotationFactory<span style="color: #666666">.</span><span style="color: #7D9029">newCalculator</span><span style="color: #666666">(</span>annotator<span style="color: #666666">)</span> 
+</pre></div>
+</body>
+</html>
index 88bb376..f6eeb26 100644 (file)
@@ -1225,6 +1225,7 @@ label.configure_displayed_columns = Customise Displayed Options
 label.start_jalview = Start Jalview
 label.biojs_html_export = BioJS
 label.scale_as_cdna = Scale protein residues to codons
+label.font_as_cdna = Use same font for cDNA and peptide
 label.scale_protein_to_cdna = Scale Protein to cDNA
 label.scale_protein_to_cdna_tip = Make protein residues same width as codons in split frame views
 info.select_annotation_row = Select Annotation Row
@@ -1300,9 +1301,10 @@ 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 = Show hidden regions
 label.quality_descr = Alignment Quality based on Blosum62 scores
 label.conservation_descr = Conservation of total alignment less than {0}% gaps
 label.consensus_descr = PID
 label.complement_consensus_descr = PID for cDNA
 label.strucconsensus_descr = PID for base pairs
-label.occupancy_descr = Number of aligned positions 
\ No newline at end of file
+label.occupancy_descr = Number of aligned positions 
index 28c0eaa..ad4d2c4 100644 (file)
@@ -1152,6 +1152,7 @@ label.open_split_window=Abrir ventana dividida
 label.open_split_window?=¿Quieres abrir ventana dividida, con cDNA y proteína vinculadas?
 status.searching_for_pdb_structures=Buscando Estructuras PDB
 label.scale_as_cdna=Adaptar residuos proteicos a los codones
+label.font_as_cdna=Utilizar la misma fuente para nucleotídos y proteicos
 action.export_hidden_sequences=Exportar Secuencias Ocultas
 action.export_hidden_columns=Exportar Columnas Ocultas
 label.found_structures_summary=Resumen de Estructuras Encontradas
@@ -1170,6 +1171,7 @@ label.find=Buscar
 label.select_pdb_file=Seleccionar Fichero PDB
 label.structures_filter=Filtro de Estructuras
 label.scale_protein_to_cdna=Adaptar proteína a cDNA
+label.scale_protein_to_cdna_tip=Hacer a los residuos de proteínas de la misma anchura que los codones en ventanas divididas
 status.loading_cached_pdb_entries=Cargando Entradas PDB en Caché
 label.select=Seleccionar :
 label.select_by_annotation=Seleccionar/Ocultar Columnas por Anotación
@@ -1189,7 +1191,6 @@ label.let_chimera_manage_structure_colours=Deja que Chimera maneje colores de es
 label.fetch_chimera_attributes = Buscar atributos desde Chimera
 label.fetch_chimera_attributes_tip = Copiar atributo de Chimera a característica de Jalview
 label.view_rna_structure=Estructura 2D VARNA
-label.scale_protein_to_cdna_tip=Hacer a los residuos de proteínas de la misma anchura que los codones en ventanas divididas
 label.colour_with_chimera=Colorear con Chimera
 label.superpose_structures = Superponer estructuras
 error.superposition_failed = Superposición fallido: {0}
@@ -1306,3 +1307,4 @@ label.consensus_descr = % Identidad
 label.complement_consensus_descr = % Identidad para cDNA
 label.strucconsensus_descr = % Identidad para pares de bases
 label.occupancy_descr = Número de posiciones alineadas
+label.togglehidden = Show hidden regions
index 8b07340..9e6d1c0 100644 (file)
@@ -36,6 +36,7 @@ import jalview.schemes.ColourSchemeI;
 import jalview.viewmodel.ViewportRanges;
 
 import java.awt.Color;
+import java.awt.Font;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
@@ -470,4 +471,27 @@ public interface AlignViewportI extends ViewStyleI
    * @return search results or null
    */
   SearchResultsI getSearchResults();
+
+  /**
+   * Updates view settings with the given font. You may need to call
+   * AlignmentPanel.fontChanged to update the layout geometry.
+   * 
+   * @param setGrid
+   *          when true, charWidth/height is set according to font metrics
+   */
+  void setFont(Font newFont, boolean b);
+
+  /**
+   * Answers true if split screen protein and cDNA use the same font
+   * 
+   * @return
+   */
+  boolean isProteinFontAsCdna();
+
+  /**
+   * Set the flag for whether split screen protein and cDNA use the same font
+   * 
+   * @return
+   */
+  void setProteinFontAsCdna(boolean b);
 }
diff --git a/src/jalview/api/AlignmentColsCollectionI.java b/src/jalview/api/AlignmentColsCollectionI.java
new file mode 100644 (file)
index 0000000..603da98
--- /dev/null
@@ -0,0 +1,13 @@
+package jalview.api;
+
+public interface AlignmentColsCollectionI extends Iterable<Integer>
+{
+  /**
+   * Answers if the column at the given position is hidden.
+   * 
+   * @param c
+   *          the column index to check
+   * @return true if the column at the position is hidden
+   */
+  public boolean isHidden(int c);
+}
diff --git a/src/jalview/api/AlignmentRowsCollectionI.java b/src/jalview/api/AlignmentRowsCollectionI.java
new file mode 100644 (file)
index 0000000..09b039d
--- /dev/null
@@ -0,0 +1,24 @@
+package jalview.api;
+
+import jalview.datamodel.SequenceI;
+
+public interface AlignmentRowsCollectionI extends Iterable<Integer>
+{
+  /**
+   * Answers if the sequence at the given position is hidden.
+   * 
+   * @param r
+   *          the row index to check
+   * @return true if the sequence at r is hidden
+   */
+  public boolean isHidden(int r);
+
+  /**
+   * Answers the sequence at the given position in the alignment
+   * 
+   * @param r
+   *          the row index to locate
+   * @return the sequence
+   */
+  public SequenceI getSequence(int r);
+}
index 2bf2782..1b579ad 100644 (file)
@@ -20,7 +20,7 @@
  */
 package jalview.api;
 
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceI;
 
 /**
@@ -50,7 +50,7 @@ public interface ComplexAlignFile
    * 
    * @return
    */
-  public ColumnSelection getColumnSelection();
+  public HiddenColumns getHiddenColumns();
 
   /**
    * Retrieves hidden sequences from a complex file parser
index db82dcf..2b554ea 100644 (file)
@@ -257,4 +257,18 @@ public interface ViewStyleI
    * @return
    */
   void setScaleProteinAsCdna(boolean b);
+
+  /**
+   * Answers true if split screen protein and cDNA use the same font
+   * 
+   * @return
+   */
+  boolean isProteinFontAsCdna();
+
+  /**
+   * Set the flag for whether split screen protein and cDNA use the same font
+   * 
+   * @return
+   */
+  void setProteinFontAsCdna(boolean b);
 }
index cd1e1a9..f914108 100644 (file)
@@ -46,6 +46,7 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
@@ -172,14 +173,14 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
   }
 
   public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs,
-          ColumnSelection columnSelection, JalviewLite applet,
+          HiddenColumns hidden, JalviewLite applet,
           String title, boolean embedded)
   {
-    this(al, hiddenSeqs, columnSelection, applet, title, embedded, true);
+    this(al, hiddenSeqs, hidden, applet, title, embedded, true);
   }
 
   public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs,
-          ColumnSelection columnSelection, JalviewLite applet,
+          HiddenColumns hidden, JalviewLite applet,
           String title, boolean embedded, boolean addToDisplay)
   {
     if (applet != null)
@@ -222,9 +223,9 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     {
       viewport.hideSequence(hiddenSeqs);
     }
-    if (columnSelection != null)
+    if (hidden != null)
     {
-      viewport.setColumnSelection(columnSelection);
+      viewport.getAlignment().setHiddenColumns(hidden);
     }
     viewport.setScaleAboveWrapped(scaleAbove.getState());
 
@@ -1927,7 +1928,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     {
       copiedHiddenColumns = new Vector();
       int hiddenOffset = viewport.getSelectionGroup().getStartRes();
-      for (int[] region : viewport.getColumnSelection().getHiddenColumns())
+      for (int[] region : viewport.getAlignment().getHiddenColumns()
+              .getHiddenRegions())
       {
         copiedHiddenColumns.addElement(new int[] {
             region[0] - hiddenOffset, region[1] - hiddenOffset });
@@ -4207,9 +4209,10 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
    * @param csel
    *          - columns to be selected on the alignment
    */
-  public void select(SequenceGroup sel, ColumnSelection csel)
+  public void select(SequenceGroup sel, ColumnSelection csel,
+          HiddenColumns hidden)
   {
-    alignPanel.seqPanel.selection(sel, csel, null);
+    alignPanel.seqPanel.selection(sel, csel, hidden, null);
   }
 
   public void scrollTo(int row, int column)
index afe57e0..9629a5f 100644 (file)
@@ -27,6 +27,7 @@ import jalview.bin.JalviewLite;
 import jalview.commands.CommandI;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.Sequence;
@@ -39,9 +40,9 @@ import jalview.structure.SelectionSource;
 import jalview.structure.StructureSelectionManager;
 import jalview.structure.VamsasSource;
 import jalview.viewmodel.AlignmentViewport;
-import jalview.viewmodel.ViewportRanges;
 
 import java.awt.Font;
+import java.awt.FontMetrics;
 
 public class AlignViewport extends AlignmentViewport implements
         SelectionSource
@@ -71,11 +72,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);
 
@@ -129,7 +129,7 @@ public class AlignViewport extends AlignmentViewport implements
         }
       }
     }
-    setFont(font);
+    setFont(font, true);
 
     MAC = new jalview.util.Platform().isAMac();
 
@@ -272,7 +272,11 @@ public class AlignViewport extends AlignmentViewport implements
 
   private float heightScale = 1, widthScale = 1;
 
-  public void setFont(Font f)
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void setFont(Font f, boolean setGrid)
   {
     font = f;
     if (nullFrame == null)
@@ -281,14 +285,17 @@ public class AlignViewport extends AlignmentViewport implements
       nullFrame.addNotify();
     }
 
-    java.awt.FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font);
-    setCharHeight((int) (heightScale * fm.getHeight()));
-    setCharWidth((int) (widthScale * fm.charWidth('M')));
+    if (setGrid)
+    {
+      FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font);
+      setCharHeight((int) (heightScale * fm.getHeight()));
+      setCharWidth((int) (widthScale * fm.charWidth('M')));
+    }
 
     if (isUpperCasebold())
     {
       Font f2 = new Font(f.getName(), Font.BOLD, f.getSize());
-      fm = nullFrame.getGraphics().getFontMetrics(f2);
+      FontMetrics fm = nullFrame.getGraphics().getFontMetrics(f2);
       setCharWidth((int) (widthScale * (fm.stringWidth("MMMMMMMMMMM") / 10)));
     }
   }
@@ -336,7 +343,8 @@ public class AlignViewport extends AlignmentViewport implements
   {
     getStructureSelectionManager().sendSelection(
             new SequenceGroup(getSelectionGroup()),
-            new ColumnSelection(getColumnSelection()), this);
+            new ColumnSelection(getColumnSelection()),
+            new HiddenColumns(getAlignment().getHiddenColumns()), this);
   }
 
   /**
index 3ae0394..458ed54 100644 (file)
@@ -419,11 +419,12 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     int start = -1;
     if (av.hasHiddenColumns())
     {
-      start = av.getColumnSelection().findColumnPosition(ostart);
-      end = av.getColumnSelection().findColumnPosition(end);
+      AlignmentI al = av.getAlignment();
+      start = al.getHiddenColumns().findColumnPosition(ostart);
+      end = al.getHiddenColumns().findColumnPosition(end);
       if (start == end)
       {
-        if (!scrollToNearest && !av.getColumnSelection().isVisible(ostart))
+        if (!scrollToNearest && !al.getHiddenColumns().isVisible(ostart))
         {
           // don't scroll - position isn't visible
           return false;
@@ -725,7 +726,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
     if (av.hasHiddenColumns())
     {
-      width = av.getColumnSelection().findColumnPosition(width);
+      width = av.getAlignment().getHiddenColumns()
+              .findColumnPosition(width);
     }
     if (x < 0)
     {
@@ -748,8 +750,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
     if ((hextent + x) > width)
     {
-      System.err.println("hextent was " + hextent + " and x was " + x);
-
+      // System.err.println("hextent was " + hextent + " and x was " + x);
+      //
       x = width - hextent;
     }
 
@@ -1009,7 +1011,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
       if (av.hasHiddenColumns())
       {
-        maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+        maxwidth = av.getAlignment().getHiddenColumns()
+                .findColumnPosition(maxwidth) - 1;
       }
 
       int canvasWidth = seqPanel.seqCanvas
index 25ff293..60775d3 100644 (file)
@@ -21,7 +21,7 @@
 package jalview.appletgui;
 
 import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.schemes.AnnotationColourGradient;
 import jalview.util.MessageManager;
 import jalview.viewmodel.annotationfilter.AnnotationFilterParameter;
@@ -110,7 +110,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
 
   private int actionOption = ACTION_OPTION_SELECT;
 
-  private ColumnSelection oldColumnSelection;
+  private HiddenColumns oldHiddenColumns;
 
   public AnnotationColumnChooser()
   {
@@ -140,7 +140,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     {
       return;
     }
-    setOldColumnSelection(av.getColumnSelection());
+    setOldHiddenColumns(av.getAlignment().getHiddenColumns());
     adjusting = true;
     Vector<String> list = new Vector<String>();
     int index = 1;
@@ -289,26 +289,26 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
   @SuppressWarnings("unchecked")
   public void reset()
   {
-    if (this.getOldColumnSelection() != null)
+    if (this.getOldHiddenColumns() != null)
     {
       av.getColumnSelection().clear();
 
       if (av.getAnnotationColumnSelectionState() != null)
       {
-        ColumnSelection oldSelection = av
+        HiddenColumns oldHidden = av
                 .getAnnotationColumnSelectionState()
-                .getOldColumnSelection();
-        if (oldSelection != null && oldSelection.getHiddenColumns() != null
-                && !oldSelection.getHiddenColumns().isEmpty())
+                .getOldHiddenColumns();
+        if (oldHidden != null && oldHidden.getHiddenRegions() != null
+                && !oldHidden.getHiddenRegions().isEmpty())
         {
-          for (Iterator<int[]> itr = oldSelection.getHiddenColumns()
+          for (Iterator<int[]> itr = oldHidden.getHiddenRegions()
                   .iterator(); itr.hasNext();)
           {
             int positions[] = itr.next();
             av.hideColumns(positions[0], positions[1]);
           }
         }
-        av.setColumnSelection(oldSelection);
+        av.getAlignment().setHiddenColumns(oldHidden);
       }
       ap.paintAlignment(true);
     }
@@ -518,16 +518,16 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     ap.paintAlignment(true);
   }
 
-  public ColumnSelection getOldColumnSelection()
+  public HiddenColumns getOldHiddenColumns()
   {
-    return oldColumnSelection;
+    return oldHiddenColumns;
   }
 
-  public void setOldColumnSelection(ColumnSelection currentColumnSelection)
+  public void setOldHiddenColumns(HiddenColumns currentHiddenColumns)
   {
-    if (currentColumnSelection != null)
+    if (currentHiddenColumns != null)
     {
-      this.oldColumnSelection = new ColumnSelection(currentColumnSelection);
+      this.oldHiddenColumns = new HiddenColumns(currentHiddenColumns);
     }
   }
 
index ad74b25..307301d 100755 (executable)
@@ -839,7 +839,8 @@ public class AnnotationLabels extends Panel implements ActionListener,
     if (av.hasHiddenColumns())
     {
       jalview.appletgui.AlignFrame.copiedHiddenColumns = new Vector();
-      for (int[] region : av.getColumnSelection().getHiddenColumns())
+      for (int[] region : av.getAlignment().getHiddenColumns()
+              .getHiddenRegions())
       {
         jalview.appletgui.AlignFrame.copiedHiddenColumns
                 .addElement(new int[] { region[0], region[1] });
index 0ec7adf..5026ee4 100755 (executable)
@@ -165,7 +165,7 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
     {
       for (int index : av.getColumnSelection().getSelected())
       {
-        if (av.getColumnSelection().isVisible(index))
+        if (av.getAlignment().getHiddenColumns().isVisible(index))
         {
           anot[index] = null;
         }
@@ -189,7 +189,7 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
       {
         // TODO: JAL-2001 - provide a fast method to list visible selected
         // columns
-        if (!av.getColumnSelection().isVisible(index))
+        if (!av.getAlignment().getHiddenColumns().isVisible(index))
         {
           continue;
         }
@@ -211,7 +211,7 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
 
       for (int index : av.getColumnSelection().getSelected())
       {
-        if (!av.getColumnSelection().isVisible(index))
+        if (!av.getAlignment().getHiddenColumns().isVisible(index))
         {
           continue;
         }
@@ -271,7 +271,7 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
 
       for (int index : av.getColumnSelection().getSelected())
       {
-        if (!av.getColumnSelection().isVisible(index))
+        if (!av.getAlignment().getHiddenColumns().isVisible(index))
         {
           continue;
         }
@@ -467,7 +467,8 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
 
     if (av.hasHiddenColumns())
     {
-      column = av.getColumnSelection().adjustForHiddenColumns(column);
+      column = av.getAlignment().getHiddenColumns()
+              .adjustForHiddenColumns(column);
     }
 
     if (row > -1 && column < aa[row].annotations.length
index c658734..1e806a5 100644 (file)
@@ -25,7 +25,7 @@ import jalview.api.ComplexAlignFile;
 import jalview.api.FeaturesSourceI;
 import jalview.bin.JalviewLite;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.io.AlignmentFileReaderI;
@@ -257,8 +257,8 @@ public class CutAndPasteTransfer extends Panel implements ActionListener,
 
         if (source instanceof ComplexAlignFile)
         {
-          ColumnSelection colSel = ((ComplexAlignFile) source)
-                  .getColumnSelection();
+            HiddenColumns colSel = ((ComplexAlignFile) source)
+                    .getHiddenColumns();
           SequenceI[] hiddenSeqs = ((ComplexAlignFile) source)
                   .getHiddenSequences();
           boolean showSeqFeatures = ((ComplexAlignFile) source)
index 59f6957..991fb96 100644 (file)
@@ -20,7 +20,6 @@
  */
 package jalview.appletgui;
 
-import jalview.api.ViewStyleI;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
@@ -59,6 +58,8 @@ public class FontChooser extends Panel implements ItemListener
 
   private Checkbox scaleAsCdna = new Checkbox();
 
+  private Checkbox fontAsCdna = new Checkbox();
+
   private Button ok = new Button();
 
   private Button cancel = new Button();
@@ -69,10 +70,20 @@ public class FontChooser extends Panel implements ItemListener
 
   private Font oldFont;
 
+  private Font oldComplementFont;
+
   private int oldCharWidth = 0;
 
+  /*
+   * the state of 'scale protein to cDNA' on opening the dialog
+   */
   private boolean oldScaleProtein = false;
 
+  /*
+   * the state of 'same font for protein and cDNA' on opening the dialog
+   */
+  boolean oldMirrorFont;
+
   private Font lastSelected = null;
 
   private int lastSelStyle = 0;
@@ -83,6 +94,8 @@ public class FontChooser extends Panel implements ItemListener
 
   private Frame frame;
 
+  boolean inSplitFrame = false;
+
   /**
    * Constructor for a TreePanel font chooser
    * 
@@ -112,8 +125,9 @@ public class FontChooser extends Panel implements ItemListener
   {
     this.ap = ap;
     oldFont = ap.av.getFont();
-    oldCharWidth = ap.av.getViewStyle().getCharWidth();
-    oldScaleProtein = ap.av.getViewStyle().isScaleProteinAsCdna();
+    oldCharWidth = ap.av.getCharWidth();
+    oldScaleProtein = ap.av.isScaleProteinAsCdna();
+    oldMirrorFont = ap.av.isProteinFontAsCdna();
 
     try
     {
@@ -152,7 +166,7 @@ public class FontChooser extends Panel implements ItemListener
     this.frame = new Frame();
     frame.add(this);
     jalview.bin.JalviewLite.addFrame(frame,
-            MessageManager.getString("action.change_font"), 440, 115);
+            MessageManager.getString("action.change_font"), 440, 145);
 
     init = false;
   }
@@ -160,6 +174,7 @@ public class FontChooser extends Panel implements ItemListener
   /**
    * Actions on change of font name, size or style.
    */
+  @Override
   public void itemStateChanged(ItemEvent evt)
   {
     final Object source = evt.getSource();
@@ -179,6 +194,29 @@ public class FontChooser extends Panel implements ItemListener
     {
       scaleAsCdna_actionPerformed();
     }
+    else if (source == fontAsCdna)
+    {
+      mirrorFont_actionPerformed();
+    }
+  }
+
+  /**
+   * Action on checking or unchecking 'use same font across split screen'
+   * option. When checked, the font settings are copied to the other half of the
+   * split screen. When unchecked, the other half is restored to its initial
+   * settings.
+   */
+  protected void mirrorFont_actionPerformed()
+  {
+    boolean selected = fontAsCdna.getState();
+    ap.av.setProteinFontAsCdna(selected);
+    ap.av.getCodingComplement().setProteinFontAsCdna(selected);
+
+    if (!selected)
+    {
+      ap.av.getCodingComplement().setFont(oldComplementFont, true);
+    }
+    changeFont();
   }
 
   /**
@@ -205,18 +243,23 @@ public class FontChooser extends Panel implements ItemListener
     if (ap != null)
     {
       ap.av.setScaleProteinAsCdna(oldScaleProtein);
+      ap.av.setProteinFontAsCdna(oldMirrorFont);
+
       if (ap.av.getCodingComplement() != null)
       {
         ap.av.getCodingComplement().setScaleProteinAsCdna(oldScaleProtein);
-        ap.alignFrame.getSplitFrame().repaint();
+        ap.av.getCodingComplement().setProteinFontAsCdna(oldMirrorFont);
+        ap.av.getCodingComplement().setFont(oldComplementFont, true);
+        SplitFrame splitFrame = ap.alignFrame.getSplitFrame();
+        splitFrame.adjustLayout();
+        splitFrame.getComplement(ap.alignFrame).alignPanel.fontChanged();
+        splitFrame.repaint();
       }
 
-      ap.av.setFont(oldFont);
-      ViewStyleI style = ap.av.getViewStyle();
-      if (style.getCharWidth() != oldCharWidth)
+      ap.av.setFont(oldFont, true);
+      if (ap.av.getCharWidth() != oldCharWidth)
       {
-        style.setCharWidth(oldCharWidth);
-        ap.av.setViewStyle(style);
+        ap.av.setCharWidth(oldCharWidth);
       }
       ap.paintAlignment(true);
     }
@@ -276,8 +319,23 @@ public class FontChooser extends Panel implements ItemListener
     }
     else if (ap != null)
     {
-      ap.av.setFont(newFont);
+      ap.av.setFont(newFont, true);
       ap.fontChanged();
+
+      /*
+       * and change font in other half of split frame if any
+       */
+      if (inSplitFrame)
+      {
+        if (fontAsCdna.getState())
+        {
+          ap.av.getCodingComplement().setFont(newFont, true);
+        }
+        SplitFrame splitFrame = ap.alignFrame.getSplitFrame();
+        splitFrame.adjustLayout();
+        splitFrame.getComplement(ap.alignFrame).alignPanel.fontChanged();
+        splitFrame.repaint();
+      }
     }
     // remember last selected
     lastSelected = newFont;
@@ -344,6 +402,11 @@ public class FontChooser extends Panel implements ItemListener
     scaleAsCdna.addItemListener(this);
     scaleAsCdna.setState(ap.av.isScaleProteinAsCdna());
 
+    fontAsCdna.setLabel(MessageManager.getString("label.font_as_cdna"));
+    fontAsCdna.setFont(VERDANA_11PT);
+    fontAsCdna.addItemListener(this);
+    fontAsCdna.setState(ap.av.isProteinFontAsCdna());
+
     ok.setFont(VERDANA_11PT);
     ok.setLabel(MessageManager.getString("action.ok"));
     ok.addActionListener(new ActionListener()
@@ -388,7 +451,8 @@ public class FontChooser extends Panel implements ItemListener
     stylePanel.add(fontStyle, BorderLayout.CENTER);
     sizePanel.add(sizeLabel, BorderLayout.WEST);
     sizePanel.add(fontSize, BorderLayout.CENTER);
-    scalePanel.add(scaleAsCdna, BorderLayout.CENTER);
+    scalePanel.add(scaleAsCdna, BorderLayout.NORTH);
+    scalePanel.add(fontAsCdna, BorderLayout.SOUTH);
     okCancelPanel.add(ok, null);
     okCancelPanel.add(cancel, null);
 
@@ -402,6 +466,9 @@ public class FontChooser extends Panel implements ItemListener
     this.add(optionsPanel, BorderLayout.NORTH);
     if (ap.alignFrame.getSplitFrame() != null)
     {
+      inSplitFrame = true;
+      oldComplementFont = ((AlignViewport) ap.av.getCodingComplement())
+              .getFont();
       this.add(scalePanel, BorderLayout.CENTER);
     }
     this.add(okCancelPanel, BorderLayout.SOUTH);
@@ -416,9 +483,7 @@ public class FontChooser extends Panel implements ItemListener
     ap.av.setScaleProteinAsCdna(scaleAsCdna.getState());
     ap.av.getCodingComplement().setScaleProteinAsCdna(
             scaleAsCdna.getState());
-    ap.alignFrame.getSplitFrame().adjustLayout();
-    ap.paintAlignment(true);
-    ap.alignFrame.getSplitFrame().repaint();
+    changeFont();
   }
 
 }
index abcbd70..db9e661 100755 (executable)
@@ -218,7 +218,8 @@ public class IdCanvas extends Panel
 
       if (av.hasHiddenColumns())
       {
-        maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+        maxwidth = av.getAlignment().getHiddenColumns()
+                .findColumnPosition(maxwidth) - 1;
       }
 
       int annotationHeight = 0;
diff --git a/src/jalview/appletgui/OverviewCanvas.java b/src/jalview/appletgui/OverviewCanvas.java
new file mode 100644 (file)
index 0000000..23e82df
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * 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.renderer.OverviewRenderer;
+import jalview.viewmodel.OverviewDimensions;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Image;
+
+public class OverviewCanvas extends Component
+{
+  // 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 jalview.renderer.seqfeatures.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 jalview.renderer.seqfeatures.FeatureRenderer(av);
+  }
+
+  /**
+   * Update the overview dimensions object used by the canvas (e.g. if we change
+   * from showing hidden columns to hiding them or vice versa)
+   * 
+   * @param overviewDims
+   */
+  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);
+    }
+
+    setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
+
+    OverviewRenderer or = new OverviewRenderer(sr, fr, od);
+    miniMe = nullFrame.createImage(od.getWidth(), od.getHeight());
+    offscreen = nullFrame.createImage(od.getWidth(), od.getHeight());
+
+    miniMe = or.draw(od.getRows(av.getAlignment()),
+            od.getColumns(av.getAlignment()));
+
+    Graphics mg = miniMe.getGraphics();
+
+    // checks for conservation annotation to make sure overview works for DNA
+    // too
+    if (showAnnotation)
+    {
+      mg.translate(0, od.getSequencesHeight());
+      or.drawGraph(mg, av.getAlignmentConservationAnnotation(),
+              av.getCharWidth(), od.getGraphHeight(),
+              od.getColumns(av.getAlignment()));
+      mg.translate(0, -od.getSequencesHeight());
+    }
+    System.gc();
+
+    if (restart)
+    {
+      restart = false;
+      draw(showSequenceFeatures, showAnnotation, transferRenderer);
+    }
+    else
+    {
+      updaterunning = false;
+    }
+  }
+
+  @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..b933d30 100755 (executable)
  */
 package jalview.appletgui;
 
-import jalview.datamodel.SequenceI;
-import jalview.renderer.seqfeatures.FeatureColourFinder;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
 import jalview.viewmodel.OverviewDimensions;
+import jalview.viewmodel.OverviewDimensionsHideHidden;
+import jalview.viewmodel.OverviewDimensionsShowHidden;
 
-import java.awt.Color;
+import java.awt.BorderLayout;
+import java.awt.CheckboxMenuItem;
 import java.awt.Dimension;
-import java.awt.Frame;
-import java.awt.Graphics;
-import java.awt.Image;
 import java.awt.Panel;
+import java.awt.PopupMenu;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
@@ -41,45 +45,29 @@ public class OverviewPanel extends Panel implements Runnable,
 {
   private OverviewDimensions 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 boolean showHidden = true;
 
-  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 OverviewDimensionsShowHidden(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()
     {
@@ -116,6 +104,10 @@ public class OverviewPanel extends Panel implements Runnable,
   @Override
   public void mouseClicked(MouseEvent evt)
   {
+    if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
+    {
+      showPopupMenu(evt);
+    }
   }
 
   @Override
@@ -143,11 +135,20 @@ public class OverviewPanel extends Panel implements Runnable,
 
   private void mouseAction(MouseEvent evt)
   {
-    od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment()
-            .getHiddenSequences(), av.getColumnSelection(), av
-            .getRanges());
-    ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
-    ap.paintAlignment(false);
+    if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
+    {
+      if (!Platform.isAMac())
+      {
+        showPopupMenu(evt);
+      }
+    }
+    else
+    {
+      od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment()
+              .getHiddenSequences(), av.getAlignment().getHiddenColumns());
+      ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
+      ap.paintAlignment(false);
+    }
   }
 
   /**
@@ -155,19 +156,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 +163,30 @@ public class OverviewPanel extends Panel implements Runnable,
     }
     setSize(new Dimension(od.getWidth(), od.getHeight()));
 
+    synchronized (this)
+    {
+      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.seqPanel.seqCanvas.getFeatureRenderer());
     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;
   }
 
   /**
@@ -335,27 +197,54 @@ public class OverviewPanel extends Panel implements Runnable,
   public void setBoxPosition()
   {
     od.setBoxPosition(av.getAlignment()
-            .getHiddenSequences(), av.getColumnSelection(), av.getRanges());
+.getHiddenSequences(), av
+            .getAlignment().getHiddenColumns());
     repaint();
   }
 
-  @Override
-  public void update(Graphics g)
+  /*
+   * Displays the popup menu and acts on user input
+   */
+  private void showPopupMenu(MouseEvent e)
   {
-    paint(g);
+    PopupMenu popup = new PopupMenu();
+    ItemListener menuListener = new ItemListener()
+    {
+      @Override
+      public void itemStateChanged(ItemEvent e)
+      {
+        toggleHiddenColumns();
+      }
+    };
+    CheckboxMenuItem item = new CheckboxMenuItem(
+            MessageManager.getString("label.togglehidden"));
+    item.setState(showHidden);
+    popup.add(item);
+    item.addItemListener(menuListener);
+    this.add(popup);
+    popup.show(this, e.getX(), e.getY());
   }
 
-  @Override
-  public void paint(Graphics g)
+  /*
+   * Toggle overview display between showing hidden columns and hiding hidden columns
+   */
+  private void toggleHiddenColumns()
   {
-    Graphics og = offscreen.getGraphics();
-    if (miniMe != null)
+    if (showHidden)
+    {
+      showHidden = false;
+      od = new OverviewDimensionsHideHidden(av.getRanges(),
+              (av.isShowAnnotation() && av
+                      .getAlignmentConservationAnnotation() != null));
+    }
+    else
     {
-      og.drawImage(miniMe, 0, 0, this);
-      og.setColor(Color.red);
-      od.drawBox(og);
-      g.drawImage(offscreen, 0, 0, this);
+      showHidden = true;
+      od = new OverviewDimensionsShowHidden(av.getRanges(),
+              (av.isShowAnnotation() && av
+                      .getAlignmentConservationAnnotation() != null));
     }
+    oviewCanvas.resetOviewDims(od);
+    updateOverviewImage();
   }
-
 }
index 2d77c59..5dc57f9 100644 (file)
@@ -25,7 +25,7 @@ import jalview.analysis.scoremodels.SimilarityParams;
 import jalview.api.analysis.ScoreModelI;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentView;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SeqCigar;
 import jalview.datamodel.SequenceI;
 import jalview.util.MessageManager;
@@ -281,7 +281,7 @@ public class PCAPanel extends EmbmenuFrame implements Runnable,
     }
     ;
     Object[] alAndColsel = pcaModel.getSeqtrings()
-            .getAlignmentAndColumnSelection(gc);
+            .getAlignmentAndHiddenColumns(gc);
 
     if (alAndColsel != null && alAndColsel[0] != null)
     {
@@ -289,7 +289,8 @@ public class PCAPanel extends EmbmenuFrame implements Runnable,
       AlignFrame af = new AlignFrame(al, av.applet,
               "Original Data for PCA", false);
 
-      af.viewport.setHiddenColumns((ColumnSelection) alAndColsel[1]);
+      af.viewport.getAlignment().setHiddenColumns(
+              (HiddenColumns) alAndColsel[1]);
     }
   }
 
index 15d82a5..22b4e3a 100755 (executable)
@@ -21,6 +21,7 @@
 package jalview.appletgui;
 
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceGroup;
 import jalview.renderer.ScaleRenderer;
 import jalview.renderer.ScaleRenderer.ScaleMark;
@@ -81,7 +82,7 @@ public class ScalePanel extends Panel implements MouseMotionListener,
 
     if (av.hasHiddenColumns())
     {
-      res = av.getColumnSelection().adjustForHiddenColumns(x);
+      res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(x);
     }
     else
     {
@@ -170,7 +171,7 @@ public class ScalePanel extends Panel implements MouseMotionListener,
       });
       pop.add(item);
 
-      if (av.getColumnSelection().hasManyHiddenColumns())
+      if (av.getAlignment().getHiddenColumns().hasManyHiddenColumns())
       {
         item = new MenuItem(MessageManager.getString("action.reveal_all"));
         item.addActionListener(new ActionListener()
@@ -239,7 +240,8 @@ public class ScalePanel extends Panel implements MouseMotionListener,
 
     if (av.hasHiddenColumns())
     {
-      res = av.getColumnSelection().adjustForHiddenColumns(res);
+      res = av.getAlignment().getHiddenColumns()
+              .adjustForHiddenColumns(res);
     }
 
     if (!stretchingGroup)
@@ -280,7 +282,7 @@ public class ScalePanel extends Panel implements MouseMotionListener,
     int res = (evt.getX() / av.getCharWidth())
             + av.getRanges().getStartRes();
     res = Math.max(0, res);
-    res = cs.adjustForHiddenColumns(res);
+    res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res);
     res = Math.min(res, av.getAlignment().getWidth() - 1);
     min = Math.min(res, min);
     max = Math.max(res, max);
@@ -329,10 +331,11 @@ public class ScalePanel extends Panel implements MouseMotionListener,
     int res = (evt.getX() / av.getCharWidth())
             + av.getRanges().getStartRes();
 
-    res = av.getColumnSelection().adjustForHiddenColumns(res);
+    res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res);
 
     reveal = null;
-    for (int[] region : av.getColumnSelection().getHiddenColumns())
+    for (int[] region : av.getAlignment().getHiddenColumns()
+            .getHiddenRegions())
     {
       if (res + 1 == region[0] || res - 1 == region[1])
       {
@@ -370,21 +373,22 @@ public class ScalePanel extends Panel implements MouseMotionListener,
 
     // Fill the selected columns
     ColumnSelection cs = av.getColumnSelection();
+    HiddenColumns hidden = av.getAlignment().getHiddenColumns();
     int avCharWidth = av.getCharWidth();
     int avcharHeight = av.getCharHeight();
     if (cs != null)
     {
       gg.setColor(new Color(220, 0, 0));
-      boolean hasHiddenColumns = cs.hasHiddenColumns();
+      boolean hasHiddenColumns = hidden.hasHiddenColumns();
       for (int sel : cs.getSelected())
       {
         // TODO: JAL-2001 - provide a fast method to list visible selected in a
         // given range
         if (hasHiddenColumns)
         {
-          if (cs.isVisible(sel))
+          if (hidden.isVisible(sel))
           {
-            sel = cs.findColumnPosition(sel);
+            sel = hidden.findColumnPosition(sel);
           }
           else
           {
@@ -443,10 +447,10 @@ public class ScalePanel extends Panel implements MouseMotionListener,
       if (av.getShowHiddenMarkers())
       {
         int widthx = 1 + endx - startx;
-        for (int i = 0; i < cs.getHiddenColumns().size(); i++)
+        for (int i = 0; i < hidden.getHiddenRegions().size(); i++)
         {
 
-          res = cs.findHiddenRegionPosition(i) - startx;
+          res = hidden.findHiddenRegionPosition(i) - startx;
 
           if (res < 0 || res > widthx)
           {
index 89df11f..39382c5 100755 (executable)
@@ -21,6 +21,7 @@
 package jalview.appletgui;
 
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -123,14 +124,17 @@ public class SeqCanvas extends Panel
     ypos += avcharHeight;
     if (av.hasHiddenColumns())
     {
-      startx = av.getColumnSelection().adjustForHiddenColumns(startx);
-      endx = av.getColumnSelection().adjustForHiddenColumns(endx);
+      startx = av.getAlignment().getHiddenColumns()
+              .adjustForHiddenColumns(startx);
+      endx = av.getAlignment().getHiddenColumns()
+              .adjustForHiddenColumns(endx);
     }
 
     int maxwidth = av.getAlignment().getWidth();
     if (av.hasHiddenColumns())
     {
-      maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+      maxwidth = av.getAlignment().getHiddenColumns()
+              .findColumnPosition(maxwidth) - 1;
     }
 
     // WEST SCALE
@@ -170,7 +174,8 @@ public class SeqCanvas extends Panel
 
     if (av.hasHiddenColumns())
     {
-      endx = av.getColumnSelection().adjustForHiddenColumns(endx);
+      endx = av.getAlignment().getHiddenColumns()
+              .adjustForHiddenColumns(endx);
     }
 
     SequenceI seq;
@@ -440,7 +445,8 @@ public class SeqCanvas extends Panel
 
     if (av.hasHiddenColumns())
     {
-      maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+      maxwidth = av.getAlignment().getHiddenColumns()
+              .findColumnPosition(maxwidth) - 1;
     }
 
     while ((ypos <= canvasHeight) && (startRes < maxwidth))
@@ -474,12 +480,13 @@ public class SeqCanvas extends Panel
       }
       if (av.hasHiddenColumns() && av.getShowHiddenMarkers())
       {
+        HiddenColumns hidden = av.getAlignment().getHiddenColumns();
         g.setColor(Color.blue);
         int res;
-        for (int i = 0; i < av.getColumnSelection().getHiddenColumns()
+        for (int i = 0; i < hidden.getHiddenRegions()
                 .size(); i++)
         {
-          res = av.getColumnSelection().findHiddenRegionPosition(i)
+          res = hidden.findHiddenRegionPosition(i)
                   - startRes;
 
           if (res < 0 || res > endx - startRes)
@@ -558,7 +565,8 @@ public class SeqCanvas extends Panel
 
       if (av.hasHiddenColumns())
       {
-        for (int[] region : av.getColumnSelection().getHiddenColumns())
+        HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+        for (int[] region : hidden.getHiddenRegions())
         {
           int hideStart = region[0];
           int hideEnd = region[1];
index 60c53dd..fcae97c 100644 (file)
@@ -25,6 +25,7 @@ import jalview.commands.EditCommand;
 import jalview.commands.EditCommand.Action;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
@@ -180,19 +181,22 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     seqCanvas.cursorX += dx;
     seqCanvas.cursorY += dy;
     if (av.hasHiddenColumns()
-            && !av.getColumnSelection().isVisible(seqCanvas.cursorX))
+            && !av.getAlignment().getHiddenColumns()
+                    .isVisible(seqCanvas.cursorX))
     {
       int original = seqCanvas.cursorX - dx;
       int maxWidth = av.getAlignment().getWidth();
 
-      while (!av.getColumnSelection().isVisible(seqCanvas.cursorX)
+      while (!av.getAlignment().getHiddenColumns()
+              .isVisible(seqCanvas.cursorX)
               && seqCanvas.cursorX < maxWidth && seqCanvas.cursorX > 0)
       {
         seqCanvas.cursorX += dx;
       }
 
       if (seqCanvas.cursorX >= maxWidth
-              || !av.getColumnSelection().isVisible(seqCanvas.cursorX))
+              || !av.getAlignment().getHiddenColumns()
+                      .isVisible(seqCanvas.cursorX))
       {
         seqCanvas.cursorX = original;
       }
@@ -228,6 +232,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     else
     {
       ViewportRanges ranges = av.getRanges();
+      HiddenColumns hidden = av.getAlignment().getHiddenColumns();
       while (seqCanvas.cursorY < ranges.getStartSeq())
       {
         ap.scrollUp(true);
@@ -236,8 +241,8 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       {
         ap.scrollUp(false);
       }
-      while (seqCanvas.cursorX < av.getColumnSelection()
-              .adjustForHiddenColumns(ranges.getStartRes()))
+      while (seqCanvas.cursorX < hidden.adjustForHiddenColumns(ranges
+              .getStartRes()))
       {
 
         if (!ap.scrollRight(false))
@@ -245,8 +250,8 @@ public class SeqPanel extends Panel implements MouseMotionListener,
           break;
         }
       }
-      while (seqCanvas.cursorX > av.getColumnSelection()
-              .adjustForHiddenColumns(ranges.getEndRes()))
+      while (seqCanvas.cursorX > hidden.adjustForHiddenColumns(ranges
+              .getEndRes()))
       {
         if (!ap.scrollRight(true))
         {
@@ -638,7 +643,8 @@ public class SeqPanel extends Panel implements MouseMotionListener,
 
     if (av.hasHiddenColumns())
     {
-      res = av.getColumnSelection().adjustForHiddenColumns(res);
+      res = av.getAlignment().getHiddenColumns()
+              .adjustForHiddenColumns(res);
     }
 
     return res;
@@ -959,7 +965,9 @@ public class SeqPanel extends Panel implements MouseMotionListener,
           fontSize = 1;
         }
 
-        av.setFont(new Font(av.font.getName(), av.font.getStyle(), fontSize));
+        av.setFont(
+                new Font(av.font.getName(), av.font.getStyle(), fontSize),
+                true);
         av.setCharWidth(oldWidth);
       }
       else
@@ -1131,8 +1139,10 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     if (av.hasHiddenColumns())
     {
       fixedColumns = true;
-      int y1 = av.getColumnSelection().getHiddenBoundaryLeft(startres);
-      int y2 = av.getColumnSelection().getHiddenBoundaryRight(startres);
+      int y1 = av.getAlignment().getHiddenColumns()
+              .getHiddenBoundaryLeft(startres);
+      int y2 = av.getAlignment().getHiddenColumns()
+              .getHiddenBoundaryRight(startres);
 
       if ((insertGap && startres > y1 && lastres < y1)
               || (!insertGap && startres < y2 && lastres > y2))
@@ -1203,8 +1213,8 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         {
           if (sg.getSize() == av.getAlignment().getHeight())
           {
-            if ((av.hasHiddenColumns() && startres < av
-                    .getColumnSelection().getHiddenBoundaryRight(startres)))
+            if ((av.hasHiddenColumns() && startres < av.getAlignment()
+                    .getHiddenColumns().getHiddenBoundaryRight(startres)))
             {
               endEditing();
               return;
@@ -1787,7 +1797,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
    */
   @Override
   public void selection(SequenceGroup seqsel, ColumnSelection colsel,
-          SelectionSource source)
+          HiddenColumns hidden, SelectionSource source)
   {
     // TODO: fix this hack - source of messages is align viewport, but SeqPanel
     // handles selection messages...
@@ -1804,7 +1814,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
      * Check for selection in a view of which this one is a dna/protein
      * complement.
      */
-    if (selectionFromTranslation(seqsel, colsel, source))
+    if (selectionFromTranslation(seqsel, colsel, hidden, source))
     {
       return;
     }
@@ -1870,15 +1880,16 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         }
         else
         {
-          av.getColumnSelection().setElementsFrom(colsel);
+          av.getColumnSelection().setElementsFrom(colsel,
+                  av.getAlignment().getHiddenColumns());
         }
       }
       repaint |= av.isColSelChanged(true);
     }
     if (copycolsel
             && av.hasHiddenColumns()
-            && (av.getColumnSelection() == null || av.getColumnSelection()
-                    .getHiddenColumns() == null))
+            && (av.getColumnSelection() == null || av.getAlignment()
+                    .getHiddenColumns().getHiddenRegions() == null))
     {
       System.err.println("Bad things");
     }
@@ -1938,7 +1949,8 @@ public class SeqPanel extends Panel implements MouseMotionListener,
    * @param source
    */
   protected boolean selectionFromTranslation(SequenceGroup seqsel,
-          ColumnSelection colsel, SelectionSource source)
+          ColumnSelection colsel, HiddenColumns hidden,
+          SelectionSource source)
   {
     if (!(source instanceof AlignViewportI))
     {
@@ -1961,9 +1973,13 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     /*
      * Map column selection
      */
-    ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
-            av);
+    // ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
+    // av);
+    ColumnSelection cs = new ColumnSelection();
+    HiddenColumns hs = new HiddenColumns();
+    MappingUtils.mapColumnSelection(colsel, hidden, sourceAv, av, cs, hs);
     av.setColumnSelection(cs);
+    av.getAlignment().setHiddenColumns(hs);
 
     ap.scalePanelHolder.repaint();
     ap.repaint();
index 8b1f79c..c7bf6aa 100644 (file)
@@ -28,7 +28,7 @@ import jalview.analysis.scoremodels.ScoreModels;
 import jalview.analysis.scoremodels.SimilarityParams;
 import jalview.api.analysis.ScoreModelI;
 import jalview.datamodel.Alignment;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceI;
 import jalview.io.NewickFile;
 import jalview.util.MessageManager;
@@ -152,7 +152,7 @@ public class TreePanel extends EmbmenuFrame implements ActionListener,
       }
 
       Object[] alAndColsel = tree.getOriginalData()
-              .getAlignmentAndColumnSelection(gc);
+              .getAlignmentAndHiddenColumns(gc);
 
       if (alAndColsel != null && alAndColsel[0] != null)
       {
@@ -160,7 +160,8 @@ public class TreePanel extends EmbmenuFrame implements ActionListener,
         AlignFrame af = new AlignFrame(al, av.applet,
                 "Original Data for Tree", false);
 
-        af.viewport.setHiddenColumns((ColumnSelection) alAndColsel[1]);
+        af.viewport.getAlignment().setHiddenColumns(
+                (HiddenColumns) alAndColsel[1]);
       }
     }
     else
index 7fa5147..dbc707d 100644 (file)
@@ -31,6 +31,7 @@ import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
@@ -485,7 +486,8 @@ public class JalviewLite extends Applet implements
         @Override
         public void run()
         {
-          alf.select(sel, csel);
+          alf.select(sel, csel, alf.getAlignViewport().getAlignment()
+                  .getHiddenColumns());
         }
       });
     }
@@ -2273,9 +2275,9 @@ public class JalviewLite extends Applet implements
           SequenceI repseq = alignFrame.viewport.getAlignment()
                   .getSequenceAt(0);
           alignFrame.viewport.getAlignment().setSeqrep(repseq);
-          ColumnSelection cs = new ColumnSelection();
+          HiddenColumns cs = new HiddenColumns();
           cs.hideInsertionsFor(repseq);
-          alignFrame.viewport.setColumnSelection(cs);
+          alignFrame.viewport.getAlignment().setHiddenColumns(cs);
           alignFrame.alignPanel.fontChanged();
           alignFrame.alignPanel.setScrollValues(0, 0);
           result = true;
index 8371036..fcb6109 100755 (executable)
@@ -62,6 +62,8 @@ public class Alignment implements AlignmentI
 
   HiddenSequences hiddenSequences;
 
+  HiddenColumns hiddenCols;
+
   public Hashtable alignmentProperties;
 
   private List<AlignedCodonFrame> codonFrameList;
@@ -70,6 +72,7 @@ public class Alignment implements AlignmentI
   {
     groups = Collections.synchronizedList(new ArrayList<SequenceGroup>());
     hiddenSequences = new HiddenSequences(this);
+    hiddenCols = new HiddenColumns();
     codonFrameList = new ArrayList<AlignedCodonFrame>();
 
     nucleotide = Comparison.isNucleotide(seqs);
@@ -125,7 +128,7 @@ public class Alignment implements AlignmentI
   public Alignment(SeqCigar[] alseqs)
   {
     SequenceI[] seqs = SeqCigar.createAlignmentSequences(alseqs,
-            gapCharacter, new ColumnSelection(), null);
+            gapCharacter, new HiddenColumns(), null);
     initAlignment(seqs);
   }
 
@@ -1327,6 +1330,12 @@ public class Alignment implements AlignmentI
   }
 
   @Override
+  public HiddenColumns getHiddenColumns()
+  {
+    return hiddenCols;
+  }
+
+  @Override
   public CigarArray getCompactAlignment()
   {
     synchronized (sequences)
@@ -1944,4 +1953,10 @@ public class Alignment implements AlignmentI
     }
     return new int[] { startPos, endPos };
   }
+
+  @Override
+  public void setHiddenColumns(HiddenColumns cols)
+  {
+    hiddenCols = cols;
+  }
 }
index 543958e..1594f2b 100755 (executable)
  */
 package jalview.datamodel;
 
+import jalview.analysis.Rna;
+import jalview.analysis.SecStrConsensus.SimpleBP;
+import jalview.analysis.WUSSParseException;
+
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -28,10 +32,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
-import jalview.analysis.Rna;
-import jalview.analysis.SecStrConsensus.SimpleBP;
-import jalview.analysis.WUSSParseException;
-
 /**
  * DOCUMENT ME!
  * 
@@ -1150,14 +1150,14 @@ public class AlignmentAnnotation
    * @param colSel
    */
   public AlignmentAnnotation(AlignmentAnnotation alignmentAnnotation,
-          ColumnSelection colSel)
+          HiddenColumns hidden)
   {
     this(alignmentAnnotation);
     if (annotations == null)
     {
       return;
     }
-    colSel.makeVisibleAnnotation(this);
+    hidden.makeVisibleAnnotation(this);
   }
 
   public void setPadGaps(boolean padgaps, char gapchar)
index 2abb1f8..2e61f9d 100755 (executable)
@@ -358,6 +358,8 @@ public interface AlignmentI extends AnnotatedCollectionI
 
   HiddenSequences getHiddenSequences();
 
+  HiddenColumns getHiddenColumns();
+
   /**
    * Compact representation of alignment
    * 
@@ -587,4 +589,6 @@ public interface AlignmentI extends AnnotatedCollectionI
    */
   public int[] getVisibleStartAndEndIndex(List<int[]> hiddenCols);
 
+  public void setHiddenColumns(HiddenColumns cols);
+
 }
index 1e34036..5058dcf 100644 (file)
@@ -141,13 +141,14 @@ public class AlignmentView
    *          the view
    */
   public AlignmentView(AlignmentI alignment,
-          ColumnSelection columnSelection, SequenceGroup selection,
+ HiddenColumns hidden,
+          SequenceGroup selection,
           boolean hasHiddenColumns, boolean selectedRegionOnly,
           boolean recordGroups)
   {
     // refactored from AlignViewport.getAlignmentView(selectedOnly);
     this(new jalview.datamodel.CigarArray(alignment,
-            (hasHiddenColumns ? columnSelection : null),
+            (hasHiddenColumns ? hidden : null),
             (selectedRegionOnly ? selection : null)),
             (selectedRegionOnly && selection != null) ? selection
                     .getStartRes() : 0);
@@ -330,13 +331,13 @@ public class AlignmentView
    *          char
    * @return Object[] { SequenceI[], ColumnSelection}
    */
-  public Object[] getAlignmentAndColumnSelection(char gapCharacter)
+  public Object[] getAlignmentAndHiddenColumns(char gapCharacter)
   {
-    ColumnSelection colsel = new ColumnSelection();
+    HiddenColumns hidden = new HiddenColumns();
 
     return new Object[] {
-        SeqCigar.createAlignmentSequences(sequences, gapCharacter, colsel,
-                contigs), colsel };
+        SeqCigar.createAlignmentSequences(sequences, gapCharacter, hidden,
+                contigs), hidden };
   }
 
   /**
@@ -710,7 +711,8 @@ public class AlignmentView
     if (contigs != null && contigs.length > 0)
     {
       SequenceI[] alignment = new SequenceI[sequences.length];
-      ColumnSelection columnselection = new ColumnSelection();
+      // ColumnSelection columnselection = new ColumnSelection();
+      HiddenColumns hidden = new HiddenColumns();
       if (contigs != null && contigs.length > 0)
       {
         int start = 0;
@@ -823,7 +825,7 @@ public class AlignmentView
             }
           }
           // mark hidden segment as hidden in the new alignment
-          columnselection.hideColumns(nwidth, nwidth + contigs[contig + 2]
+          hidden.hideColumns(nwidth, nwidth + contigs[contig + 2]
                   - 1);
           nwidth += contigs[contig + 2];
         }
@@ -901,7 +903,7 @@ public class AlignmentView
           }
         }
       }
-      return new Object[] { alignment, columnselection };
+      return new Object[] { alignment, hidden };
     }
     else
     {
@@ -920,7 +922,7 @@ public class AlignmentView
       }
       else
       {
-        return getAlignmentAndColumnSelection(gapCharacter);
+        return getAlignmentAndHiddenColumns(gapCharacter);
       }
     }
   }
@@ -1135,7 +1137,7 @@ public class AlignmentView
   }
 
   public static void testSelectionViews(AlignmentI alignment,
-          ColumnSelection csel, SequenceGroup selection)
+          HiddenColumns hidden, SequenceGroup selection)
   {
     System.out.println("Testing standard view creation:\n");
     AlignmentView view = null;
@@ -1143,7 +1145,7 @@ public class AlignmentView
     {
       System.out
               .println("View with no hidden columns, no limit to selection, no groups to be collected:");
-      view = new AlignmentView(alignment, csel, selection, false, false,
+      view = new AlignmentView(alignment, hidden, selection, false, false,
               false);
       summariseAlignmentView(view, System.out);
 
@@ -1157,7 +1159,7 @@ public class AlignmentView
     {
       System.out
               .println("View with no hidden columns, no limit to selection, and all groups to be collected:");
-      view = new AlignmentView(alignment, csel, selection, false, false,
+      view = new AlignmentView(alignment, hidden, selection, false, false,
               true);
       summariseAlignmentView(view, System.out);
     } catch (Exception e)
@@ -1170,7 +1172,7 @@ public class AlignmentView
     {
       System.out
               .println("View with no hidden columns, limited to selection and no groups to be collected:");
-      view = new AlignmentView(alignment, csel, selection, false, true,
+      view = new AlignmentView(alignment, hidden, selection, false, true,
               false);
       summariseAlignmentView(view, System.out);
     } catch (Exception e)
@@ -1183,7 +1185,7 @@ public class AlignmentView
     {
       System.out
               .println("View with no hidden columns, limited to selection, and all groups to be collected:");
-      view = new AlignmentView(alignment, csel, selection, false, true,
+      view = new AlignmentView(alignment, hidden, selection, false, true,
               true);
       summariseAlignmentView(view, System.out);
     } catch (Exception e)
@@ -1196,7 +1198,7 @@ public class AlignmentView
     {
       System.out
               .println("View *with* hidden columns, no limit to selection, no groups to be collected:");
-      view = new AlignmentView(alignment, csel, selection, true, false,
+      view = new AlignmentView(alignment, hidden, selection, true, false,
               false);
       summariseAlignmentView(view, System.out);
     } catch (Exception e)
@@ -1209,7 +1211,7 @@ public class AlignmentView
     {
       System.out
               .println("View *with* hidden columns, no limit to selection, and all groups to be collected:");
-      view = new AlignmentView(alignment, csel, selection, true, false,
+      view = new AlignmentView(alignment, hidden, selection, true, false,
               true);
       summariseAlignmentView(view, System.out);
     } catch (Exception e)
@@ -1222,7 +1224,7 @@ public class AlignmentView
     {
       System.out
               .println("View *with* hidden columns, limited to selection and no groups to be collected:");
-      view = new AlignmentView(alignment, csel, selection, true, true,
+      view = new AlignmentView(alignment, hidden, selection, true, true,
               false);
       summariseAlignmentView(view, System.out);
     } catch (Exception e)
@@ -1235,7 +1237,8 @@ public class AlignmentView
     {
       System.out
               .println("View *with* hidden columns, limited to selection, and all groups to be collected:");
-      view = new AlignmentView(alignment, csel, selection, true, true, true);
+      view = new AlignmentView(alignment, hidden, selection, true, true,
+              true);
       summariseAlignmentView(view, System.out);
     } catch (Exception e)
     {
diff --git a/src/jalview/datamodel/AllColsCollection.java b/src/jalview/datamodel/AllColsCollection.java
new file mode 100644 (file)
index 0000000..f84ba95
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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 jalview.api.AlignmentColsCollectionI;
+
+import java.util.Iterator;
+
+public class AllColsCollection implements AlignmentColsCollectionI
+{
+  int start;
+  int end;
+
+  HiddenColumns hidden;
+  
+  public AllColsCollection(int s, int e, AlignmentI al)
+  {
+    start = s;
+    end = e;
+    hidden = al.getHiddenColumns();
+  }
+  
+  @Override
+  public Iterator<Integer> iterator()
+  {
+    return new AllColsIterator(start,end,hidden);
+  }
+
+  @Override
+  public boolean isHidden(int c)
+  {
+    return !hidden.isVisible(c);
+  }
+}
diff --git a/src/jalview/datamodel/AllColsIterator.java b/src/jalview/datamodel/AllColsIterator.java
new file mode 100644 (file)
index 0000000..c7a0bb1
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+  public AllColsIterator(int firstcol, int lastcol, HiddenColumns hiddenCols)
+  {
+    last = lastcol;
+    next = firstcol;
+    current = firstcol;
+  }
+
+  @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/AllRowsCollection.java b/src/jalview/datamodel/AllRowsCollection.java
new file mode 100644 (file)
index 0000000..502ace4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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 jalview.api.AlignmentRowsCollectionI;
+
+import java.util.Iterator;
+
+public class AllRowsCollection implements AlignmentRowsCollectionI
+{
+  int start;
+
+  int end;
+
+  AlignmentI alignment;
+
+  HiddenSequences hidden;
+
+  public AllRowsCollection(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);
+  }
+
+  @Override
+  public boolean isHidden(int seq)
+  {
+    return hidden.isHidden(seq);
+  }
+
+  @Override
+  public SequenceI getSequence(int seq)
+  {
+    return alignment.getSequenceAtAbsoluteIndex(seq);
+  }
+}
+
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 f6e5862..aab82a1 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.datamodel;
 
+import htsjdk.samtools.Cigar;
+
 import java.util.List;
 
 public class CigarArray extends CigarBase
@@ -85,12 +87,12 @@ public class CigarArray extends CigarBase
    * @param columnSelection
    * @param selectionGroup
    */
-  public CigarArray(AlignmentI alignment, ColumnSelection columnSelection,
+  public CigarArray(AlignmentI alignment, HiddenColumns hidden,
           SequenceGroup selectionGroup)
   {
     this(constructSeqCigarArray(alignment, selectionGroup));
     constructFromAlignment(alignment,
-            columnSelection != null ? columnSelection.getHiddenColumns()
+            hidden != null ? hidden.getHiddenRegions()
                     : null, selectionGroup);
   }
 
index 97bc5a3..eb2d174 100644 (file)
@@ -20,8 +20,6 @@
  */
 package jalview.datamodel;
 
-import jalview.util.Comparison;
-import jalview.util.ShiftList;
 import jalview.viewmodel.annotationfilter.AnnotationFilterParameter;
 import jalview.viewmodel.annotationfilter.AnnotationFilterParameter.SearchableAnnotationField;
 
@@ -29,7 +27,6 @@ import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.Collections;
 import java.util.List;
-import java.util.Vector;
 
 /**
  * Data class holding the selected columns and hidden column ranges for a view.
@@ -268,12 +265,6 @@ public class ColumnSelection
 
   IntList selection = new IntList();
 
-  /*
-   * list of hidden column [start, end] ranges; the list is maintained in
-   * ascending start column order
-   */
-  Vector<int[]> hiddenColumns;
-
   /**
    * Add a column to the selection
    * 
@@ -350,1100 +341,137 @@ public class ColumnSelection
   }
 
   /**
-   * 
-   * @param col
-   *          index to search for in column selection
-   * 
-   * @return true if col is selected
-   */
-  public boolean contains(int col)
-  {
-    return (col > -1) ? selection.isSelected(col) : false;
-  }
-
-  /**
-   * Answers true if no columns are selected, else false
-   */
-  public boolean isEmpty()
-  {
-    return selection == null || selection.isEmpty();
-  }
-
-  /**
-   * rightmost selected column
-   * 
-   * @return rightmost column in alignment that is selected
-   */
-  public int getMax()
-  {
-    if (selection.isEmpty())
-    {
-      return -1;
-    }
-    return selection.getMaxColumn();
-  }
-
-  /**
-   * Leftmost column in selection
-   * 
-   * @return column index of leftmost column in selection
-   */
-  public int getMin()
-  {
-    if (selection.isEmpty())
-    {
-      return 1000000000;
-    }
-    return selection.getMinColumn();
-  }
-
-  /**
-   * propagate shift in alignment columns to column selection
-   * 
-   * @param start
-   *          beginning of edit
-   * @param left
-   *          shift in edit (+ve for removal, or -ve for inserts)
-   */
-  public List<int[]> compensateForEdit(int start, int change)
-  {
-    List<int[]> deletedHiddenColumns = null;
-    selection.compensateForEdits(start, change);
-
-    if (hiddenColumns != null)
-    {
-      deletedHiddenColumns = new ArrayList<int[]>();
-      int hSize = hiddenColumns.size();
-      for (int i = 0; i < hSize; i++)
-      {
-        int[] region = hiddenColumns.elementAt(i);
-        if (region[0] > start && start + change > region[1])
-        {
-          deletedHiddenColumns.add(region);
-
-          hiddenColumns.removeElementAt(i);
-          i--;
-          hSize--;
-          continue;
-        }
-
-        if (region[0] > start)
-        {
-          region[0] -= change;
-          region[1] -= change;
-        }
-
-        if (region[0] < 0)
-        {
-          region[0] = 0;
-        }
-
-      }
-
-      this.revealHiddenColumns(0);
-    }
-
-    return deletedHiddenColumns;
-  }
-
-  /**
-   * propagate shift in alignment columns to column selection special version of
-   * compensateForEdit - allowing for edits within hidden regions
-   * 
-   * @param start
-   *          beginning of edit
-   * @param left
-   *          shift in edit (+ve for removal, or -ve for inserts)
-   */
-  private void compensateForDelEdits(int start, int change)
-  {
-
-    selection.compensateForEdits(start, change);
-
-    if (hiddenColumns != null)
-    {
-      for (int i = 0; i < hiddenColumns.size(); i++)
-      {
-        int[] region = hiddenColumns.elementAt(i);
-        if (region[0] >= start)
-        {
-          region[0] -= change;
-        }
-        if (region[1] >= start)
-        {
-          region[1] -= change;
-        }
-        if (region[1] < region[0])
-        {
-          hiddenColumns.removeElementAt(i--);
-        }
-
-        if (region[0] < 0)
-        {
-          region[0] = 0;
-        }
-        if (region[1] < 0)
-        {
-          region[1] = 0;
-        }
-      }
-    }
-  }
-
-  /**
-   * Adjust hidden column boundaries based on a series of column additions or
-   * deletions in visible regions.
-   * 
-   * @param shiftrecord
-   * @return
-   */
-  public ShiftList compensateForEdits(ShiftList shiftrecord)
-  {
-    if (shiftrecord != null)
-    {
-      final List<int[]> shifts = shiftrecord.getShifts();
-      if (shifts != null && shifts.size() > 0)
-      {
-        int shifted = 0;
-        for (int i = 0, j = shifts.size(); i < j; i++)
-        {
-          int[] sh = shifts.get(i);
-          // compensateForEdit(shifted+sh[0], sh[1]);
-          compensateForDelEdits(shifted + sh[0], sh[1]);
-          shifted -= sh[1];
-        }
-      }
-      return shiftrecord.getInverse();
-    }
-    return null;
-  }
-
-  /**
-   * removes intersection of position,length ranges in deletions from the
-   * start,end regions marked in intervals.
-   * 
-   * @param shifts
-   * @param intervals
-   * @return
-   */
-  private boolean pruneIntervalVector(final List<int[]> shifts,
-          Vector<int[]> intervals)
-  {
-    boolean pruned = false;
-    int i = 0, j = intervals.size() - 1, s = 0, t = shifts.size() - 1;
-    int hr[] = intervals.elementAt(i);
-    int sr[] = shifts.get(s);
-    while (i <= j && s <= t)
-    {
-      boolean trailinghn = hr[1] >= sr[0];
-      if (!trailinghn)
-      {
-        if (i < j)
-        {
-          hr = intervals.elementAt(++i);
-        }
-        else
-        {
-          i++;
-        }
-        continue;
-      }
-      int endshift = sr[0] + sr[1]; // deletion ranges - -ve means an insert
-      if (endshift < hr[0] || endshift < sr[0])
-      { // leadinghc disjoint or not a deletion
-        if (s < t)
-        {
-          sr = shifts.get(++s);
-        }
-        else
-        {
-          s++;
-        }
-        continue;
-      }
-      boolean leadinghn = hr[0] >= sr[0];
-      boolean leadinghc = hr[0] < endshift;
-      boolean trailinghc = hr[1] < endshift;
-      if (leadinghn)
-      {
-        if (trailinghc)
-        { // deleted hidden region.
-          intervals.removeElementAt(i);
-          pruned = true;
-          j--;
-          if (i <= j)
-          {
-            hr = intervals.elementAt(i);
-          }
-          continue;
-        }
-        if (leadinghc)
-        {
-          hr[0] = endshift; // clip c terminal region
-          leadinghn = !leadinghn;
-          pruned = true;
-        }
-      }
-      if (!leadinghn)
-      {
-        if (trailinghc)
-        {
-          if (trailinghn)
-          {
-            hr[1] = sr[0] - 1;
-            pruned = true;
-          }
-        }
-        else
-        {
-          // sr contained in hr
-          if (s < t)
-          {
-            sr = shifts.get(++s);
-          }
-          else
-          {
-            s++;
-          }
-          continue;
-        }
-      }
-    }
-    return pruned; // true if any interval was removed or modified by
-    // operations.
-  }
-
-  /**
-   * remove any hiddenColumns or selected columns and shift remaining based on a
-   * series of position, range deletions.
-   * 
-   * @param deletions
-   */
-  public void pruneDeletions(ShiftList deletions)
-  {
-    if (deletions != null)
-    {
-      final List<int[]> shifts = deletions.getShifts();
-      if (shifts != null && shifts.size() > 0)
-      {
-        // delete any intervals intersecting.
-        if (hiddenColumns != null)
-        {
-          pruneIntervalVector(shifts, hiddenColumns);
-          if (hiddenColumns != null && hiddenColumns.size() == 0)
-          {
-            hiddenColumns = null;
-          }
-        }
-        if (selection != null && selection.size() > 0)
-        {
-          selection.pruneColumnList(shifts);
-          if (selection != null && selection.size() == 0)
-          {
-            selection = null;
-          }
-        }
-        // and shift the rest.
-        this.compensateForEdits(deletions);
-      }
-    }
-  }
-
-  /**
-   * This Method is used to return all the HiddenColumn regions
-   * 
-   * @return empty list or List of hidden column intervals
-   */
-  public List<int[]> getHiddenColumns()
-  {
-    return hiddenColumns == null ? Collections.<int[]> emptyList()
-            : hiddenColumns;
-  }
-
-  /**
-   * Return absolute column index for a visible column index
-   * 
-   * @param column
-   *          int column index in alignment view (count from zero)
-   * @return alignment column index for column
-   */
-  public int adjustForHiddenColumns(int column)
-  {
-    int result = column;
-    if (hiddenColumns != null)
-    {
-      for (int i = 0; i < hiddenColumns.size(); i++)
-      {
-        int[] region = hiddenColumns.elementAt(i);
-        if (result >= region[0])
-        {
-          result += region[1] - region[0] + 1;
-        }
-      }
-    }
-    return result;
-  }
-
-  /**
-   * Use this method to find out where a column will appear in the visible
-   * alignment when hidden columns exist. If the column is not visible, then the
-   * left-most visible column will always be returned.
-   * 
-   * @param hiddenColumn
-   *          the column index in the full alignment including hidden columns
-   * @return the position of the column in the visible alignment
-   */
-  public int findColumnPosition(int hiddenColumn)
-  {
-    int result = hiddenColumn;
-    if (hiddenColumns != null)
-    {
-      int index = 0;
-      int[] region;
-      do
-      {
-        region = hiddenColumns.elementAt(index++);
-        if (hiddenColumn > region[1])
-        {
-          result -= region[1] + 1 - region[0];
-        }
-      } while ((hiddenColumn > region[1]) && (index < hiddenColumns.size()));
-
-      if (hiddenColumn >= region[0] && hiddenColumn <= region[1])
-       {
-         // Here the hidden column is within a region, so
-         // we want to return the position of region[0]-1, adjusted for any
-         // earlier hidden columns.
-         // Calculate the difference between the actual hidden col position
-         // and region[0]-1, and then subtract from result to convert result from
-         // the adjusted hiddenColumn value to the adjusted region[0]-1 value
-
-        // However, if the region begins at 0 we cannot return region[0]-1
-        // just return 0
-        if (region[0] == 0)
-        {
-          return 0;
-        }
-        else
-        {
-          return result - (hiddenColumn - region[0] + 1);
-        }
-      }
-    }
-    return result; // return the shifted position after removing hidden columns.
-  }
-
-  /**
-   * Find the visible column which is a given visible number of columns to the
-   * left of another visible column. i.e. for a startColumn x, the column which
-   * is distance 1 away will be column x-1.
-   * 
-   * @param visibleDistance
-   *          the number of visible columns to offset by
-   * @param startColumn
-   *          the column to start from
-   * @return the position of the column in the visible alignment
-   */
-  public int subtractVisibleColumns(int visibleDistance, int startColumn)
-  {
-    int distance = visibleDistance;
-
-    // in case startColumn is in a hidden region, move it to the left
-    int start = adjustForHiddenColumns(findColumnPosition(startColumn));
-
-    // get index of hidden region to left of start
-    int index = getHiddenIndexLeft(start);
-    if (index == -1)
-    {
-      // no hidden regions to left of startColumn
-      return start - distance;
-    }
-
-    // walk backwards through the alignment subtracting the counts of visible
-    // columns from distance
-    int[] region;
-    int gap = 0;
-    int nextstart = start;
-
-    while ((index > -1) && (distance - gap > 0))
-    {
-      // subtract the gap to right of region from distance
-      distance -= gap;
-      start = nextstart;
-
-      // calculate the next gap
-      region = hiddenColumns.get(index);
-      gap = start - region[1];
-
-      // set start to just to left of current region
-      nextstart = region[0] - 1;
-      index--;
-    }
-
-    if (distance - gap > 0)
-    {
-      // fell out of loop because there are no more hidden regions
-      distance -= gap;
-      return nextstart - distance;
-    }
-    return start - distance;
-
-  }
-
-  /**
-   * Use this method to determine where the next hiddenRegion starts
-   * 
-   * @param hiddenRegion
-   *          index of hidden region (counts from 0)
-   * @return column number in visible view
-   */
-  public int findHiddenRegionPosition(int hiddenRegion)
-  {
-    int result = 0;
-    if (hiddenColumns != null)
-    {
-      int index = 0;
-      int gaps = 0;
-      do
-      {
-        int[] region = hiddenColumns.elementAt(index);
-        if (hiddenRegion == 0)
-        {
-          return region[0];
-        }
-
-        gaps += region[1] + 1 - region[0];
-        result = region[1] + 1;
-        index++;
-      } while (index <= hiddenRegion);
-
-      result -= gaps;
-    }
-
-    return result;
-  }
-
-  /**
-   * THis method returns the rightmost limit of a region of an alignment with
-   * hidden columns. In otherwords, the next hidden column.
-   * 
-   * @param index
-   *          int
-   */
-  public int getHiddenBoundaryRight(int alPos)
-  {
-    if (hiddenColumns != null)
-    {
-      int index = 0;
-      do
-      {
-        int[] region = hiddenColumns.elementAt(index);
-        if (alPos < region[0])
-        {
-          return region[0];
-        }
-
-        index++;
-      } while (index < hiddenColumns.size());
-    }
-
-    return alPos;
-
-  }
-
-  /**
-   * This method returns the leftmost limit of a region of an alignment with
-   * hidden columns. In otherwords, the previous hidden column.
-   * 
-   * @param index
-   *          int
-   */
-  public int getHiddenBoundaryLeft(int alPos)
-  {
-    if (hiddenColumns != null)
-    {
-      int index = hiddenColumns.size() - 1;
-      do
-      {
-        int[] region = hiddenColumns.elementAt(index);
-        if (alPos > region[1])
-        {
-          return region[1];
-        }
-
-        index--;
-      } while (index > -1);
-    }
-
-    return alPos;
-
-  }
-
-  /**
-   * This method returns the index of the hidden region to the left of a column
-   * position. If the column is in a hidden region it returns the index of the
-   * region to the left. If there is no hidden region to the left it returns -1.
-   * 
-   * @param pos
-   *          int
-   */
-  private int getHiddenIndexLeft(int pos)
-  {
-    if (hiddenColumns != null)
-    {
-      int index = hiddenColumns.size() - 1;
-      do
-      {
-        int[] region = hiddenColumns.elementAt(index);
-        if (pos > region[1])
-        {
-          return index;
-        }
-
-        index--;
-      } while (index > -1);
-    }
-
-    return -1;
-
-  }
-
-  public void hideSelectedColumns()
-  {
-    synchronized (selection)
-    {
-      for (int[] selregions : selection.getRanges())
-      {
-        hideColumns(selregions[0], selregions[1]);
-      }
-      selection.clear();
-    }
-
-  }
-
-  /**
-   * Adds the specified column range to the hidden columns
-   * 
-   * @param start
-   * @param end
-   */
-  public void hideColumns(int start, int end)
-  {
-    if (hiddenColumns == null)
-    {
-      hiddenColumns = new Vector<int[]>();
-    }
-
-    /*
-     * traverse existing hidden ranges and insert / amend / append as
-     * appropriate
-     */
-    for (int i = 0; i < hiddenColumns.size(); i++)
-    {
-      int[] region = hiddenColumns.elementAt(i);
-
-      if (end < region[0] - 1)
-      {
-        /*
-         * insert discontiguous preceding range
-         */
-        hiddenColumns.insertElementAt(new int[] { start, end }, i);
-        return;
-      }
-
-      if (end <= region[1])
-      {
-        /*
-         * new range overlaps existing, or is contiguous preceding it - adjust
-         * start column
-         */
-        region[0] = Math.min(region[0], start);
-        return;
-      }
-
-      if (start <= region[1] + 1)
-      {
-        /*
-         * new range overlaps existing, or is contiguous following it - adjust
-         * start and end columns
-         */
-        region[0] = Math.min(region[0], start);
-        region[1] = Math.max(region[1], end);
-
-        /*
-         * also update or remove any subsequent ranges 
-         * that are overlapped
-         */
-        while (i < hiddenColumns.size() - 1)
-        {
-          int[] nextRegion = hiddenColumns.get(i + 1);
-          if (nextRegion[0] > end + 1)
-          {
-            /*
-             * gap to next hidden range - no more to update
-             */
-            break;
-          }
-          region[1] = Math.max(nextRegion[1], end);
-          hiddenColumns.remove(i + 1);
-        }
-        return;
-      }
-    }
-
-    /*
-     * remaining case is that the new range follows everything else
-     */
-    hiddenColumns.addElement(new int[] { start, end });
-  }
-
-  /**
-   * Hides the specified column and any adjacent selected columns
-   * 
-   * @param res
-   *          int
-   */
-  public void hideColumns(int col)
-  {
-    /*
-     * deselect column (whether selected or not!)
-     */
-    removeElement(col);
-
-    /*
-     * find adjacent selected columns
-     */
-    int min = col - 1, max = col + 1;
-    while (contains(min))
-    {
-      removeElement(min);
-      min--;
-    }
-
-    while (contains(max))
-    {
-      removeElement(max);
-      max++;
-    }
-
-    /*
-     * min, max are now the closest unselected columns
-     */
-    min++;
-    max--;
-    if (min > max)
-    {
-      min = max;
-    }
-
-    hideColumns(min, max);
-  }
-
-  /**
-   * Unhides, and adds to the selection list, all hidden columns
-   */
-  public void revealAllHiddenColumns()
-  {
-    if (hiddenColumns != null)
-    {
-      for (int i = 0; i < hiddenColumns.size(); i++)
-      {
-        int[] region = hiddenColumns.elementAt(i);
-        for (int j = region[0]; j < region[1] + 1; j++)
-        {
-          addElement(j);
-        }
-      }
-    }
-
-    hiddenColumns = null;
-  }
-
-  /**
-   * Reveals, and marks as selected, the hidden column range with the given
-   * start column
-   * 
-   * @param start
-   */
-  public void revealHiddenColumns(int start)
-  {
-    for (int i = 0; i < hiddenColumns.size(); i++)
-    {
-      int[] region = hiddenColumns.elementAt(i);
-      if (start == region[0])
-      {
-        for (int j = region[0]; j < region[1] + 1; j++)
-        {
-          addElement(j);
-        }
-
-        hiddenColumns.removeElement(region);
-        break;
-      }
-    }
-    if (hiddenColumns.size() == 0)
-    {
-      hiddenColumns = null;
-    }
-  }
-
-  public boolean isVisible(int column)
-  {
-    if (hiddenColumns != null)
-    {
-      for (int[] region : hiddenColumns)
-      {
-        if (column >= region[0] && column <= region[1])
-        {
-          return false;
-        }
-      }
-    }
-
-    return true;
-  }
-
-  /**
-   * Copy constructor
-   * 
-   * @param copy
-   */
-  public ColumnSelection(ColumnSelection copy)
-  {
-    if (copy != null)
-    {
-      selection = new IntList(copy.selection);
-      if (copy.hiddenColumns != null)
-      {
-        hiddenColumns = new Vector<int[]>(copy.hiddenColumns.size());
-        for (int i = 0, j = copy.hiddenColumns.size(); i < j; i++)
-        {
-          int[] rh, cp;
-          rh = copy.hiddenColumns.elementAt(i);
-          if (rh != null)
-          {
-            cp = new int[rh.length];
-            System.arraycopy(rh, 0, cp, 0, rh.length);
-            hiddenColumns.addElement(cp);
-          }
-        }
-      }
-    }
-  }
-
-  /**
-   * ColumnSelection
+   * 
+   * @param col
+   *          index to search for in column selection
+   * 
+   * @return true if col is selected
    */
-  public ColumnSelection()
+  public boolean contains(int col)
   {
+    return (col > -1) ? selection.isSelected(col) : false;
   }
 
-  public String[] getVisibleSequenceStrings(int start, int end,
-          SequenceI[] seqs)
+  /**
+   * Answers true if no columns are selected, else false
+   */
+  public boolean isEmpty()
   {
-    int i, iSize = seqs.length;
-    String selections[] = new String[iSize];
-    if (hiddenColumns != null && hiddenColumns.size() > 0)
-    {
-      for (i = 0; i < iSize; i++)
-      {
-        StringBuffer visibleSeq = new StringBuffer();
-        List<int[]> regions = getHiddenColumns();
-
-        int blockStart = start, blockEnd = end;
-        int[] region;
-        int hideStart, hideEnd;
-
-        for (int j = 0; j < regions.size(); j++)
-        {
-          region = regions.get(j);
-          hideStart = region[0];
-          hideEnd = region[1];
-
-          if (hideStart < start)
-          {
-            continue;
-          }
-
-          blockStart = Math.min(blockStart, hideEnd + 1);
-          blockEnd = Math.min(blockEnd, hideStart);
-
-          if (blockStart > blockEnd)
-          {
-            break;
-          }
-
-          visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));
-
-          blockStart = hideEnd + 1;
-          blockEnd = end;
-        }
-
-        if (end > blockStart)
-        {
-          visibleSeq.append(seqs[i].getSequence(blockStart, end));
-        }
+    return selection == null || selection.isEmpty();
+  }
 
-        selections[i] = visibleSeq.toString();
-      }
-    }
-    else
+  /**
+   * rightmost selected column
+   * 
+   * @return rightmost column in alignment that is selected
+   */
+  public int getMax()
+  {
+    if (selection.isEmpty())
     {
-      for (i = 0; i < iSize; i++)
-      {
-        selections[i] = seqs[i].getSequenceAsString(start, end);
-      }
+      return -1;
     }
-
-    return selections;
+    return selection.getMaxColumn();
   }
 
   /**
-   * return all visible segments between the given start and end boundaries
+   * Leftmost column in selection
    * 
-   * @param start
-   *          (first column inclusive from 0)
-   * @param end
-   *          (last column - not inclusive)
-   * @return int[] {i_start, i_end, ..} where intervals lie in
-   *         start<=i_start<=i_end<end
+   * @return column index of leftmost column in selection
    */
-  public int[] getVisibleContigs(int start, int end)
+  public int getMin()
   {
-    if (hiddenColumns != null && hiddenColumns.size() > 0)
+    if (selection.isEmpty())
     {
-      List<int[]> visiblecontigs = new ArrayList<int[]>();
-      List<int[]> regions = getHiddenColumns();
-
-      int vstart = start;
-      int[] region;
-      int hideStart, hideEnd;
-
-      for (int j = 0; vstart < end && j < regions.size(); j++)
-      {
-        region = regions.get(j);
-        hideStart = region[0];
-        hideEnd = region[1];
-
-        if (hideEnd < vstart)
-        {
-          continue;
-        }
-        if (hideStart > vstart)
-        {
-          visiblecontigs.add(new int[] { vstart, hideStart - 1 });
-        }
-        vstart = hideEnd + 1;
-      }
+      return 1000000000;
+    }
+    return selection.getMinColumn();
+  }
 
-      if (vstart < end)
-      {
-        visiblecontigs.add(new int[] { vstart, end - 1 });
-      }
-      int[] vcontigs = new int[visiblecontigs.size() * 2];
-      for (int i = 0, j = visiblecontigs.size(); i < j; i++)
+  public void hideSelectedColumns(AlignmentI al)
+  {
+    synchronized (selection)
+    {
+      for (int[] selregions : selection.getRanges())
       {
-        int[] vc = visiblecontigs.get(i);
-        visiblecontigs.set(i, null);
-        vcontigs[i * 2] = vc[0];
-        vcontigs[i * 2 + 1] = vc[1];
+        al.getHiddenColumns().hideColumns(selregions[0], selregions[1]);
       }
-      visiblecontigs.clear();
-      return vcontigs;
-    }
-    else
-    {
-      return new int[] { start, end - 1 };
+      selection.clear();
     }
+
   }
 
+
   /**
-   * Locate the first and last position visible for this sequence. if seq isn't
-   * visible then return the position of the left and right of the hidden
-   * boundary region, and the corresponding alignment column indices for the
-   * extent of the sequence
+   * Hides the specified column and any adjacent selected columns
    * 
-   * @param seq
-   * @return int[] { visible start, visible end, first seqpos, last seqpos,
-   *         alignment index for seq start, alignment index for seq end }
+   * @param res
+   *          int
    */
-  public int[] locateVisibleBoundsOfSequence(SequenceI seq)
+  public void hideSelectedColumns(int col, HiddenColumns hidden)
   {
-    int fpos = seq.getStart(), lpos = seq.getEnd();
-    int start = 0;
+    /*
+     * deselect column (whether selected or not!)
+     */
+    removeElement(col);
 
-    if (hiddenColumns == null || hiddenColumns.size() == 0)
+    /*
+     * find adjacent selected columns
+     */
+    int min = col - 1, max = col + 1;
+    while (contains(min))
     {
-      int ifpos = seq.findIndex(fpos) - 1, ilpos = seq.findIndex(lpos) - 1;
-      return new int[] { ifpos, ilpos, fpos, lpos, ifpos, ilpos };
+      removeElement(min);
+      min--;
     }
 
-    // Simply walk along the sequence whilst watching for hidden column
-    // boundaries
-    List<int[]> regions = getHiddenColumns();
-    int spos = fpos, lastvispos = -1, rcount = 0, hideStart = seq
-            .getLength(), hideEnd = -1;
-    int visPrev = 0, visNext = 0, firstP = -1, lastP = -1;
-    boolean foundStart = false;
-    for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd()
-            && p < pLen; p++)
+    while (contains(max))
     {
-      if (!Comparison.isGap(seq.getCharAt(p)))
-      {
-        // keep track of first/last column
-        // containing sequence data regardless of visibility
-        if (firstP == -1)
-        {
-          firstP = p;
-        }
-        lastP = p;
-        // update hidden region start/end
-        while (hideEnd < p && rcount < regions.size())
-        {
-          int[] region = regions.get(rcount++);
-          visPrev = visNext;
-          visNext += region[0] - visPrev;
-          hideStart = region[0];
-          hideEnd = region[1];
-        }
-        if (hideEnd < p)
-        {
-          hideStart = seq.getLength();
-        }
-        // update visible boundary for sequence
-        if (p < hideStart)
-        {
-          if (!foundStart)
-          {
-            fpos = spos;
-            start = p;
-            foundStart = true;
-          }
-          lastvispos = p;
-          lpos = spos;
-        }
-        // look for next sequence position
-        spos++;
-      }
+      removeElement(max);
+      max++;
     }
-    if (foundStart)
+
+    /*
+     * min, max are now the closest unselected columns
+     */
+    min++;
+    max--;
+    if (min > max)
     {
-      return new int[] { findColumnPosition(start),
-          findColumnPosition(lastvispos), fpos, lpos, firstP, lastP };
+      min = max;
     }
-    // otherwise, sequence was completely hidden
-    return new int[] { visPrev, visNext, 0, 0, firstP, lastP };
+
+    hidden.hideColumns(min, max);
   }
 
+
+
+
+
   /**
-   * delete any columns in alignmentAnnotation that are hidden (including
-   * sequence associated annotation).
+   * Copy constructor
    * 
-   * @param alignmentAnnotation
+   * @param copy
    */
-  public void makeVisibleAnnotation(AlignmentAnnotation alignmentAnnotation)
+  public ColumnSelection(ColumnSelection copy)
   {
-    makeVisibleAnnotation(-1, -1, alignmentAnnotation);
+    if (copy != null)
+    {
+      selection = new IntList(copy.selection);
+    }
   }
 
   /**
-   * delete any columns in alignmentAnnotation that are hidden (including
-   * sequence associated annotation).
-   * 
-   * @param start
-   *          remove any annotation to the right of this column
-   * @param end
-   *          remove any annotation to the left of this column
-   * @param alignmentAnnotation
-   *          the annotation to operate on
+   * ColumnSelection
    */
-  public void makeVisibleAnnotation(int start, int end,
-          AlignmentAnnotation alignmentAnnotation)
+  public ColumnSelection()
   {
-    if (alignmentAnnotation.annotations == null)
-    {
-      return;
-    }
-    if (start == end && end == -1)
-    {
-      start = 0;
-      end = alignmentAnnotation.annotations.length;
-    }
-    if (hiddenColumns != null && hiddenColumns.size() > 0)
-    {
-      // then mangle the alignmentAnnotation annotation array
-      Vector<Annotation[]> annels = new Vector<Annotation[]>();
-      Annotation[] els = null;
-      List<int[]> regions = getHiddenColumns();
-      int blockStart = start, blockEnd = end;
-      int[] region;
-      int hideStart, hideEnd, w = 0;
-
-      for (int j = 0; j < regions.size(); j++)
-      {
-        region = regions.get(j);
-        hideStart = region[0];
-        hideEnd = region[1];
-
-        if (hideStart < start)
-        {
-          continue;
-        }
-
-        blockStart = Math.min(blockStart, hideEnd + 1);
-        blockEnd = Math.min(blockEnd, hideStart);
+  }
 
-        if (blockStart > blockEnd)
-        {
-          break;
-        }
 
-        annels.addElement(els = new Annotation[blockEnd - blockStart]);
-        System.arraycopy(alignmentAnnotation.annotations, blockStart, els,
-                0, els.length);
-        w += els.length;
-        blockStart = hideEnd + 1;
-        blockEnd = end;
-      }
 
-      if (end > blockStart)
-      {
-        annels.addElement(els = new Annotation[end - blockStart + 1]);
-        if ((els.length + blockStart) <= alignmentAnnotation.annotations.length)
-        {
-          // copy just the visible segment of the annotation row
-          System.arraycopy(alignmentAnnotation.annotations, blockStart,
-                  els, 0, els.length);
-        }
-        else
-        {
-          // copy to the end of the annotation row
-          System.arraycopy(alignmentAnnotation.annotations, blockStart,
-                  els, 0,
-                  (alignmentAnnotation.annotations.length - blockStart));
-        }
-        w += els.length;
-      }
-      if (w == 0)
-      {
-        return;
-      }
 
-      alignmentAnnotation.annotations = new Annotation[w];
-      w = 0;
 
-      for (Annotation[] chnk : annels)
-      {
-        System.arraycopy(chnk, 0, alignmentAnnotation.annotations, w,
-                chnk.length);
-        w += chnk.length;
-      }
-    }
-    else
-    {
-      alignmentAnnotation.restrict(start, end);
-    }
-  }
 
   /**
    * Invert the column selection from first to end-1. leaves hiddenColumns
@@ -1452,9 +480,9 @@ public class ColumnSelection
    * @param first
    * @param end
    */
-  public void invertColumnSelection(int first, int width)
+  public void invertColumnSelection(int first, int width, AlignmentI al)
   {
-    boolean hasHidden = hiddenColumns != null && hiddenColumns.size() > 0;
+    boolean hasHidden = al.getHiddenColumns().hasHidden();
     for (int i = first; i < width; i++)
     {
       if (contains(i))
@@ -1463,7 +491,7 @@ public class ColumnSelection
       }
       else
       {
-        if (!hasHidden || isVisible(i))
+        if (!hasHidden || al.getHiddenColumns().isVisible(i))
         {
           addElement(i);
         }
@@ -1472,195 +500,41 @@ public class ColumnSelection
   }
 
   /**
-   * add in any unselected columns from the given column selection, excluding
-   * any that are hidden.
-   * 
-   * @param colsel
-   */
-  public void addElementsFrom(ColumnSelection colsel)
-  {
-    if (colsel != null && !colsel.isEmpty())
-    {
-      for (Integer col : colsel.getSelected())
-      {
-        if (hiddenColumns != null && isVisible(col.intValue()))
-        {
-          selection.add(col);
-        }
-      }
-    }
-  }
-
-  /**
-   * set the selected columns the given column selection, excluding any columns
-   * that are hidden.
+   * set the selected columns to the given column selection, excluding any
+   * columns that are hidden.
    * 
    * @param colsel
    */
-  public void setElementsFrom(ColumnSelection colsel)
+  public void setElementsFrom(ColumnSelection colsel,
+          HiddenColumns hiddenColumns)
   {
     selection = new IntList();
     if (colsel.selection != null && colsel.selection.size() > 0)
     {
-      if (hiddenColumns != null && hiddenColumns.size() > 0)
+      if (hiddenColumns.hasHidden())
       {
         // only select visible columns in this columns selection
-        addElementsFrom(colsel);
-      }
-      else
-      {
-        // add everything regardless
         for (Integer col : colsel.getSelected())
         {
-          addElement(col);
-        }
-      }
-    }
-  }
-
-  /**
-   * Add gaps into the sequences aligned to profileseq under the given
-   * AlignmentView
-   * 
-   * @param profileseq
-   * @param al
-   *          - alignment to have gaps inserted into it
-   * @param input
-   *          - alignment view where sequence corresponding to profileseq is
-   *          first entry
-   * @return new Column selection for new alignment view, with insertions into
-   *         profileseq marked as hidden.
-   */
-  public static ColumnSelection propagateInsertions(SequenceI profileseq,
-          AlignmentI al, AlignmentView input)
-  {
-    int profsqpos = 0;
-
-    // return propagateInsertions(profileseq, al, )
-    char gc = al.getGapCharacter();
-    Object[] alandcolsel = input.getAlignmentAndColumnSelection(gc);
-    ColumnSelection nview = (ColumnSelection) alandcolsel[1];
-    SequenceI origseq = ((SequenceI[]) alandcolsel[0])[profsqpos];
-    nview.propagateInsertions(profileseq, al, origseq);
-    return nview;
-  }
-
-  /**
-   * 
-   * @param profileseq
-   *          - sequence in al which corresponds to origseq
-   * @param al
-   *          - alignment which is to have gaps inserted into it
-   * @param origseq
-   *          - sequence corresponding to profileseq which defines gap map for
-   *          modifying al
-   */
-  public void propagateInsertions(SequenceI profileseq, AlignmentI al,
-          SequenceI origseq)
-  {
-    char gc = al.getGapCharacter();
-    // recover mapping between sequence's non-gap positions and positions
-    // mapping to view.
-    pruneDeletions(ShiftList.parseMap(origseq.gapMap()));
-    int[] viscontigs = getVisibleContigs(0, profileseq.getLength());
-    int spos = 0;
-    int offset = 0;
-    // input.pruneDeletions(ShiftList.parseMap(((SequenceI[])
-    // alandcolsel[0])[0].gapMap()))
-    // add profile to visible contigs
-    for (int v = 0; v < viscontigs.length; v += 2)
-    {
-      if (viscontigs[v] > spos)
-      {
-        StringBuffer sb = new StringBuffer();
-        for (int s = 0, ns = viscontigs[v] - spos; s < ns; s++)
-        {
-          sb.append(gc);
-        }
-        for (int s = 0, ns = al.getHeight(); s < ns; s++)
-        {
-          SequenceI sqobj = al.getSequenceAt(s);
-          if (sqobj != profileseq)
+          if (hiddenColumns != null
+                  && hiddenColumns.isVisible(col.intValue()))
           {
-            String sq = al.getSequenceAt(s).getSequenceAsString();
-            if (sq.length() <= spos + offset)
-            {
-              // pad sequence
-              int diff = spos + offset - sq.length() - 1;
-              if (diff > 0)
-              {
-                // pad gaps
-                sq = sq + sb;
-                while ((diff = spos + offset - sq.length() - 1) > 0)
-                {
-                  // sq = sq
-                  // + ((diff >= sb.length()) ? sb.toString() : sb
-                  // .substring(0, diff));
-                  if (diff >= sb.length())
-                  {
-                    sq += sb.toString();
-                  }
-                  else
-                  {
-                    char[] buf = new char[diff];
-                    sb.getChars(0, diff, buf, 0);
-                    sq += buf.toString();
-                  }
-                }
-              }
-              sq += sb.toString();
-            }
-            else
-            {
-              al.getSequenceAt(s).setSequence(
-                      sq.substring(0, spos + offset) + sb.toString()
-                              + sq.substring(spos + offset));
-            }
+            selection.add(col);
           }
         }
-        // offset+=sb.length();
-      }
-      spos = viscontigs[v + 1] + 1;
-    }
-    if ((offset + spos) < profileseq.getLength())
-    {
-      // pad the final region with gaps.
-      StringBuffer sb = new StringBuffer();
-      for (int s = 0, ns = profileseq.getLength() - spos - offset; s < ns; s++)
-      {
-        sb.append(gc);
       }
-      for (int s = 0, ns = al.getHeight(); s < ns; s++)
+      else
       {
-        SequenceI sqobj = al.getSequenceAt(s);
-        if (sqobj == profileseq)
-        {
-          continue;
-        }
-        String sq = sqobj.getSequenceAsString();
-        // pad sequence
-        int diff = origseq.getLength() - sq.length();
-        while (diff > 0)
+        // add everything regardless
+        for (Integer col : colsel.getSelected())
         {
-          // sq = sq
-          // + ((diff >= sb.length()) ? sb.toString() : sb
-          // .substring(0, diff));
-          if (diff >= sb.length())
-          {
-            sq += sb.toString();
-          }
-          else
-          {
-            char[] buf = new char[diff];
-            sb.getChars(0, diff, buf, 0);
-            sq += buf.toString();
-          }
-          diff = origseq.getLength() - sq.length();
+          addElement(col);
         }
       }
     }
   }
 
+
   /**
    * 
    * @return true if there are columns marked
@@ -1670,45 +544,13 @@ public class ColumnSelection
     return (selection != null && selection.size() > 0);
   }
 
-  /**
-   * 
-   * @return true if there are columns hidden
-   */
-  public boolean hasHiddenColumns()
-  {
-    return hiddenColumns != null && hiddenColumns.size() > 0;
-  }
-
-  /**
-   * 
-   * @return true if there are more than one set of columns hidden
-   */
-  public boolean hasManyHiddenColumns()
-  {
-    return hiddenColumns != null && hiddenColumns.size() > 1;
-  }
 
-  /**
-   * mark the columns corresponding to gap characters as hidden in the column
-   * selection
-   * 
-   * @param sr
-   */
-  public void hideInsertionsFor(SequenceI sr)
-  {
-    List<int[]> inserts = sr.getInsertions();
-    for (int[] r : inserts)
-    {
-      hideColumns(r[0], r[1]);
-    }
-  }
 
   public boolean filterAnnotations(Annotation[] annotations,
           AnnotationFilterParameter filterParams)
   {
     // JBPNote - this method needs to be refactored to become independent of
     // viewmodel package
-    this.revealAllHiddenColumns();
     this.clear();
     int count = 0;
     do
@@ -1791,21 +633,12 @@ public class ColumnSelection
   }
 
   /**
-   * Returns a hashCode built from selected columns and hidden column ranges
+   * Returns a hashCode built from selected columns ranges
    */
   @Override
   public int hashCode()
   {
-    int hashCode = selection.hashCode();
-    if (hiddenColumns != null)
-    {
-      for (int[] hidden : hiddenColumns)
-      {
-        hashCode = 31 * hashCode + hidden[0];
-        hashCode = 31 * hashCode + hidden[1];
-      }
-    }
-    return hashCode;
+    return selection.hashCode();
   }
 
   /**
@@ -1836,27 +669,6 @@ public class ColumnSelection
       return false;
     }
 
-    /*
-     * check hidden columns are either both null, or match
-     */
-    if (this.hiddenColumns == null)
-    {
-      return (that.hiddenColumns == null);
-    }
-    if (that.hiddenColumns == null
-            || that.hiddenColumns.size() != this.hiddenColumns.size())
-    {
-      return false;
-    }
-    int i = 0;
-    for (int[] thisRange : hiddenColumns)
-    {
-      int[] thatRange = that.hiddenColumns.get(i++);
-      if (thisRange[0] != thatRange[0] || thisRange[1] != thatRange[1])
-      {
-        return false;
-      }
-    }
     return true;
   }
 
diff --git a/src/jalview/datamodel/HiddenColumns.java b/src/jalview/datamodel/HiddenColumns.java
new file mode 100644 (file)
index 0000000..2edb3f1
--- /dev/null
@@ -0,0 +1,1264 @@
+package jalview.datamodel;
+
+import jalview.util.Comparison;
+import jalview.util.ShiftList;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Vector;
+
+public class HiddenColumns
+{
+  /*
+   * list of hidden column [start, end] ranges; the list is maintained in
+   * ascending start column order
+   */
+  private Vector<int[]> hiddenColumns;
+
+  /**
+   * This Method is used to return all the HiddenColumn regions
+   * 
+   * @return empty list or List of hidden column intervals
+   */
+  public List<int[]> getHiddenRegions()
+  {
+    return hiddenColumns == null ? Collections.<int[]> emptyList()
+            : hiddenColumns;
+  }
+
+  /**
+   * Find the number of hidden columns
+   * 
+   * @return number of hidden columns
+   */
+  public int getSize()
+  {
+    int size = 0;
+    if (hasHidden())
+    {
+      for (int[] range : hiddenColumns)
+      {
+        size += range[1] - range[0] + 1;
+      }
+    }
+    return size;
+  }
+
+  /**
+   * Answers if there are any hidden columns
+   * 
+   * @return true if there are hidden columns
+   */
+  public boolean hasHidden()
+  {
+    return (hiddenColumns != null) && (!hiddenColumns.isEmpty());
+  }
+
+  @Override
+  public boolean equals(Object obj)
+  {
+    if (!(obj instanceof HiddenColumns))
+    {
+      return false;
+    }
+    HiddenColumns that = (HiddenColumns) obj;
+
+    /*
+     * check hidden columns are either both null, or match
+     */
+    if (this.hiddenColumns == null)
+    {
+      return (that.hiddenColumns == null);
+    }
+    if (that.hiddenColumns == null
+            || that.hiddenColumns.size() != this.hiddenColumns.size())
+    {
+      return false;
+    }
+    int i = 0;
+    for (int[] thisRange : hiddenColumns)
+    {
+      int[] thatRange = that.hiddenColumns.get(i++);
+      if (thisRange[0] != thatRange[0] || thisRange[1] != thatRange[1])
+      {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Return absolute column index for a visible column index
+   * 
+   * @param column
+   *          int column index in alignment view (count from zero)
+   * @return alignment column index for column
+   */
+  public int adjustForHiddenColumns(int column)
+  {
+    int result = column;
+    if (hiddenColumns != null)
+    {
+      for (int i = 0; i < hiddenColumns.size(); i++)
+      {
+        int[] region = hiddenColumns.elementAt(i);
+        if (result >= region[0])
+        {
+          result += region[1] - region[0] + 1;
+        }
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Use this method to find out where a column will appear in the visible
+   * alignment when hidden columns exist. If the column is not visible, then the
+   * left-most visible column will always be returned.
+   * 
+   * @param hiddenColumn
+   *          the column index in the full alignment including hidden columns
+   * @return the position of the column in the visible alignment
+   */
+  public int findColumnPosition(int hiddenColumn)
+  {
+    int result = hiddenColumn;
+    if (hiddenColumns != null)
+    {
+      int index = 0;
+      int[] region;
+      do
+      {
+        region = hiddenColumns.elementAt(index++);
+        if (hiddenColumn > region[1])
+        {
+          result -= region[1] + 1 - region[0];
+        }
+      } while ((hiddenColumn > region[1]) && (index < hiddenColumns.size()));
+
+      if (hiddenColumn >= region[0] && hiddenColumn <= region[1])
+      {
+        // Here the hidden column is within a region, so
+        // we want to return the position of region[0]-1, adjusted for any
+        // earlier hidden columns.
+        // Calculate the difference between the actual hidden col position
+        // and region[0]-1, and then subtract from result to convert result from
+        // the adjusted hiddenColumn value to the adjusted region[0]-1 value
+
+        // However, if the region begins at 0 we cannot return region[0]-1
+        // just return 0
+        if (region[0] == 0)
+        {
+          return 0;
+        }
+        else
+        {
+          return result - (hiddenColumn - region[0] + 1);
+        }
+      }
+    }
+    return result; // return the shifted position after removing hidden columns.
+  }
+
+  /**
+   * Find the visible column which is a given visible number of columns to the
+   * left of another visible column. i.e. for a startColumn x, the column which
+   * is distance 1 away will be column x-1.
+   * 
+   * @param visibleDistance
+   *          the number of visible columns to offset by
+   * @param startColumn
+   *          the column to start from
+   * @return the position of the column in the visible alignment
+   */
+  public int subtractVisibleColumns(int visibleDistance, int startColumn)
+  {
+    int distance = visibleDistance;
+
+    // in case startColumn is in a hidden region, move it to the left
+    int start = adjustForHiddenColumns(findColumnPosition(startColumn));
+
+    // get index of hidden region to left of start
+    int index = getHiddenIndexLeft(start);
+    if (index == -1)
+    {
+      // no hidden regions to left of startColumn
+      return start - distance;
+    }
+
+    // walk backwards through the alignment subtracting the counts of visible
+    // columns from distance
+    int[] region;
+    int gap = 0;
+    int nextstart = start;
+
+    while ((index > -1) && (distance - gap > 0))
+    {
+      // subtract the gap to right of region from distance
+      distance -= gap;
+      start = nextstart;
+
+      // calculate the next gap
+      region = hiddenColumns.get(index);
+      gap = start - region[1];
+
+      // set start to just to left of current region
+      nextstart = region[0] - 1;
+      index--;
+    }
+
+    if (distance - gap > 0)
+    {
+      // fell out of loop because there are no more hidden regions
+      distance -= gap;
+      return nextstart - distance;
+    }
+    return start - distance;
+
+  }
+
+  /**
+   * Use this method to determine where the next hiddenRegion starts
+   * 
+   * @param hiddenRegion
+   *          index of hidden region (counts from 0)
+   * @return column number in visible view
+   */
+  public int findHiddenRegionPosition(int hiddenRegion)
+  {
+    int result = 0;
+    if (hiddenColumns != null)
+    {
+      int index = 0;
+      int gaps = 0;
+      do
+      {
+        int[] region = hiddenColumns.elementAt(index);
+        if (hiddenRegion == 0)
+        {
+          return region[0];
+        }
+
+        gaps += region[1] + 1 - region[0];
+        result = region[1] + 1;
+        index++;
+      } while (index <= hiddenRegion);
+
+      result -= gaps;
+    }
+
+    return result;
+  }
+
+  /**
+   * This method returns the rightmost limit of a region of an alignment with
+   * hidden columns. In otherwords, the next hidden column.
+   * 
+   * @param index
+   *          int
+   */
+  public int getHiddenBoundaryRight(int alPos)
+  {
+    if (hiddenColumns != null)
+    {
+      int index = 0;
+      do
+      {
+        int[] region = hiddenColumns.elementAt(index);
+        if (alPos < region[0])
+        {
+          return region[0];
+        }
+
+        index++;
+      } while (index < hiddenColumns.size());
+    }
+
+    return alPos;
+
+  }
+
+  /**
+   * This method returns the leftmost limit of a region of an alignment with
+   * hidden columns. In otherwords, the previous hidden column.
+   * 
+   * @param index
+   *          int
+   */
+  public int getHiddenBoundaryLeft(int alPos)
+  {
+    if (hiddenColumns != null)
+    {
+      int index = hiddenColumns.size() - 1;
+      do
+      {
+        int[] region = hiddenColumns.elementAt(index);
+        if (alPos > region[1])
+        {
+          return region[1];
+        }
+
+        index--;
+      } while (index > -1);
+    }
+
+    return alPos;
+
+  }
+
+  /**
+   * This method returns the index of the hidden region to the left of a column
+   * position. If the column is in a hidden region it returns the index of the
+   * region to the left. If there is no hidden region to the left it returns -1.
+   * 
+   * @param pos
+   *          int
+   */
+  private int getHiddenIndexLeft(int pos)
+  {
+    if (hiddenColumns != null)
+    {
+      int index = hiddenColumns.size() - 1;
+      do
+      {
+        int[] region = hiddenColumns.elementAt(index);
+        if (pos > region[1])
+        {
+          return index;
+        }
+
+        index--;
+      } while (index > -1);
+    }
+
+    return -1;
+
+  }
+
+  /**
+   * Adds the specified column range to the hidden columns
+   * 
+   * @param start
+   * @param end
+   */
+  public void hideColumns(int start, int end)
+  {
+    if (hiddenColumns == null)
+    {
+      hiddenColumns = new Vector<int[]>();
+    }
+
+    /*
+     * traverse existing hidden ranges and insert / amend / append as
+     * appropriate
+     */
+    for (int i = 0; i < hiddenColumns.size(); i++)
+    {
+      int[] region = hiddenColumns.elementAt(i);
+
+      if (end < region[0] - 1)
+      {
+        /*
+         * insert discontiguous preceding range
+         */
+        hiddenColumns.insertElementAt(new int[] { start, end }, i);
+        return;
+      }
+
+      if (end <= region[1])
+      {
+        /*
+         * new range overlaps existing, or is contiguous preceding it - adjust
+         * start column
+         */
+        region[0] = Math.min(region[0], start);
+        return;
+      }
+
+      if (start <= region[1] + 1)
+      {
+        /*
+         * new range overlaps existing, or is contiguous following it - adjust
+         * start and end columns
+         */
+        region[0] = Math.min(region[0], start);
+        region[1] = Math.max(region[1], end);
+
+        /*
+         * also update or remove any subsequent ranges 
+         * that are overlapped
+         */
+        while (i < hiddenColumns.size() - 1)
+        {
+          int[] nextRegion = hiddenColumns.get(i + 1);
+          if (nextRegion[0] > end + 1)
+          {
+            /*
+             * gap to next hidden range - no more to update
+             */
+            break;
+          }
+          region[1] = Math.max(nextRegion[1], end);
+          hiddenColumns.remove(i + 1);
+        }
+        return;
+      }
+    }
+
+    /*
+     * remaining case is that the new range follows everything else
+     */
+    hiddenColumns.addElement(new int[] { start, end });
+  }
+
+  public boolean isVisible(int column)
+  {
+    if (hiddenColumns != null)
+    {
+      for (int[] region : hiddenColumns)
+      {
+        if (column >= region[0] && column <= region[1])
+        {
+          return false;
+        }
+      }
+    }
+
+    return true;
+  }
+
+  /**
+   * ColumnSelection
+   */
+  public HiddenColumns()
+  {
+  }
+
+  /**
+   * Copy constructor
+   * 
+   * @param copy
+   */
+  public HiddenColumns(HiddenColumns copy)
+  {
+    if (copy != null)
+    {
+      if (copy.hiddenColumns != null)
+      {
+        hiddenColumns = new Vector<int[]>(copy.hiddenColumns.size());
+        for (int i = 0, j = copy.hiddenColumns.size(); i < j; i++)
+        {
+          int[] rh, cp;
+          rh = copy.hiddenColumns.elementAt(i);
+          if (rh != null)
+          {
+            cp = new int[rh.length];
+            System.arraycopy(rh, 0, cp, 0, rh.length);
+            hiddenColumns.addElement(cp);
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * propagate shift in alignment columns to column selection
+   * 
+   * @param start
+   *          beginning of edit
+   * @param left
+   *          shift in edit (+ve for removal, or -ve for inserts)
+   */
+  public List<int[]> compensateForEdit(int start, int change,
+          ColumnSelection sel)
+  {
+    List<int[]> deletedHiddenColumns = null;
+
+    if (hiddenColumns != null)
+    {
+      deletedHiddenColumns = new ArrayList<int[]>();
+      int hSize = hiddenColumns.size();
+      for (int i = 0; i < hSize; i++)
+      {
+        int[] region = hiddenColumns.elementAt(i);
+        if (region[0] > start && start + change > region[1])
+        {
+          deletedHiddenColumns.add(region);
+
+          hiddenColumns.removeElementAt(i);
+          i--;
+          hSize--;
+          continue;
+        }
+
+        if (region[0] > start)
+        {
+          region[0] -= change;
+          region[1] -= change;
+        }
+
+        if (region[0] < 0)
+        {
+          region[0] = 0;
+        }
+
+      }
+
+      this.revealHiddenColumns(0, sel);
+    }
+
+    return deletedHiddenColumns;
+  }
+
+  /**
+   * propagate shift in alignment columns to column selection special version of
+   * compensateForEdit - allowing for edits within hidden regions
+   * 
+   * @param start
+   *          beginning of edit
+   * @param left
+   *          shift in edit (+ve for removal, or -ve for inserts)
+   */
+  public void compensateForDelEdits(int start, int change)
+  {
+    if (hiddenColumns != null)
+    {
+      for (int i = 0; i < hiddenColumns.size(); i++)
+      {
+        int[] region = hiddenColumns.elementAt(i);
+        if (region[0] >= start)
+        {
+          region[0] -= change;
+        }
+        if (region[1] >= start)
+        {
+          region[1] -= change;
+        }
+        if (region[1] < region[0])
+        {
+          hiddenColumns.removeElementAt(i--);
+        }
+
+        if (region[0] < 0)
+        {
+          region[0] = 0;
+        }
+        if (region[1] < 0)
+        {
+          region[1] = 0;
+        }
+      }
+    }
+  }
+
+  /**
+   * return all visible segments between the given start and end boundaries
+   * 
+   * @param start
+   *          (first column inclusive from 0)
+   * @param end
+   *          (last column - not inclusive)
+   * @return int[] {i_start, i_end, ..} where intervals lie in
+   *         start<=i_start<=i_end<end
+   */
+  public int[] getVisibleContigs(int start, int end)
+  {
+    if (hiddenColumns != null && hiddenColumns.size() > 0)
+    {
+      List<int[]> visiblecontigs = new ArrayList<int[]>();
+      List<int[]> regions = getHiddenRegions();
+
+      int vstart = start;
+      int[] region;
+      int hideStart, hideEnd;
+
+      for (int j = 0; vstart < end && j < regions.size(); j++)
+      {
+        region = regions.get(j);
+        hideStart = region[0];
+        hideEnd = region[1];
+
+        if (hideEnd < vstart)
+        {
+          continue;
+        }
+        if (hideStart > vstart)
+        {
+          visiblecontigs.add(new int[] { vstart, hideStart - 1 });
+        }
+        vstart = hideEnd + 1;
+      }
+
+      if (vstart < end)
+      {
+        visiblecontigs.add(new int[] { vstart, end - 1 });
+      }
+      int[] vcontigs = new int[visiblecontigs.size() * 2];
+      for (int i = 0, j = visiblecontigs.size(); i < j; i++)
+      {
+        int[] vc = visiblecontigs.get(i);
+        visiblecontigs.set(i, null);
+        vcontigs[i * 2] = vc[0];
+        vcontigs[i * 2 + 1] = vc[1];
+      }
+      visiblecontigs.clear();
+      return vcontigs;
+    }
+    else
+    {
+      return new int[] { start, end - 1 };
+    }
+  }
+
+  public String[] getVisibleSequenceStrings(int start, int end,
+          SequenceI[] seqs)
+  {
+    int i, iSize = seqs.length;
+    String selections[] = new String[iSize];
+    if (hiddenColumns != null && hiddenColumns.size() > 0)
+    {
+      for (i = 0; i < iSize; i++)
+      {
+        StringBuffer visibleSeq = new StringBuffer();
+        List<int[]> regions = getHiddenRegions();
+
+        int blockStart = start, blockEnd = end;
+        int[] region;
+        int hideStart, hideEnd;
+
+        for (int j = 0; j < regions.size(); j++)
+        {
+          region = regions.get(j);
+          hideStart = region[0];
+          hideEnd = region[1];
+
+          if (hideStart < start)
+          {
+            continue;
+          }
+
+          blockStart = Math.min(blockStart, hideEnd + 1);
+          blockEnd = Math.min(blockEnd, hideStart);
+
+          if (blockStart > blockEnd)
+          {
+            break;
+          }
+
+          visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));
+
+          blockStart = hideEnd + 1;
+          blockEnd = end;
+        }
+
+        if (end > blockStart)
+        {
+          visibleSeq.append(seqs[i].getSequence(blockStart, end));
+        }
+
+        selections[i] = visibleSeq.toString();
+      }
+    }
+    else
+    {
+      for (i = 0; i < iSize; i++)
+      {
+        selections[i] = seqs[i].getSequenceAsString(start, end);
+      }
+    }
+
+    return selections;
+  }
+
+  /**
+   * Locate the first and last position visible for this sequence. if seq isn't
+   * visible then return the position of the left and right of the hidden
+   * boundary region, and the corresponding alignment column indices for the
+   * extent of the sequence
+   * 
+   * @param seq
+   * @return int[] { visible start, visible end, first seqpos, last seqpos,
+   *         alignment index for seq start, alignment index for seq end }
+   */
+  public int[] locateVisibleBoundsOfSequence(SequenceI seq)
+  {
+    int fpos = seq.getStart(), lpos = seq.getEnd();
+    int start = 0;
+
+    if (hiddenColumns == null || hiddenColumns.size() == 0)
+    {
+      int ifpos = seq.findIndex(fpos) - 1, ilpos = seq.findIndex(lpos) - 1;
+      return new int[] { ifpos, ilpos, fpos, lpos, ifpos, ilpos };
+    }
+
+    // Simply walk along the sequence whilst watching for hidden column
+    // boundaries
+    List<int[]> regions = getHiddenRegions();
+    int spos = fpos, lastvispos = -1, rcount = 0, hideStart = seq
+            .getLength(), hideEnd = -1;
+    int visPrev = 0, visNext = 0, firstP = -1, lastP = -1;
+    boolean foundStart = false;
+    for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd()
+            && p < pLen; p++)
+    {
+      if (!Comparison.isGap(seq.getCharAt(p)))
+      {
+        // keep track of first/last column
+        // containing sequence data regardless of visibility
+        if (firstP == -1)
+        {
+          firstP = p;
+        }
+        lastP = p;
+        // update hidden region start/end
+        while (hideEnd < p && rcount < regions.size())
+        {
+          int[] region = regions.get(rcount++);
+          visPrev = visNext;
+          visNext += region[0] - visPrev;
+          hideStart = region[0];
+          hideEnd = region[1];
+        }
+        if (hideEnd < p)
+        {
+          hideStart = seq.getLength();
+        }
+        // update visible boundary for sequence
+        if (p < hideStart)
+        {
+          if (!foundStart)
+          {
+            fpos = spos;
+            start = p;
+            foundStart = true;
+          }
+          lastvispos = p;
+          lpos = spos;
+        }
+        // look for next sequence position
+        spos++;
+      }
+    }
+    if (foundStart)
+    {
+      return new int[] { findColumnPosition(start),
+          findColumnPosition(lastvispos), fpos, lpos, firstP, lastP };
+    }
+    // otherwise, sequence was completely hidden
+    return new int[] { visPrev, visNext, 0, 0, firstP, lastP };
+  }
+
+  /**
+   * delete any columns in alignmentAnnotation that are hidden (including
+   * sequence associated annotation).
+   * 
+   * @param alignmentAnnotation
+   */
+  public void makeVisibleAnnotation(AlignmentAnnotation alignmentAnnotation)
+  {
+    makeVisibleAnnotation(-1, -1, alignmentAnnotation);
+  }
+
+  /**
+   * delete any columns in alignmentAnnotation that are hidden (including
+   * sequence associated annotation).
+   * 
+   * @param start
+   *          remove any annotation to the right of this column
+   * @param end
+   *          remove any annotation to the left of this column
+   * @param alignmentAnnotation
+   *          the annotation to operate on
+   */
+  public void makeVisibleAnnotation(int start, int end,
+          AlignmentAnnotation alignmentAnnotation)
+  {
+    if (alignmentAnnotation.annotations == null)
+    {
+      return;
+    }
+    if (start == end && end == -1)
+    {
+      start = 0;
+      end = alignmentAnnotation.annotations.length;
+    }
+    if (hiddenColumns != null && hiddenColumns.size() > 0)
+    {
+      // then mangle the alignmentAnnotation annotation array
+      Vector<Annotation[]> annels = new Vector<Annotation[]>();
+      Annotation[] els = null;
+      List<int[]> regions = getHiddenRegions();
+      int blockStart = start, blockEnd = end;
+      int[] region;
+      int hideStart, hideEnd, w = 0;
+
+      for (int j = 0; j < regions.size(); j++)
+      {
+        region = regions.get(j);
+        hideStart = region[0];
+        hideEnd = region[1];
+
+        if (hideStart < start)
+        {
+          continue;
+        }
+
+        blockStart = Math.min(blockStart, hideEnd + 1);
+        blockEnd = Math.min(blockEnd, hideStart);
+
+        if (blockStart > blockEnd)
+        {
+          break;
+        }
+
+        annels.addElement(els = new Annotation[blockEnd - blockStart]);
+        System.arraycopy(alignmentAnnotation.annotations, blockStart, els,
+                0, els.length);
+        w += els.length;
+        blockStart = hideEnd + 1;
+        blockEnd = end;
+      }
+
+      if (end > blockStart)
+      {
+        annels.addElement(els = new Annotation[end - blockStart + 1]);
+        if ((els.length + blockStart) <= alignmentAnnotation.annotations.length)
+        {
+          // copy just the visible segment of the annotation row
+          System.arraycopy(alignmentAnnotation.annotations, blockStart,
+                  els, 0, els.length);
+        }
+        else
+        {
+          // copy to the end of the annotation row
+          System.arraycopy(alignmentAnnotation.annotations, blockStart,
+                  els, 0,
+                  (alignmentAnnotation.annotations.length - blockStart));
+        }
+        w += els.length;
+      }
+      if (w == 0)
+      {
+        return;
+      }
+
+      alignmentAnnotation.annotations = new Annotation[w];
+      w = 0;
+
+      for (Annotation[] chnk : annels)
+      {
+        System.arraycopy(chnk, 0, alignmentAnnotation.annotations, w,
+                chnk.length);
+        w += chnk.length;
+      }
+    }
+    else
+    {
+      alignmentAnnotation.restrict(start, end);
+    }
+  }
+
+  /**
+   * 
+   * @return true if there are columns hidden
+   */
+  public boolean hasHiddenColumns()
+  {
+    return hiddenColumns != null && hiddenColumns.size() > 0;
+  }
+
+  /**
+   * 
+   * @return true if there are more than one set of columns hidden
+   */
+  public boolean hasManyHiddenColumns()
+  {
+    return hiddenColumns != null && hiddenColumns.size() > 1;
+  }
+
+  /**
+   * mark the columns corresponding to gap characters as hidden in the column
+   * selection
+   * 
+   * @param sr
+   */
+  public void hideInsertionsFor(SequenceI sr)
+  {
+    List<int[]> inserts = sr.getInsertions();
+    for (int[] r : inserts)
+    {
+      hideColumns(r[0], r[1]);
+    }
+  }
+
+  /**
+   * Unhides, and adds to the selection list, all hidden columns
+   */
+  public void revealAllHiddenColumns(ColumnSelection sel)
+  {
+    if (hiddenColumns != null)
+    {
+      for (int i = 0; i < hiddenColumns.size(); i++)
+      {
+        int[] region = hiddenColumns.elementAt(i);
+        for (int j = region[0]; j < region[1] + 1; j++)
+        {
+          sel.addElement(j);
+        }
+      }
+    }
+
+    hiddenColumns = null;
+  }
+
+  /**
+   * Reveals, and marks as selected, the hidden column range with the given
+   * start column
+   * 
+   * @param start
+   */
+  public void revealHiddenColumns(int start, ColumnSelection sel)
+  {
+    for (int i = 0; i < hiddenColumns.size(); i++)
+    {
+      int[] region = hiddenColumns.elementAt(i);
+      if (start == region[0])
+      {
+        for (int j = region[0]; j < region[1] + 1; j++)
+        {
+          sel.addElement(j);
+        }
+
+        hiddenColumns.removeElement(region);
+        break;
+      }
+    }
+    if (hiddenColumns.size() == 0)
+    {
+      hiddenColumns = null;
+    }
+  }
+
+  /**
+   * removes intersection of position,length ranges in deletions from the
+   * start,end regions marked in intervals.
+   * 
+   * @param shifts
+   * @param intervals
+   * @return
+   */
+  private boolean pruneIntervalVector(final List<int[]> shifts,
+          Vector<int[]> intervals)
+  {
+    boolean pruned = false;
+    int i = 0, j = intervals.size() - 1, s = 0, t = shifts.size() - 1;
+    int hr[] = intervals.elementAt(i);
+    int sr[] = shifts.get(s);
+    while (i <= j && s <= t)
+    {
+      boolean trailinghn = hr[1] >= sr[0];
+      if (!trailinghn)
+      {
+        if (i < j)
+        {
+          hr = intervals.elementAt(++i);
+        }
+        else
+        {
+          i++;
+        }
+        continue;
+      }
+      int endshift = sr[0] + sr[1]; // deletion ranges - -ve means an insert
+      if (endshift < hr[0] || endshift < sr[0])
+      { // leadinghc disjoint or not a deletion
+        if (s < t)
+        {
+          sr = shifts.get(++s);
+        }
+        else
+        {
+          s++;
+        }
+        continue;
+      }
+      boolean leadinghn = hr[0] >= sr[0];
+      boolean leadinghc = hr[0] < endshift;
+      boolean trailinghc = hr[1] < endshift;
+      if (leadinghn)
+      {
+        if (trailinghc)
+        { // deleted hidden region.
+          intervals.removeElementAt(i);
+          pruned = true;
+          j--;
+          if (i <= j)
+          {
+            hr = intervals.elementAt(i);
+          }
+          continue;
+        }
+        if (leadinghc)
+        {
+          hr[0] = endshift; // clip c terminal region
+          leadinghn = !leadinghn;
+          pruned = true;
+        }
+      }
+      if (!leadinghn)
+      {
+        if (trailinghc)
+        {
+          if (trailinghn)
+          {
+            hr[1] = sr[0] - 1;
+            pruned = true;
+          }
+        }
+        else
+        {
+          // sr contained in hr
+          if (s < t)
+          {
+            sr = shifts.get(++s);
+          }
+          else
+          {
+            s++;
+          }
+          continue;
+        }
+      }
+    }
+    return pruned; // true if any interval was removed or modified by
+    // operations.
+  }
+
+  /**
+   * remove any hiddenColumns or selected columns and shift remaining based on a
+   * series of position, range deletions.
+   * 
+   * @param deletions
+   */
+  public void pruneDeletions(List<int[]> shifts)
+  {
+    // delete any intervals intersecting.
+    if (hiddenColumns != null)
+    {
+      pruneIntervalVector(shifts, hiddenColumns);
+      if (hiddenColumns != null && hiddenColumns.size() == 0)
+      {
+        hiddenColumns = null;
+      }
+    }
+  }
+
+  /**
+   * Add gaps into the sequences aligned to profileseq under the given
+   * AlignmentView
+   * 
+   * @param profileseq
+   * @param al
+   *          - alignment to have gaps inserted into it
+   * @param input
+   *          - alignment view where sequence corresponding to profileseq is
+   *          first entry
+   * @return new HiddenColumns for new alignment view, with insertions into
+   *         profileseq marked as hidden.
+   */
+  public static HiddenColumns propagateInsertions(SequenceI profileseq,
+          AlignmentI al, AlignmentView input)
+  {
+    int profsqpos = 0;
+
+    char gc = al.getGapCharacter();
+    Object[] alandhidden = input.getAlignmentAndHiddenColumns(gc);
+    HiddenColumns nview = (HiddenColumns) alandhidden[1];
+    SequenceI origseq = ((SequenceI[]) alandhidden[0])[profsqpos];
+    nview.propagateInsertions(profileseq, al, origseq);
+    return nview;
+  }
+
+  /**
+   * 
+   * @param profileseq
+   *          - sequence in al which corresponds to origseq
+   * @param al
+   *          - alignment which is to have gaps inserted into it
+   * @param origseq
+   *          - sequence corresponding to profileseq which defines gap map for
+   *          modifying al
+   */
+  private void propagateInsertions(SequenceI profileseq, AlignmentI al,
+          SequenceI origseq)
+  {
+    char gc = al.getGapCharacter();
+    // recover mapping between sequence's non-gap positions and positions
+    // mapping to view.
+    pruneDeletions(ShiftList.parseMap(origseq.gapMap()));
+    int[] viscontigs = al.getHiddenColumns().getVisibleContigs(0,
+            profileseq.getLength());
+    int spos = 0;
+    int offset = 0;
+
+    // add profile to visible contigs
+    for (int v = 0; v < viscontigs.length; v += 2)
+    {
+      if (viscontigs[v] > spos)
+      {
+        StringBuffer sb = new StringBuffer();
+        for (int s = 0, ns = viscontigs[v] - spos; s < ns; s++)
+        {
+          sb.append(gc);
+        }
+        for (int s = 0, ns = al.getHeight(); s < ns; s++)
+        {
+          SequenceI sqobj = al.getSequenceAt(s);
+          if (sqobj != profileseq)
+          {
+            String sq = al.getSequenceAt(s).getSequenceAsString();
+            if (sq.length() <= spos + offset)
+            {
+              // pad sequence
+              int diff = spos + offset - sq.length() - 1;
+              if (diff > 0)
+              {
+                // pad gaps
+                sq = sq + sb;
+                while ((diff = spos + offset - sq.length() - 1) > 0)
+                {
+                  // sq = sq
+                  // + ((diff >= sb.length()) ? sb.toString() : sb
+                  // .substring(0, diff));
+                  if (diff >= sb.length())
+                  {
+                    sq += sb.toString();
+                  }
+                  else
+                  {
+                    char[] buf = new char[diff];
+                    sb.getChars(0, diff, buf, 0);
+                    sq += buf.toString();
+                  }
+                }
+              }
+              sq += sb.toString();
+            }
+            else
+            {
+              al.getSequenceAt(s).setSequence(
+                      sq.substring(0, spos + offset) + sb.toString()
+                              + sq.substring(spos + offset));
+            }
+          }
+        }
+        // offset+=sb.length();
+      }
+      spos = viscontigs[v + 1] + 1;
+    }
+    if ((offset + spos) < profileseq.getLength())
+    {
+      // pad the final region with gaps.
+      StringBuffer sb = new StringBuffer();
+      for (int s = 0, ns = profileseq.getLength() - spos - offset; s < ns; s++)
+      {
+        sb.append(gc);
+      }
+      for (int s = 0, ns = al.getHeight(); s < ns; s++)
+      {
+        SequenceI sqobj = al.getSequenceAt(s);
+        if (sqobj == profileseq)
+        {
+          continue;
+        }
+        String sq = sqobj.getSequenceAsString();
+        // pad sequence
+        int diff = origseq.getLength() - sq.length();
+        while (diff > 0)
+        {
+          // sq = sq
+          // + ((diff >= sb.length()) ? sb.toString() : sb
+          // .substring(0, diff));
+          if (diff >= sb.length())
+          {
+            sq += sb.toString();
+          }
+          else
+          {
+            char[] buf = new char[diff];
+            sb.getChars(0, diff, buf, 0);
+            sq += buf.toString();
+          }
+          diff = origseq.getLength() - sq.length();
+        }
+      }
+    }
+  }
+
+  /**
+   * remove any hiddenColumns or selected columns and shift remaining based on a
+   * series of position, range deletions.
+   * 
+   * @param deletions
+   */
+  private void pruneDeletions(ShiftList deletions)
+  {
+    if (deletions != null)
+    {
+      final List<int[]> shifts = deletions.getShifts();
+      if (shifts != null && shifts.size() > 0)
+      {
+        pruneDeletions(shifts);
+
+        // and shift the rest.
+        this.compensateForEdits(deletions);
+      }
+    }
+  }
+
+  /**
+   * Adjust hidden column boundaries based on a series of column additions or
+   * deletions in visible regions.
+   * 
+   * @param shiftrecord
+   * @return
+   */
+  private ShiftList compensateForEdits(ShiftList shiftrecord)
+  {
+    if (shiftrecord != null)
+    {
+      final List<int[]> shifts = shiftrecord.getShifts();
+      if (shifts != null && shifts.size() > 0)
+      {
+        int shifted = 0;
+        for (int i = 0, j = shifts.size(); i < j; i++)
+        {
+          int[] sh = shifts.get(i);
+          compensateForDelEdits(shifted + sh[0], sh[1]);
+          shifted -= sh[1];
+        }
+      }
+      return shiftrecord.getInverse();
+    }
+    return null;
+  }
+
+  /**
+   * Returns a hashCode built from hidden column ranges
+   */
+  public int hashCode(int hc)
+  {
+    int hashCode = hc;
+    if (hiddenColumns != null)
+    {
+      for (int[] hidden : hiddenColumns)
+      {
+        hashCode = 31 * hashCode + hidden[0];
+        hashCode = 31 * hashCode + hidden[1];
+      }
+    }
+    return hashCode;
+  }
+
+}
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;
+  }
 }
index 98b0de5..9cc7b4a 100644 (file)
@@ -494,18 +494,18 @@ public class SeqCigar extends CigarSimple
   /**
    * create an alignment from the given array of cigar sequences and gap
    * character, and marking the given segments as visible in the given
-   * columselection.
+   * hiddenColumns.
    * 
    * @param alseqs
    * @param gapCharacter
-   * @param colsel
-   *          - columnSelection where hidden regions are marked
+   * @param hidden
+   *          - hiddenColumns where hidden regions are marked
    * @param segments
    *          - visible regions of alignment
    * @return SequenceI[]
    */
   public static SequenceI[] createAlignmentSequences(SeqCigar[] alseqs,
-          char gapCharacter, ColumnSelection colsel, int[] segments)
+          char gapCharacter, HiddenColumns hidden, int[] segments)
   {
     SequenceI[] seqs = new SequenceI[alseqs.length];
     StringBuffer[] g_seqs = new StringBuffer[alseqs.length];
@@ -577,7 +577,7 @@ public class SeqCigar extends CigarSimple
           if (segments == null)
           {
             // add a hidden column for this deletion
-            colsel.hideColumns(inspos, inspos + insert.length - 1);
+            hidden.hideColumns(inspos, inspos + insert.length - 1);
           }
         }
       }
@@ -598,7 +598,7 @@ public class SeqCigar extends CigarSimple
       {
         // int start=shifts.shift(segments[i]-1)+1;
         // int end=shifts.shift(segments[i]+segments[i+1]-1)-1;
-        colsel.hideColumns(segments[i + 1], segments[i + 1]
+        hidden.hideColumns(segments[i + 1], segments[i + 1]
                 + segments[i + 2] - 1);
       }
     }
diff --git a/src/jalview/datamodel/VisibleColsCollection.java b/src/jalview/datamodel/VisibleColsCollection.java
new file mode 100644 (file)
index 0000000..86233ab
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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 jalview.api.AlignmentColsCollectionI;
+
+import java.util.Iterator;
+
+public class VisibleColsCollection implements AlignmentColsCollectionI
+{
+  int start;
+  int end;
+
+  HiddenColumns hidden;
+
+  public VisibleColsCollection(int s, int e, AlignmentI al)
+  {
+    start = s;
+    end = e;
+    hidden = al.getHiddenColumns();
+  }
+
+  @Override
+  public Iterator<Integer> iterator()
+  {
+    return new VisibleColsIterator(start, end, hidden);
+  }
+
+  @Override
+  public boolean isHidden(int c)
+  {
+    return false;
+  }
+
+}
diff --git a/src/jalview/datamodel/VisibleColsIterator.java b/src/jalview/datamodel/VisibleColsIterator.java
new file mode 100644 (file)
index 0000000..70de1e3
--- /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,
+          HiddenColumns hiddenCols)
+  {
+    last = lastcol;
+    current = firstcol;
+    next = firstcol;
+    hidden = hiddenCols.getHiddenRegions();
+    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/VisibleRowsCollection.java b/src/jalview/datamodel/VisibleRowsCollection.java
new file mode 100644 (file)
index 0000000..ce8e8da
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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 jalview.api.AlignmentRowsCollectionI;
+
+import java.util.Iterator;
+
+public class VisibleRowsCollection implements AlignmentRowsCollectionI
+{
+  int start;
+
+  int end;
+
+  AlignmentI alignment;
+
+  public VisibleRowsCollection(int s, int e, AlignmentI al)
+  {
+    start = s;
+    end = e;
+    alignment = al;
+  }
+
+  @Override
+  public Iterator<Integer> iterator()
+  {
+    return new VisibleRowsIterator(start, end, alignment);
+  }
+
+  @Override
+  public boolean isHidden(int seq)
+  {
+    return false;
+  }
+
+  @Override
+  public SequenceI getSequence(int seq)
+  {
+    return alignment.getSequenceAtAbsoluteIndex(seq);
+  }
+}
+
diff --git a/src/jalview/datamodel/VisibleRowsIterator.java b/src/jalview/datamodel/VisibleRowsIterator.java
new file mode 100644 (file)
index 0000000..a9c782d
--- /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 (last > current && hidden.isHidden(last))
+    {
+      last--;
+    }
+    current = firstrow;
+    while (current < last && hidden.isHidden(current))
+    {
+      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 (next <= last && hidden.isHidden(next));
+    return current;
+  }
+
+  @Override
+  public void remove()
+  {
+    throw new UnsupportedOperationException();
+  }
+}
+
index 94df99a..00fd679 100644 (file)
@@ -24,7 +24,7 @@ import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureRenderer;
 import jalview.api.SequenceRenderer;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.io.DataSourceType;
@@ -222,11 +222,11 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
    *          TODO
    */
   public void superposeStructures(AlignmentI alignment, int refStructure,
-          ColumnSelection hiddenCols)
+          HiddenColumns hiddenCols)
   {
     superposeStructures(new AlignmentI[] { alignment },
             new int[] { refStructure },
-            new ColumnSelection[] { hiddenCols });
+ new HiddenColumns[] { hiddenCols });
   }
 
   /**
@@ -234,7 +234,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
    */
   @Override
   public String superposeStructures(AlignmentI[] _alignment,
-          int[] _refStructure, ColumnSelection[] _hiddenCols)
+          int[] _refStructure, HiddenColumns[] _hiddenCols)
   {
     while (viewer.isScriptExecuting())
     {
@@ -278,7 +278,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     {
       int refStructure = _refStructure[a];
       AlignmentI alignment = _alignment[a];
-      ColumnSelection hiddenCols = _hiddenCols[a];
+      HiddenColumns hiddenCols = _hiddenCols[a];
       if (a > 0
               && selectioncom.length() > 0
               && !selectioncom.substring(selectioncom.length() - 1).equals(
index 23e0a6f..3e7ca59 100644 (file)
@@ -25,7 +25,7 @@ import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureRenderer;
 import jalview.api.SequenceRenderer;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.seqfeatures.FeatureColourFinder;
 import jalview.structure.StructureMapping;
@@ -61,7 +61,7 @@ public class JmolCommands
     FeatureRenderer fr = viewPanel.getFeatureRenderer();
     FeatureColourFinder finder = new FeatureColourFinder(fr);
     AlignViewportI viewport = viewPanel.getAlignViewport();
-    ColumnSelection cs = viewport.getColumnSelection();
+    HiddenColumns cs = viewport.getAlignment().getHiddenColumns();
     AlignmentI al = viewport.getAlignment();
     List<StructureMappingcommandSet> cset = new ArrayList<StructureMappingcommandSet>();
 
index 95757fd..62aaa1c 100644 (file)
@@ -25,7 +25,7 @@ import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureRenderer;
 import jalview.api.SequenceRenderer;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.seqfeatures.FeatureColourFinder;
@@ -194,7 +194,7 @@ public class ChimeraCommands
     FeatureRenderer fr = viewPanel.getFeatureRenderer();
     FeatureColourFinder finder = new FeatureColourFinder(fr);
     AlignViewportI viewport = viewPanel.getAlignViewport();
-    ColumnSelection cs = viewport.getColumnSelection();
+    HiddenColumns cs = viewport.getAlignment().getHiddenColumns();
     AlignmentI al = viewport.getAlignment();
     Map<Object, AtomSpecModel> colourMap = new LinkedHashMap<Object, AtomSpecModel>();
     Color lastColour = null;
index ffce90c..870c4fe 100644 (file)
@@ -25,7 +25,7 @@ import jalview.api.SequenceRenderer;
 import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.Cache;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResultsI;
@@ -337,7 +337,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
    */
   @Override
   public String superposeStructures(AlignmentI[] _alignment,
-          int[] _refStructure, ColumnSelection[] _hiddenCols)
+          int[] _refStructure, HiddenColumns[] _hiddenCols)
   {
     StringBuilder allComs = new StringBuilder(128);
     String[] files = getPdbFile();
@@ -353,7 +353,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     {
       int refStructure = _refStructure[a];
       AlignmentI alignment = _alignment[a];
-      ColumnSelection hiddenCols = _hiddenCols[a];
+      HiddenColumns hiddenCols = _hiddenCols[a];
 
       if (refStructure >= files.length)
       {
index 016ee85..4073e3e 100644 (file)
@@ -53,6 +53,7 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SeqCigar;
@@ -233,7 +234,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * @param height
    *          height of frame.
    */
-  public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
+  public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns,
           int width, int height)
   {
     this(al, hiddenColumns, width, height, null);
@@ -250,7 +251,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * @param sequenceSetId
    *          (may be null)
    */
-  public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
+  public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns,
           int width, int height, String sequenceSetId)
   {
     this(al, hiddenColumns, width, height, sequenceSetId, null);
@@ -269,7 +270,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * @param viewId
    *          (may be null)
    */
-  public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
+  public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns,
           int width, int height, String sequenceSetId, String viewId)
   {
     setSize(width, height);
@@ -288,7 +289,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs,
-          ColumnSelection hiddenColumns, int width, int height)
+          HiddenColumns hiddenColumns, int width, int height)
   {
     setSize(width, height);
 
@@ -1192,8 +1193,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               exportData.getAlignment(), // class cast exceptions will
               // occur in the distant future
               exportData.getOmitHidden(), exportData.getStartEndPostions(),
-              f.getCacheSuffixDefault(format),
-              viewport.getColumnSelection());
+              f.getCacheSuffixDefault(format), viewport.getAlignment()
+                      .getHiddenColumns());
 
       if (output == null)
       {
@@ -1271,8 +1272,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       cap.setText(new FormatAdapter(alignPanel, exportData.getSettings())
               .formatSequences(format, exportData.getAlignment(),
                       exportData.getOmitHidden(),
-                      exportData.getStartEndPostions(),
-                      viewport.getColumnSelection()));
+ exportData
+                              .getStartEndPostions(), viewport
+                              .getAlignment().getHiddenColumns()));
       Desktop.addInternalFrame(cap, MessageManager.formatMessage(
               "label.alignment_output_command",
               new Object[] { e.getActionCommand() }), 600, 500);
@@ -1321,8 +1323,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       alignmentToExport = viewport.getAlignment();
     }
     alignmentStartEnd = alignmentToExport
-            .getVisibleStartAndEndIndex(viewport.getColumnSelection()
-                    .getHiddenColumns());
+            .getVisibleStartAndEndIndex(viewport.getAlignment()
+                    .getHiddenColumns()
+                    .getHiddenRegions());
     AlignmentExportData ed = new AlignmentExportData(alignmentToExport,
             omitHidden, alignmentStartEnd, settings);
     return ed;
@@ -1886,7 +1889,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       hiddenColumns = new ArrayList<int[]>();
       int hiddenOffset = viewport.getSelectionGroup().getStartRes(), hiddenCutoff = viewport
               .getSelectionGroup().getEndRes();
-      for (int[] region : viewport.getColumnSelection().getHiddenColumns())
+      for (int[] region : viewport.getAlignment().getHiddenColumns()
+              .getHiddenRegions())
       {
         if (region[0] >= hiddenOffset && region[1] <= hiddenCutoff)
         {
@@ -4655,9 +4659,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                     viewport.getAlignment(), 0, false);
             SequenceI repseq = viewport.getAlignment().getSequenceAt(0);
             viewport.getAlignment().setSeqrep(repseq);
-            ColumnSelection cs = new ColumnSelection();
+            HiddenColumns cs = new HiddenColumns();
             cs.hideInsertionsFor(repseq);
-            viewport.setColumnSelection(cs);
+            viewport.getAlignment().setHiddenColumns(cs);
             isAnnotation = true;
           }
           // else if (IdentifyFile.FeaturesFile.equals(format))
index f22a911..6409b56 100644 (file)
@@ -35,6 +35,7 @@ import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
@@ -51,12 +52,12 @@ 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;
 import java.awt.Dimension;
 import java.awt.Font;
+import java.awt.FontMetrics;
 import java.awt.Rectangle;
 import java.util.ArrayList;
 import java.util.Hashtable;
@@ -105,7 +106,7 @@ public class AlignViewport extends AlignmentViewport implements
    */
   public AlignViewport(AlignmentI al)
   {
-    setAlignment(al);
+    super(al);
     init();
   }
 
@@ -123,6 +124,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 +137,8 @@ public class AlignViewport extends AlignmentViewport implements
     {
       Cache.log.debug("Setting viewport's view id : " + viewId);
     }
-    setAlignment(al);
     init();
+
   }
 
   /**
@@ -147,12 +149,12 @@ public class AlignViewport extends AlignmentViewport implements
    * @param hiddenColumns
    *          ColumnSelection
    */
-  public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns)
+  public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns)
   {
-    setAlignment(al);
+    super(al);
     if (hiddenColumns != null)
     {
-      colSel = hiddenColumns;
+      al.setHiddenColumns(hiddenColumns);
     }
     init();
   }
@@ -165,7 +167,7 @@ public class AlignViewport extends AlignmentViewport implements
    * @param seqsetid
    *          (may be null)
    */
-  public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns,
+  public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns,
           String seqsetid)
   {
     this(al, hiddenColumns, seqsetid, null);
@@ -181,9 +183,10 @@ public class AlignViewport extends AlignmentViewport implements
    * @param viewid
    *          (may be null)
    */
-  public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns,
+  public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns,
           String seqsetid, String viewid)
   {
+    super(al);
     sequenceSetID = seqsetid;
     viewId = viewid;
     // TODO remove these once 2.4.VAMSAS release finished
@@ -196,10 +199,10 @@ public class AlignViewport extends AlignmentViewport implements
     {
       Cache.log.debug("Setting viewport's view id : " + viewId);
     }
-    setAlignment(al);
+
     if (hiddenColumns != null)
     {
-      colSel = hiddenColumns;
+      al.setHiddenColumns(hiddenColumns);
     }
     init();
   }
@@ -238,7 +241,6 @@ public class AlignViewport extends AlignmentViewport implements
 
   void init()
   {
-    ranges = new ViewportRanges(this.alignment);
     applyViewProperties();
 
     String fontName = Cache.getDefault("FONT_NAME", "SansSerif");
@@ -350,23 +352,19 @@ public class AlignViewport extends AlignmentViewport implements
   boolean validCharWidth;
 
   /**
-   * update view settings with the given font. You may need to call
-   * alignPanel.fontChanged to update the layout geometry
-   * 
-   * @param setGrid
-   *          when true, charWidth/height is set according to font mentrics
+   * {@inheritDoc}
    */
+  @Override
   public void setFont(Font f, boolean setGrid)
   {
     font = f;
 
     Container c = new Container();
 
-    java.awt.FontMetrics fm = c.getFontMetrics(font);
-    int w = viewStyle.getCharWidth(), ww = fm.charWidth('M'), h = viewStyle
-            .getCharHeight();
     if (setGrid)
     {
+      FontMetrics fm = c.getFontMetrics(font);
+      int ww = fm.charWidth('M');
       setCharHeight(fm.getHeight());
       setCharWidth(ww);
     }
@@ -529,7 +527,7 @@ public class AlignViewport extends AlignmentViewport implements
     {
       end = alignment.getWidth();
     }
-    viscontigs = colSel.getVisibleContigs(start, end);
+    viscontigs = alignment.getHiddenColumns().getVisibleContigs(start, end);
     return viscontigs;
   }
 
@@ -599,7 +597,9 @@ public class AlignViewport extends AlignmentViewport implements
     jalview.structure.StructureSelectionManager
             .getStructureSelectionManager(Desktop.instance).sendSelection(
                     new SequenceGroup(getSelectionGroup()),
-                    new ColumnSelection(getColumnSelection()), this);
+                    new ColumnSelection(getColumnSelection()),
+                    new HiddenColumns(getAlignment().getHiddenColumns()),
+                    this);
   }
 
   /**
index 04de50b..885d79d 100644 (file)
@@ -25,6 +25,7 @@ import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.bin.Cache;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceGroup;
@@ -402,11 +403,12 @@ public class AlignmentPanel extends GAlignmentPanel implements
       }
       if (av.hasHiddenColumns())
       {
-        start = av.getColumnSelection().findColumnPosition(start);
-        end = av.getColumnSelection().findColumnPosition(end);
+        HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+        start = hidden.findColumnPosition(start);
+        end = hidden.findColumnPosition(end);
         if (start == end)
         {
-          if (!av.getColumnSelection().isVisible(r[0]))
+          if (!hidden.isVisible(r[0]))
           {
             // don't scroll - position isn't visible
             return false;
@@ -711,7 +713,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
     if (av.hasHiddenColumns())
     {
       // reset the width to exclude hidden columns
-      width = av.getColumnSelection().findColumnPosition(width);
+      width = av.getAlignment().getHiddenColumns()
+              .findColumnPosition(width);
     }
 
     hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
@@ -924,7 +927,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
       if (av.hasHiddenColumns())
       {
-        maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+        maxwidth = av.getAlignment().getHiddenColumns()
+                .findColumnPosition(maxwidth) - 1;
       }
 
       int canvasWidth = getSeqPanel().seqCanvas
@@ -1212,7 +1216,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
     int maxwidth = av.getAlignment().getWidth();
     if (av.hasHiddenColumns())
     {
-      maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+      maxwidth = av.getAlignment().getHiddenColumns()
+              .findColumnPosition(maxwidth) - 1;
     }
 
     int resWidth = getSeqPanel().seqCanvas.getWrappedCanvasWidth(pwidth
@@ -1406,7 +1411,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
     int maxwidth = av.getAlignment().getWidth();
     if (av.hasHiddenColumns())
     {
-      maxwidth = av.getColumnSelection().findColumnPosition(maxwidth);
+      maxwidth = av.getAlignment().getHiddenColumns()
+              .findColumnPosition(maxwidth);
     }
 
     int height = ((av.getAlignment().getHeight() + 1) * av.getCharHeight())
@@ -1636,7 +1642,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
     int maxwidth = av.getAlignment().getWidth();
     if (av.hasHiddenColumns())
     {
-      maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+      maxwidth = av.getAlignment().getHiddenColumns()
+              .findColumnPosition(maxwidth) - 1;
     }
 
     int height = ((maxwidth / chunkWidth) + 1) * cHeight;
index 999d217..96299e7 100644 (file)
@@ -21,7 +21,7 @@
 
 package jalview.gui;
 
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.schemes.AnnotationColourGradient;
 import jalview.util.MessageManager;
 import jalview.viewmodel.annotationfilter.AnnotationFilterParameter;
@@ -86,7 +86,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
 
   private int actionOption = ACTION_OPTION_SELECT;
 
-  private ColumnSelection oldColumnSelection;
+  private HiddenColumns oldHiddenColumns;
 
   protected int MIN_WIDTH = 420;
 
@@ -110,7 +110,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     {
       return;
     }
-    setOldColumnSelection(av.getColumnSelection());
+    setOldHiddenColumns(av.getAlignment().getHiddenColumns());
     adjusting = true;
 
     setAnnotations(new JComboBox<String>(getAnnotationItems(false)));
@@ -236,26 +236,26 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
   @Override
   protected void reset()
   {
-    if (this.getOldColumnSelection() != null)
+    if (this.getOldHiddenColumns() != null)
     {
       av.getColumnSelection().clear();
 
       if (av.getAnnotationColumnSelectionState() != null)
       {
-        ColumnSelection oldSelection = av
+        HiddenColumns oldHidden = av
                 .getAnnotationColumnSelectionState()
-                .getOldColumnSelection();
-        if (oldSelection != null && oldSelection.getHiddenColumns() != null
-                && !oldSelection.getHiddenColumns().isEmpty())
+                .getOldHiddenColumns();
+        if (oldHidden != null && oldHidden.getHiddenRegions() != null
+                && !oldHidden.getHiddenRegions().isEmpty())
         {
-          for (Iterator<int[]> itr = oldSelection.getHiddenColumns()
+          for (Iterator<int[]> itr = oldHidden.getHiddenRegions()
                   .iterator(); itr.hasNext();)
           {
             int positions[] = itr.next();
             av.hideColumns(positions[0], positions[1]);
           }
         }
-        av.setColumnSelection(oldSelection);
+        av.getAlignment().setHiddenColumns(oldHidden);
       }
       ap.paintAlignment(true);
     }
@@ -408,17 +408,16 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     ap.paintAlignment(true);
   }
 
-
-  public ColumnSelection getOldColumnSelection()
+  public HiddenColumns getOldHiddenColumns()
   {
-    return oldColumnSelection;
+    return oldHiddenColumns;
   }
 
-  public void setOldColumnSelection(ColumnSelection currentColumnSelection)
+  public void setOldHiddenColumns(HiddenColumns currentHiddenColumns)
   {
-    if (currentColumnSelection != null)
+    if (currentHiddenColumns != null)
     {
-      this.oldColumnSelection = new ColumnSelection(currentColumnSelection);
+      this.oldHiddenColumns = new HiddenColumns(currentHiddenColumns);
     }
   }
 
index c9535d0..8ca1a4e 100755 (executable)
@@ -947,12 +947,14 @@ public class AnnotationLabels extends JPanel implements MouseListener,
     Alignment ds = new Alignment(dseqs);
     if (av.hasHiddenColumns())
     {
-      omitHidden = av.getColumnSelection().getVisibleSequenceStrings(0,
+      omitHidden = av.getAlignment().getHiddenColumns()
+              .getVisibleSequenceStrings(0,
               sq.getLength(), seqs);
     }
 
     int[] alignmentStartEnd = new int[] { 0, ds.getWidth() - 1 };
-    List<int[]> hiddenCols = av.getColumnSelection().getHiddenColumns();
+    List<int[]> hiddenCols = av.getAlignment().getHiddenColumns()
+            .getHiddenRegions();
     if (hiddenCols != null)
     {
       alignmentStartEnd = av.getAlignment().getVisibleStartAndEndIndex(
@@ -968,7 +970,8 @@ public class AnnotationLabels extends JPanel implements MouseListener,
     if (av.hasHiddenColumns())
     {
       hiddenColumns = new ArrayList<int[]>();
-      for (int[] region : av.getColumnSelection().getHiddenColumns())
+      for (int[] region : av.getAlignment().getHiddenColumns()
+              .getHiddenRegions())
       {
         hiddenColumns.add(new int[] { region[0], region[1] });
       }
index 84f3e6c..919356f 100755 (executable)
@@ -23,6 +23,7 @@ package jalview.gui;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.AnnotationRenderer;
 import jalview.renderer.AwtRenderPanelI;
@@ -290,7 +291,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     {
       for (int index : av.getColumnSelection().getSelected())
       {
-        if (av.getColumnSelection().isVisible(index))
+        if (av.getAlignment().getHiddenColumns().isVisible(index))
         {
           anot[index] = null;
         }
@@ -314,7 +315,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
       for (int index : av.getColumnSelection().getSelected())
       {
-        if (!av.getColumnSelection().isVisible(index))
+        if (!av.getAlignment().getHiddenColumns().isVisible(index))
         {
           continue;
         }
@@ -337,7 +338,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
       for (int index : av.getColumnSelection().getSelected())
       {
-        if (!av.getColumnSelection().isVisible(index))
+        if (!av.getAlignment().getHiddenColumns().isVisible(index))
         {
           continue;
         }
@@ -397,7 +398,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       }
       for (int index : av.getColumnSelection().getSelected())
       {
-        if (!av.getColumnSelection().isVisible(index))
+        if (!av.getAlignment().getHiddenColumns().isVisible(index))
         {
           continue;
         }
@@ -440,6 +441,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     StringBuilder collatedInput = new StringBuilder(64);
     String last = "";
     ColumnSelection viscols = av.getColumnSelection();
+    HiddenColumns hidden = av.getAlignment().getHiddenColumns();
 
     /*
      * the selection list (read-only view) is in selection order, not
@@ -450,7 +452,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     for (int index : selected)
     {
       // always check for current display state - just in case
-      if (!viscols.isVisible(index))
+      if (!hidden.isVisible(index))
       {
         continue;
       }
@@ -712,7 +714,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
     if (av.hasHiddenColumns())
     {
-      column = av.getColumnSelection().adjustForHiddenColumns(column);
+      column = av.getAlignment().getHiddenColumns()
+              .adjustForHiddenColumns(column);
     }
 
     AlignmentAnnotation ann = aa[row];
index f4a4f4d..a50de77 100644 (file)
@@ -23,6 +23,7 @@ package jalview.gui;
 import jalview.analysis.AlignSeq;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.RnaViewerModel;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -400,7 +401,7 @@ public class AppVarna extends JInternalFrame implements SelectionListener,
 
   @Override
   public void selection(SequenceGroup seqsel, ColumnSelection colsel,
-          SelectionSource source)
+          HiddenColumns hidden, SelectionSource source)
   {
     if (source != ap.av)
     {
index 7a0b0af..a5aa9eb 100644 (file)
@@ -28,7 +28,7 @@ import jalview.api.FeaturesDisplayedI;
 import jalview.api.FeaturesSourceI;
 import jalview.bin.Jalview;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceI;
 import jalview.io.AlignmentFileReaderI;
 import jalview.io.AppletFormatAdapter;
@@ -284,8 +284,8 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer
         AlignFrame af;
         if (source instanceof ComplexAlignFile)
         {
-          ColumnSelection colSel = ((ComplexAlignFile) source)
-                  .getColumnSelection();
+          HiddenColumns hidden = ((ComplexAlignFile) source)
+                  .getHiddenColumns();
           SequenceI[] hiddenSeqs = ((ComplexAlignFile) source)
                   .getHiddenSequences();
           boolean showSeqFeatures = ((ComplexAlignFile) source)
@@ -294,7 +294,7 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer
                   .getGlobalColourScheme();
           FeaturesDisplayedI fd = ((ComplexAlignFile) source)
                   .getDisplayedFeatures();
-          af = new AlignFrame(al, hiddenSeqs, colSel,
+          af = new AlignFrame(al, hiddenSeqs, hidden,
                   AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
           af.getViewport().setShowSequenceFeatures(showSeqFeatures);
           af.getViewport().setFeaturesDisplayed(fd);
index 8220aea..06f29e9 100755 (executable)
@@ -26,12 +26,10 @@ import jalview.util.MessageManager;
 
 import java.awt.Font;
 import java.awt.FontMetrics;
-import java.awt.event.ActionEvent;
 import java.awt.geom.Rectangle2D;
 
 import javax.swing.JInternalFrame;
 import javax.swing.JLayeredPane;
-import javax.swing.JOptionPane;
 
 /**
  * DOCUMENT ME!
@@ -50,8 +48,22 @@ public class FontChooser extends GFontChooser
    */
   Font oldFont;
 
+  /*
+   * The font on opening the dialog (to be restored on Cancel)
+   * on the other half of a split frame (if applicable)
+   */
+  Font oldComplementFont;
+
+  /*
+   * the state of 'scale protein as cDNA' on opening the dialog
+   */
   boolean oldProteinScale;
 
+  /*
+   * the state of 'same font for protein and cDNA' on opening the dialog
+   */
+  boolean oldMirrorFont;
+
   boolean init = true;
 
   JInternalFrame frame;
@@ -63,34 +75,37 @@ public class FontChooser extends GFontChooser
 
   private boolean lastSelMono = false;
 
+  private boolean oldSmoothFont;
+
+  private boolean oldComplementSmooth;
+
   /**
-   * Creates a new FontChooser object.
+   * Creates a new FontChooser for a tree panel
    * 
-   * @param ap
-   *          DOCUMENT ME!
+   * @param treePanel
    */
-  public FontChooser(TreePanel tp)
+  public FontChooser(TreePanel treePanel)
   {
-    this.tp = tp;
-    ap = tp.treeCanvas.ap;
-    oldFont = tp.getTreeFont();
+    this.tp = treePanel;
+    ap = treePanel.treeCanvas.ap;
+    oldFont = treePanel.getTreeFont();
     defaultButton.setVisible(false);
     smoothFont.setEnabled(false);
     init();
   }
 
   /**
-   * Creates a new FontChooser object.
+   * Creates a new FontChooser for an alignment panel
    * 
-   * @param ap
-   *          DOCUMENT ME!
+   * @param alignPanel
    */
-  public FontChooser(AlignmentPanel ap)
+  public FontChooser(AlignmentPanel alignPanel)
   {
-    oldFont = ap.av.getFont();
-    oldProteinScale = ap.av.isScaleProteinAsCdna();
-
-    this.ap = ap;
+    oldFont = alignPanel.av.getFont();
+    oldProteinScale = alignPanel.av.isScaleProteinAsCdna();
+    oldMirrorFont = alignPanel.av.isProteinFontAsCdna();
+    oldSmoothFont = alignPanel.av.antiAlias;
+    this.ap = alignPanel;
     init();
   }
 
@@ -103,14 +118,19 @@ public class FontChooser extends GFontChooser
 
     /*
      * Enable 'scale protein as cDNA' in a SplitFrame view. The selection is
-     * stored in the ViewStyle of both dna and protein Viewport
+     * stored in the ViewStyle of both dna and protein Viewport. Also enable
+     * checkbox for copy font changes to other half of split frame.
      */
-    scaleAsCdna.setEnabled(false);
-    if (ap.av.getCodingComplement() != null)
+    boolean inSplitFrame = ap.av.getCodingComplement() != null;
+    if (inSplitFrame)
     {
-      scaleAsCdna.setEnabled(true);
+      oldComplementFont = ((AlignViewport) ap.av.getCodingComplement())
+              .getFont();
+      oldComplementSmooth = ((AlignViewport) ap.av.getCodingComplement()).antiAlias;
       scaleAsCdna.setVisible(true);
       scaleAsCdna.setSelected(ap.av.isScaleProteinAsCdna());
+      fontAsCdna.setVisible(true);
+      fontAsCdna.setSelected(ap.av.isProteinFontAsCdna());
     }
 
     if (tp != null)
@@ -122,7 +142,7 @@ public class FontChooser extends GFontChooser
     else
     {
       Desktop.addInternalFrame(frame,
-              MessageManager.getString("action.change_font"), 380, 200,
+              MessageManager.getString("action.change_font"), 380, 220,
               false);
     }
 
@@ -158,11 +178,19 @@ public class FontChooser extends GFontChooser
   }
 
   @Override
-  public void smoothFont_actionPerformed(ActionEvent e)
+  protected void smoothFont_actionPerformed()
   {
     ap.av.antiAlias = smoothFont.isSelected();
     ap.getAnnotationPanel().image = null;
     ap.paintAlignment(true);
+    if (ap.av.getCodingComplement() != null && ap.av.isProteinFontAsCdna())
+    {
+      ((AlignViewport) ap.av.getCodingComplement()).antiAlias = ap.av.antiAlias;
+      SplitFrame sv = (SplitFrame) ap.alignFrame.getSplitViewContainer();
+      sv.adjustLayout();
+      sv.repaint();
+    }
+
   }
 
   /**
@@ -172,7 +200,7 @@ public class FontChooser extends GFontChooser
    *          DOCUMENT ME!
    */
   @Override
-  protected void ok_actionPerformed(ActionEvent e)
+  protected void ok_actionPerformed()
   {
     try
     {
@@ -197,26 +225,32 @@ public class FontChooser extends GFontChooser
    *          DOCUMENT ME!
    */
   @Override
-  protected void cancel_actionPerformed(ActionEvent e)
+  protected void cancel_actionPerformed()
   {
     if (ap != null)
     {
       ap.av.setFont(oldFont, true);
       ap.av.setScaleProteinAsCdna(oldProteinScale);
+      ap.av.setProteinFontAsCdna(oldMirrorFont);
+      ap.av.antiAlias = oldSmoothFont;
       ap.paintAlignment(true);
-      if (scaleAsCdna.isEnabled())
+
+      if (scaleAsCdna.isVisible() && scaleAsCdna.isEnabled())
       {
-        ap.av.setScaleProteinAsCdna(oldProteinScale);
         ap.av.getCodingComplement().setScaleProteinAsCdna(oldProteinScale);
+        ap.av.getCodingComplement().setProteinFontAsCdna(oldMirrorFont);
+        ((AlignViewport) ap.av.getCodingComplement()).antiAlias = oldComplementSmooth;
+        ap.av.getCodingComplement().setFont(oldComplementFont, true);
+        SplitFrame splitFrame = (SplitFrame) ap.alignFrame
+                .getSplitViewContainer();
+        splitFrame.adjustLayout();
+        splitFrame.repaint();
       }
     }
     else if (tp != null)
     {
       tp.setTreeFont(oldFont);
     }
-    fontName.setSelectedItem(oldFont.getName());
-    fontSize.setSelectedItem(oldFont.getSize());
-    fontStyle.setSelectedIndex(oldFont.getStyle());
 
     try
     {
@@ -287,6 +321,29 @@ public class FontChooser extends GFontChooser
     {
       ap.av.setFont(newFont, true);
       ap.fontChanged();
+
+      /*
+       * adjust other half of split frame if any, if either same
+       * font, or proportionate scaling, is selected
+       */
+      if (fontAsCdna.isEnabled())
+      {
+        if (fontAsCdna.isSelected())
+        {
+          /*
+           * copy the font
+           */
+          ap.av.getCodingComplement().setFont(newFont, true);
+        }
+
+        /*
+         * adjust layout for font change / reset / sizing
+         */
+        SplitFrame splitFrame = (SplitFrame) ap.alignFrame
+                .getSplitViewContainer();
+        splitFrame.adjustLayout();
+        splitFrame.repaint();
+      }
     }
 
     monospaced.setSelected(mw == iw);
@@ -299,13 +356,10 @@ public class FontChooser extends GFontChooser
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Updates on change of selected font name
    */
   @Override
-  protected void fontName_actionPerformed(ActionEvent e)
+  protected void fontName_actionPerformed()
   {
     if (init)
     {
@@ -316,13 +370,10 @@ public class FontChooser extends GFontChooser
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Updates on change of selected font size
    */
   @Override
-  protected void fontSize_actionPerformed(ActionEvent e)
+  protected void fontSize_actionPerformed()
   {
     if (init)
     {
@@ -333,13 +384,10 @@ public class FontChooser extends GFontChooser
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Updates on change of selected font style
    */
   @Override
-  protected void fontStyle_actionPerformed(ActionEvent e)
+  protected void fontStyle_actionPerformed()
   {
     if (init)
     {
@@ -352,11 +400,9 @@ public class FontChooser extends GFontChooser
   /**
    * Make selected settings the defaults by storing them (via Cache class) in
    * the .jalview_properties file (the file is only written when Jalview exits)
-   * 
-   * @param e
    */
   @Override
-  public void defaultButton_actionPerformed(ActionEvent e)
+  public void defaultButton_actionPerformed()
   {
     Cache.setProperty("FONT_NAME", fontName.getSelectedItem().toString());
     Cache.setProperty("FONT_STYLE", fontStyle.getSelectedIndex() + "");
@@ -372,7 +418,7 @@ public class FontChooser extends GFontChooser
    * characters
    */
   @Override
-  protected void scaleAsCdna_actionPerformed(ActionEvent e)
+  protected void scaleAsCdna_actionPerformed()
   {
     ap.av.setScaleProteinAsCdna(scaleAsCdna.isSelected());
     ap.av.getCodingComplement().setScaleProteinAsCdna(
@@ -381,7 +427,28 @@ public class FontChooser extends GFontChooser
             .getSplitViewContainer();
     splitFrame.adjustLayout();
     splitFrame.repaint();
-    // ap.paintAlignment(true);
-    // TODO would like to repaint
+  }
+
+  /**
+   * Turn on/off mirroring of font across split frame. If turning on, also
+   * copies the current font across the split frame. If turning off, restores
+   * the other half of the split frame to its initial font.
+   */
+  @Override
+  protected void mirrorFonts_actionPerformed()
+  {
+    boolean selected = fontAsCdna.isSelected();
+    ap.av.setProteinFontAsCdna(selected);
+    ap.av.getCodingComplement().setProteinFontAsCdna(selected);
+
+    /*
+     * reset other half of split frame if turning option off
+     */
+    if (!selected)
+    {
+      ap.av.getCodingComplement().setFont(oldComplementFont, true);
+    }
+
+    changeFont();
   }
 }
index aad0776..1b79f54 100755 (executable)
@@ -290,7 +290,8 @@ public class IdCanvas extends JPanel
 
       if (av.hasHiddenColumns())
       {
-        maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+        maxwidth = av.getAlignment().getHiddenColumns()
+                .findColumnPosition(maxwidth) - 1;
       }
 
       int annotationHeight = 0;
index 02136f9..6361caf 100644 (file)
@@ -1413,17 +1413,18 @@ public class Jalview2XML
 
       if (av.hasHiddenColumns())
       {
-        if (av.getColumnSelection() == null
-                || av.getColumnSelection().getHiddenColumns() == null)
+        jalview.datamodel.HiddenColumns hidden = av.getAlignment()
+                .getHiddenColumns();
+        if (hidden == null || hidden.getHiddenRegions() == null)
         {
           warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
         }
         else
         {
-          for (int c = 0; c < av.getColumnSelection().getHiddenColumns()
+          for (int c = 0; c < hidden.getHiddenRegions()
                   .size(); c++)
           {
-            int[] region = av.getColumnSelection().getHiddenColumns()
+            int[] region = hidden.getHiddenRegions()
                     .get(c);
             HiddenColumns hc = new HiddenColumns();
             hc.setStart(region[0]);
diff --git a/src/jalview/gui/OverviewCanvas.java b/src/jalview/gui/OverviewCanvas.java
new file mode 100644 (file)
index 0000000..6f9fbbf
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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.OverviewRenderer;
+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;
+
+  private OverviewDimensions od;
+
+  private 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);
+  }
+
+  /**
+   * Update the overview dimensions object used by the canvas (e.g. if we change
+   * from showing hidden columns to hiding them or vice versa)
+   * 
+   * @param overviewDims
+   */
+  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;
+    }
+  }
+
+  /**
+   * Draw the overview sequences
+   * 
+   * @param showSequenceFeatures
+   *          true if sequence features are to be shown
+   * @param showAnnotation
+   *          true if the annotation is to be shown
+   * @param transferRenderer
+   *          the renderer to transfer feature colouring from
+   */
+  public void draw(boolean showSequenceFeatures, boolean showAnnotation,
+          FeatureRenderer transferRenderer)
+  {
+    miniMe = null;
+
+    if (showSequenceFeatures)
+    {
+      fr.transferSettings(transferRenderer);
+    }
+
+    setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
+
+    OverviewRenderer or = new OverviewRenderer(sr, fr, od);
+    miniMe = or.draw(od.getRows(av.getAlignment()),
+            od.getColumns(av.getAlignment()));
+
+    Graphics mg = miniMe.getGraphics();
+
+    if (showAnnotation)
+    {
+      mg.translate(0, od.getSequencesHeight());
+      or.drawGraph(mg, av.getAlignmentConservationAnnotation(),
+              av.getCharWidth(), od.getGraphHeight(),
+              od.getColumns(av.getAlignment()));
+      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..a6c3960 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.OverviewDimensionsHideHidden;
+import jalview.viewmodel.OverviewDimensionsShowHidden;
 
-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.JCheckBoxMenuItem;
 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,17 @@ 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;
+  private JCheckBoxMenuItem displayToggle;
 
-  // 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 +72,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 OverviewDimensionsShowHidden(av.getRanges(),
             (av.isShowAnnotation() && av
                     .getAlignmentConservationAnnotation() != null));
 
+    oviewCanvas = new OverviewCanvas(od, av);
+    setLayout(new BorderLayout());
+    add(oviewCanvas, BorderLayout.CENTER);
+
     addComponentListener(new ComponentAdapter()
     {
       @Override
@@ -112,11 +99,12 @@ 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
-                  .getColumnSelection(), av.getRanges());
+                  .getAlignment().getHiddenSequences(), av.getAlignment()
+                  .getHiddenColumns());
           ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
         }
       }
@@ -127,191 +115,116 @@ 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
-                  .getColumnSelection(), av.getRanges());
+                  .getAlignment().getHiddenSequences(), av.getAlignment()
+                  .getHiddenColumns());
           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()
-  {
-    if (resizing)
-    {
-      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()
+  private void showPopupMenu(MouseEvent e)
   {
-    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))
+    JPopupMenu popup = new JPopupMenu();
+    ActionListener menuListener = new ActionListener()
     {
-      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();
+        displayToggle.setSelected(showHidden);
       }
-    }
-    System.gc();
-
-    resizing = false;
-
-    if (resizeAgain)
-    {
-      resizeAgain = false;
-      updateOverviewImage();
-    }
-    else
-    {
-      lastMiniMe = miniMe;
-    }
-
-    setBoxPosition();
+    };
+    displayToggle = new JCheckBoxMenuItem(
+            MessageManager.getString("label.togglehidden"));
+    displayToggle.setEnabled(true);
+    displayToggle.setSelected(showHidden);
+    popup.add(displayToggle);
+    displayToggle.addActionListener(menuListener);
+    popup.show(this, e.getX(), e.getY());
   }
 
   /*
-   * Build the overview panel image
+   * Toggle overview display between showing hidden columns and hiding hidden columns
    */
-  private void buildImage(float sampleRow, float sampleCol)
+  private void toggleHiddenColumns()
   {
-    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 (showHidden)
     {
-      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);
-      }
+      showHidden = false;
+      od = new OverviewDimensionsHideHidden(av.getRanges(),
+              (av.isShowAnnotation() && av
+                      .getAlignmentConservationAnnotation() != null));
+    }
+    else
+    {
+      showHidden = true;
+      od = new OverviewDimensionsShowHidden(av.getRanges(),
+              (av.isShowAnnotation() && av
+                      .getAlignmentConservationAnnotation() != null));
     }
+    oviewCanvas.resetOviewDims(od);
+    updateOverviewImage();
   }
 
-  /*
-   * Find the colour of a sequence at a specified column position
+  /**
+   * Updates the overview image when the related alignment panel is updated
    */
-  private int getColumnColourFromSequence(
-          jalview.datamodel.SequenceI seq,
-          boolean hiddenRow, boolean hasHiddenCols, int lastcol,
-          FeatureColourFinder finder)
+  public void updateOverviewImage()
   {
-    Color color = Color.white;
-
-    if ((seq != null) && (seq.getLength() > lastcol))
+    if ((getWidth() > 0) && (getHeight() > 0))
     {
-       color = sr.getResidueColour(seq, lastcol, finder);
+      od.setWidth(getWidth());
+      od.setHeight(getHeight());
     }
+    
+    setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
 
-    if (hiddenRow
-            || (hasHiddenCols && !av.getColumnSelection()
-                    .isVisible(lastcol)))
+    if (oviewCanvas.restartDraw())
     {
-      color = color.darker().darker();
+      return;
     }
 
-    return color.getRGB();
+    Thread thread = new Thread(this);
+    thread.start();
+    repaint();
+
+  }
+
+  @Override
+  public void run()
+  {
+    oviewCanvas.draw(av.isShowSequenceFeatures(),
+            (av.isShowAnnotation() && av
+                    .getAlignmentConservationAnnotation() != null), ap
+                    .getSeqPanel().seqCanvas.getFeatureRenderer());
+    setBoxPosition();
   }
 
   /**
@@ -321,40 +234,8 @@ public class OverviewPanel extends JPanel implements Runnable
    */
   public void setBoxPosition()
   {
-    od.setBoxPosition(av.getAlignment()
-            .getHiddenSequences(), av.getColumnSelection(), av.getRanges());
+    od.setBoxPosition(av.getAlignment().getHiddenSequences(), av
+            .getAlignment().getHiddenColumns());
     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);
-  }
 }
index e9ba1e7..d8e6b06 100644 (file)
@@ -27,7 +27,7 @@ import jalview.api.analysis.SimilarityParamsI;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceI;
 import jalview.jbgui.GPCAPanel;
 import jalview.util.MessageManager;
@@ -406,7 +406,7 @@ public class PCAPanel extends GPCAPanel implements Runnable,
     }
     ;
     Object[] alAndColsel = pcaModel.getSeqtrings()
-            .getAlignmentAndColumnSelection(gc);
+            .getAlignmentAndHiddenColumns(gc);
 
     if (alAndColsel != null && alAndColsel[0] != null)
     {
@@ -423,8 +423,8 @@ public class PCAPanel extends GPCAPanel implements Runnable,
       if (true)
       {
         // make a new frame!
-        AlignFrame af = new AlignFrame(al,
-                (ColumnSelection) alAndColsel[1], AlignFrame.DEFAULT_WIDTH,
+        AlignFrame af = new AlignFrame(al, (HiddenColumns) alAndColsel[1],
+                AlignFrame.DEFAULT_WIDTH,
                 AlignFrame.DEFAULT_HEIGHT);
 
         // >>>This is a fix for the moment, until a better solution is
index 1685721..09e3263 100644 (file)
@@ -31,8 +31,8 @@ import jalview.commands.EditCommand.Action;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
-import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
@@ -1446,13 +1446,21 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
   {
     if (sequence != null)
     {
-      ColumnSelection cs = ap.av.getColumnSelection();
-      if (cs == null)
+      /* ColumnSelection cs = ap.av.getColumnSelection();
+       if (cs == null)
+       {
+         cs = new ColumnSelection();
+       }
+       cs.hideInsertionsFor(sequence);
+       ap.av.setColumnSelection(cs);*/
+
+      HiddenColumns hidden = ap.av.getAlignment().getHiddenColumns();
+      if (hidden == null)
       {
-        cs = new ColumnSelection();
+        hidden = new HiddenColumns();
       }
-      cs.hideInsertionsFor(sequence);
-      ap.av.setColumnSelection(cs);
+      hidden.hideInsertionsFor(sequence);
+      ap.av.getAlignment().setHiddenColumns(hidden);
     }
     refresh();
   }
index de21be6..90f7cd2 100755 (executable)
@@ -21,6 +21,7 @@
 package jalview.gui;
 
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.ScaleRenderer;
@@ -106,7 +107,7 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
 
     if (av.hasHiddenColumns())
     {
-      x = av.getColumnSelection().adjustForHiddenColumns(x);
+      x = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(x);
     }
 
     if (x >= av.getAlignment().getWidth())
@@ -172,7 +173,7 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
       });
       pop.add(item);
 
-      if (av.getColumnSelection().hasHiddenColumns())
+      if (av.getAlignment().getHiddenColumns().hasHiddenColumns())
       {
         item = new JMenuItem(MessageManager.getString("action.reveal_all"));
         item.addActionListener(new ActionListener()
@@ -287,7 +288,8 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
 
     if (av.hasHiddenColumns())
     {
-      res = av.getColumnSelection().adjustForHiddenColumns(res);
+      res = av.getAlignment().getHiddenColumns()
+              .adjustForHiddenColumns(res);
     }
 
     if (res >= av.getAlignment().getWidth())
@@ -337,11 +339,12 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
   {
     mouseDragging = true;
     ColumnSelection cs = av.getColumnSelection();
+    HiddenColumns hidden = av.getAlignment().getHiddenColumns();
 
     int res = (evt.getX() / av.getCharWidth())
             + av.getRanges().getStartRes();
     res = Math.max(0, res);
-    res = cs.adjustForHiddenColumns(res);
+    res = hidden.adjustForHiddenColumns(res);
     res = Math.min(res, av.getAlignment().getWidth() - 1);
     min = Math.min(res, min);
     max = Math.max(res, max);
@@ -394,11 +397,12 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
     int res = (evt.getX() / av.getCharWidth())
             + av.getRanges().getStartRes();
 
-    res = av.getColumnSelection().adjustForHiddenColumns(res);
+    res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res);
 
-    if (av.getColumnSelection().getHiddenColumns() != null)
+    if (av.getAlignment().getHiddenColumns().getHiddenRegions() != null)
     {
-      for (int[] region : av.getColumnSelection().getHiddenColumns())
+      for (int[] region : av.getAlignment().getHiddenColumns()
+              .getHiddenRegions())
       {
         if (res + 1 == region[0] || res - 1 == region[1])
         {
@@ -446,7 +450,9 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
 
     // Fill the selected columns
     ColumnSelection cs = av.getColumnSelection();
-    int avCharWidth = av.getCharWidth(), avCharHeight = av.getCharHeight();
+    HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+    int avCharWidth = av.getCharWidth();
+    int avCharHeight = av.getCharHeight();
 
     if (cs != null)
     {
@@ -459,9 +465,9 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
 
         if (av.hasHiddenColumns())
         {
-          if (cs.isVisible(sel))
+          if (hidden.isVisible(sel))
           {
-            sel = cs.findColumnPosition(sel);
+            sel = hidden.findColumnPosition(sel);
           }
           else
           {
@@ -488,13 +494,13 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
       // draw any hidden column markers
       gg.setColor(Color.blue);
       int res;
-      if (av.getShowHiddenMarkers()
-              && av.getColumnSelection().getHiddenColumns() != null)
+
+      if (av.getShowHiddenMarkers() && hidden.getHiddenRegions() != null)
       {
-        for (int i = 0; i < av.getColumnSelection().getHiddenColumns()
+        for (int i = 0; i < hidden.getHiddenRegions()
                 .size(); i++)
         {
-          res = av.getColumnSelection().findHiddenRegionPosition(i)
+          res = hidden.findHiddenRegionPosition(i)
                   - startx;
 
           if (res < 0 || res > widthx)
index 64e5fdc..c2a2ccb 100755 (executable)
@@ -21,6 +21,7 @@
 package jalview.gui;
 
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -165,14 +166,17 @@ public class SeqCanvas extends JComponent
 
     if (av.hasHiddenColumns())
     {
-      startx = av.getColumnSelection().adjustForHiddenColumns(startx);
-      endx = av.getColumnSelection().adjustForHiddenColumns(endx);
+      startx = av.getAlignment().getHiddenColumns()
+              .adjustForHiddenColumns(startx);
+      endx = av.getAlignment().getHiddenColumns()
+              .adjustForHiddenColumns(endx);
     }
 
     int maxwidth = av.getAlignment().getWidth();
     if (av.hasHiddenColumns())
     {
-      maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+      maxwidth = av.getAlignment().getHiddenColumns()
+              .findColumnPosition(maxwidth) - 1;
     }
 
     // WEST SCALE
@@ -224,7 +228,8 @@ public class SeqCanvas extends JComponent
 
     if (av.hasHiddenColumns())
     {
-      endx = av.getColumnSelection().adjustForHiddenColumns(endx);
+      endx = av.getAlignment().getHiddenColumns()
+              .adjustForHiddenColumns(endx);
     }
 
     SequenceI seq;
@@ -515,7 +520,8 @@ public class SeqCanvas extends JComponent
 
     if (av.hasHiddenColumns())
     {
-      maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+      maxwidth = av.getAlignment().getHiddenColumns()
+              .findColumnPosition(maxwidth) - 1;
     }
 
     while ((ypos <= canvasHeight) && (startRes < maxwidth))
@@ -553,11 +559,10 @@ public class SeqCanvas extends JComponent
       {
         g.setColor(Color.blue);
         int res;
-        for (int i = 0; i < av.getColumnSelection().getHiddenColumns()
-                .size(); i++)
+        HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+        for (int i = 0; i < hidden.getHiddenRegions().size(); i++)
         {
-          res = av.getColumnSelection().findHiddenRegionPosition(i)
-                  - startRes;
+          res = hidden.findHiddenRegionPosition(i) - startRes;
 
           if (res < 0 || res > endx - startRes)
           {
@@ -654,7 +659,8 @@ public class SeqCanvas extends JComponent
     }
     else
     {
-      List<int[]> regions = av.getColumnSelection().getHiddenColumns();
+      List<int[]> regions = av.getAlignment().getHiddenColumns()
+              .getHiddenRegions();
 
       int screenY = 0;
       int blockStart = startRes;
index 1432fcb..a2c2bd9 100644 (file)
@@ -27,6 +27,7 @@ import jalview.commands.EditCommand.Action;
 import jalview.commands.EditCommand.Edit;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
@@ -233,7 +234,8 @@ public class SeqPanel extends JPanel implements MouseListener,
 
     if (av.hasHiddenColumns())
     {
-      res = av.getColumnSelection().adjustForHiddenColumns(res);
+      res = av.getAlignment().getHiddenColumns()
+              .adjustForHiddenColumns(res);
     }
 
     return res;
@@ -339,20 +341,23 @@ public class SeqPanel extends JPanel implements MouseListener,
   {
     seqCanvas.cursorX += dx;
     seqCanvas.cursorY += dy;
+
+    HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+
     if (av.hasHiddenColumns()
-            && !av.getColumnSelection().isVisible(seqCanvas.cursorX))
+ && !hidden.isVisible(seqCanvas.cursorX))
     {
       int original = seqCanvas.cursorX - dx;
       int maxWidth = av.getAlignment().getWidth();
 
-      while (!av.getColumnSelection().isVisible(seqCanvas.cursorX)
+      while (!hidden.isVisible(seqCanvas.cursorX)
               && seqCanvas.cursorX < maxWidth && seqCanvas.cursorX > 0)
       {
         seqCanvas.cursorX += dx;
       }
 
       if (seqCanvas.cursorX >= maxWidth
-              || !av.getColumnSelection().isVisible(seqCanvas.cursorX))
+              || !hidden.isVisible(seqCanvas.cursorX))
       {
         seqCanvas.cursorX = original;
       }
@@ -392,22 +397,23 @@ public class SeqPanel extends JPanel implements MouseListener,
       {
         ap.scrollUp(true);
       }
-      while (seqCanvas.cursorY + 1 > av.getRanges().getEndSeq())
+      while (seqCanvas.cursorY > av.getRanges().getEndSeq())
       {
         ap.scrollUp(false);
       }
       if (!av.getWrapAlignment())
       {
-        while (seqCanvas.cursorX < av.getColumnSelection()
-                .adjustForHiddenColumns(av.getRanges().getStartRes()))
+        HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+        while (seqCanvas.cursorX < hidden.adjustForHiddenColumns(av
+                .getRanges().getStartRes()))
         {
           if (!ap.scrollRight(false))
           {
             break;
           }
         }
-        while (seqCanvas.cursorX > av.getColumnSelection()
-                .adjustForHiddenColumns(av.getRanges().getEndRes()))
+        while (seqCanvas.cursorX > hidden.adjustForHiddenColumns(av
+                .getRanges().getEndRes()))
         {
           if (!ap.scrollRight(true))
           {
@@ -945,30 +951,36 @@ public class SeqPanel extends JPanel implements MouseListener,
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
+   * {@inheritDoc}
    */
   @Override
   public void mouseDragged(MouseEvent evt)
   {
     if (mouseWheelPressed)
     {
+      boolean inSplitFrame = ap.av.getCodingComplement() != null;
+      boolean copyChanges = inSplitFrame && av.isProteinFontAsCdna();
+
       int oldWidth = av.getCharWidth();
 
       // Which is bigger, left-right or up-down?
       if (Math.abs(evt.getY() - lastMousePress.getY()) > Math.abs(evt
               .getX() - lastMousePress.getX()))
       {
+        /*
+         * on drag up or down, decrement or increment font size
+         */
         int fontSize = av.font.getSize();
+        boolean fontChanged = false;
 
         if (evt.getY() < lastMousePress.getY())
         {
+          fontChanged = true;
           fontSize--;
         }
         else if (evt.getY() > lastMousePress.getY())
         {
+          fontChanged = true;
           fontSize++;
         }
 
@@ -977,24 +989,56 @@ public class SeqPanel extends JPanel implements MouseListener,
           fontSize = 1;
         }
 
-        av.setFont(
-                new Font(av.font.getName(), av.font.getStyle(), fontSize),
-                true);
-        av.setCharWidth(oldWidth);
-        ap.fontChanged();
+        if (fontChanged)
+        {
+          Font newFont = new Font(av.font.getName(), av.font.getStyle(),
+                  fontSize);
+          av.setFont(newFont, true);
+          av.setCharWidth(oldWidth);
+          ap.fontChanged();
+          if (copyChanges)
+          {
+            ap.av.getCodingComplement().setFont(newFont, true);
+            SplitFrame splitFrame = (SplitFrame) ap.alignFrame
+                    .getSplitViewContainer();
+            splitFrame.adjustLayout();
+            splitFrame.repaint();
+          }
+        }
       }
       else
       {
+        /*
+         * on drag left or right, decrement or increment character width
+         */
+        int newWidth = 0;
         if (evt.getX() < lastMousePress.getX() && av.getCharWidth() > 1)
         {
-          av.setCharWidth(av.getCharWidth() - 1);
+          newWidth = av.getCharWidth() - 1;
+          av.setCharWidth(newWidth);
         }
         else if (evt.getX() > lastMousePress.getX())
         {
-          av.setCharWidth(av.getCharWidth() + 1);
+          newWidth = av.getCharWidth() + 1;
+          av.setCharWidth(newWidth);
+        }
+        if (newWidth > 0)
+        {
+          ap.paintAlignment(false);
+          if (copyChanges)
+          {
+            /*
+             * need to ensure newWidth is set on cdna, regardless of which
+             * panel the mouse drag happened in; protein will compute its 
+             * character width as 1:1 or 3:1
+             */
+            av.getCodingComplement().setCharWidth(newWidth);
+            SplitFrame splitFrame = (SplitFrame) ap.alignFrame
+                    .getSplitViewContainer();
+            splitFrame.adjustLayout();
+            splitFrame.repaint();
+          }
         }
-
-        ap.paintAlignment(false);
       }
 
       FontMetrics fm = getFontMetrics(av.getFont());
@@ -1144,8 +1188,10 @@ public class SeqPanel extends JPanel implements MouseListener,
     if (av.hasHiddenColumns())
     {
       fixedColumns = true;
-      int y1 = av.getColumnSelection().getHiddenBoundaryLeft(startres);
-      int y2 = av.getColumnSelection().getHiddenBoundaryRight(startres);
+      int y1 = av.getAlignment().getHiddenColumns()
+              .getHiddenBoundaryLeft(startres);
+      int y2 = av.getAlignment().getHiddenColumns()
+              .getHiddenBoundaryRight(startres);
 
       if ((insertGap && startres > y1 && lastres < y1)
               || (!insertGap && startres < y2 && lastres > y2))
@@ -1220,8 +1266,8 @@ public class SeqPanel extends JPanel implements MouseListener,
         {
           if (sg.getSize() == av.getAlignment().getHeight())
           {
-            if ((av.hasHiddenColumns() && startres < av
-                    .getColumnSelection().getHiddenBoundaryRight(startres)))
+            if ((av.hasHiddenColumns() && startres < av.getAlignment()
+                    .getHiddenColumns().getHiddenBoundaryRight(startres)))
             {
               endEditing();
               return;
@@ -1957,7 +2003,7 @@ public class SeqPanel extends JPanel implements MouseListener,
    */
   @Override
   public void selection(SequenceGroup seqsel, ColumnSelection colsel,
-          SelectionSource source)
+          HiddenColumns hidden, SelectionSource source)
   {
     // TODO: fix this hack - source of messages is align viewport, but SeqPanel
     // handles selection messages...
@@ -1993,7 +2039,7 @@ public class SeqPanel extends JPanel implements MouseListener,
      * Check for selection in a view of which this one is a dna/protein
      * complement.
      */
-    if (selectionFromTranslation(seqsel, colsel, source))
+    if (selectionFromTranslation(seqsel, colsel, hidden, source))
     {
       return;
     }
@@ -2056,7 +2102,8 @@ public class SeqPanel extends JPanel implements MouseListener,
         }
         else
         {
-          av.getColumnSelection().setElementsFrom(colsel);
+          av.getColumnSelection().setElementsFrom(colsel,
+                  av.getAlignment().getHiddenColumns());
         }
       }
       av.isColSelChanged(true);
@@ -2065,8 +2112,8 @@ public class SeqPanel extends JPanel implements MouseListener,
 
     if (copycolsel
             && av.hasHiddenColumns()
-            && (av.getColumnSelection() == null || av.getColumnSelection()
-                    .getHiddenColumns() == null))
+            && (av.getAlignment().getHiddenColumns() == null || av
+                    .getAlignment().getHiddenColumns().getHiddenRegions() == null))
     {
       System.err.println("Bad things");
     }
@@ -2095,7 +2142,8 @@ public class SeqPanel extends JPanel implements MouseListener,
    * @param source
    */
   protected boolean selectionFromTranslation(SequenceGroup seqsel,
-          ColumnSelection colsel, SelectionSource source)
+          ColumnSelection colsel, HiddenColumns hidden,
+          SelectionSource source)
   {
     if (!(source instanceof AlignViewportI))
     {
@@ -2118,9 +2166,13 @@ public class SeqPanel extends JPanel implements MouseListener,
     /*
      * Map column selection
      */
-    ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
-            av);
+    // ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
+    // av);
+    ColumnSelection cs = new ColumnSelection();
+    HiddenColumns hs = new HiddenColumns();
+    MappingUtils.mapColumnSelection(colsel, hidden, sourceAv, av, cs, hs);
     av.setColumnSelection(cs);
+    av.getAlignment().setHiddenColumns(hs);
 
     // lastly, update any dependent dialogs
     if (ap.getCalculationDialog() != null)
index 91c3f0f..36825ea 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 6c849c3..1d929e6 100644 (file)
@@ -21,7 +21,6 @@
 package jalview.gui;
 
 import jalview.api.SplitContainerI;
-import jalview.api.ViewStyleI;
 import jalview.datamodel.AlignmentI;
 import jalview.jbgui.GAlignFrame;
 import jalview.jbgui.GSplitFrame;
@@ -189,10 +188,8 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
             : (!bottomAlignment.isNucleotide() ? bottomViewport : null);
     if (protein != null && cdna != null)
     {
-      ViewStyleI vs = protein.getViewStyle();
-      int scale = vs.isScaleProteinAsCdna() ? 3 : 1;
-      vs.setCharWidth(scale * cdna.getViewStyle().getCharWidth());
-      protein.setViewStyle(vs);
+      int scale = protein.isScaleProteinAsCdna() ? 3 : 1;
+      protein.setCharWidth(scale * cdna.getViewStyle().getCharWidth());
     }
   }
 
index ee22ae4..3e516a6 100644 (file)
@@ -53,7 +53,6 @@ import java.util.Vector;
 import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
 import javax.swing.JLabel;
-import javax.swing.JOptionPane;
 import javax.swing.table.AbstractTableModel;
 
 /**
@@ -542,26 +541,26 @@ public class StructureChooser extends GStructureChooser implements
     if (haveData)
     {
       cmb_filterOption.addItem(new FilterOption("Best Quality",
-              "overall_quality", VIEWS_FILTER));
+              "overall_quality", VIEWS_FILTER, false));
       cmb_filterOption.addItem(new FilterOption("Best Resolution",
-              "resolution", VIEWS_FILTER));
+              "resolution", VIEWS_FILTER, false));
       cmb_filterOption.addItem(new FilterOption("Most Protein Chain",
-              "number_of_protein_chains", VIEWS_FILTER));
+              "number_of_protein_chains", VIEWS_FILTER, false));
       cmb_filterOption.addItem(new FilterOption("Most Bound Molecules",
-              "number_of_bound_molecules", VIEWS_FILTER));
+              "number_of_bound_molecules", VIEWS_FILTER, false));
       cmb_filterOption.addItem(new FilterOption("Most Polymer Residues",
-              "number_of_polymer_residues", VIEWS_FILTER));
+              "number_of_polymer_residues", VIEWS_FILTER, true));
     }
     cmb_filterOption.addItem(new FilterOption("Enter PDB Id", "-",
-            VIEWS_ENTER_ID));
+            VIEWS_ENTER_ID, false));
     cmb_filterOption.addItem(new FilterOption("From File", "-",
-            VIEWS_FROM_FILE));
-    FilterOption cachedOption = new FilterOption("Cached PDB Entries", "-",
-            VIEWS_LOCAL_PDB);
-    cmb_filterOption.addItem(cachedOption);
+            VIEWS_FROM_FILE, false));
 
-    if (/*!haveData &&*/cachedPDBExists)
+    if (cachedPDBExists)
     {
+      FilterOption cachedOption = new FilterOption("Cached PDB Entries",
+              "-", VIEWS_LOCAL_PDB, false);
+      cmb_filterOption.addItem(cachedOption);
       cmb_filterOption.setSelectedItem(cachedOption);
     }
 
index d7f7c31..e37627d 100644 (file)
@@ -23,7 +23,7 @@ package jalview.gui;
 import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.gui.StructureViewer.ViewerType;
@@ -812,7 +812,7 @@ public abstract class StructureViewerBase extends GStructureViewer
     try
     {
       AlignmentI[] als = new Alignment[_alignwith.size()];
-      ColumnSelection[] alc = new ColumnSelection[_alignwith.size()];
+      HiddenColumns[] alc = new HiddenColumns[_alignwith.size()];
       int[] alm = new int[_alignwith.size()];
       int a = 0;
   
@@ -820,7 +820,7 @@ public abstract class StructureViewerBase extends GStructureViewer
       {
         als[a] = ap.av.getAlignment();
         alm[a] = -1;
-        alc[a++] = ap.av.getColumnSelection();
+        alc[a++] = ap.av.getAlignment().getHiddenColumns();
       }
       reply = getBinding().superposeStructures(als, alm, alc);
       if (reply != null)
index 9dd805e..35998eb 100755 (executable)
@@ -35,8 +35,8 @@ import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.BinaryNode;
-import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.NodeTransformI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
@@ -432,8 +432,7 @@ public class TreePanel extends GTreePanel
     {
     }
 
-    Object[] alAndColsel = originalData
-            .getAlignmentAndColumnSelection(gc);
+    Object[] alAndColsel = originalData.getAlignmentAndHiddenColumns(gc);
 
     if (alAndColsel != null && alAndColsel[0] != null)
     {
@@ -450,8 +449,8 @@ public class TreePanel extends GTreePanel
       if (true)
       {
         // make a new frame!
-        AlignFrame af = new AlignFrame(al,
-                (ColumnSelection) alAndColsel[1], AlignFrame.DEFAULT_WIDTH,
+        AlignFrame af = new AlignFrame(al, (HiddenColumns) alAndColsel[1],
+                AlignFrame.DEFAULT_WIDTH,
                 AlignFrame.DEFAULT_HEIGHT);
 
         // >>>This is a fix for the moment, until a better solution is
index 75ddba5..d58cb5a 100644 (file)
@@ -23,6 +23,7 @@ package jalview.gui;
 import jalview.bin.Cache;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.io.VamsasAppDatastore;
@@ -43,7 +44,6 @@ import java.util.IdentityHashMap;
 import java.util.Iterator;
 
 import javax.swing.JInternalFrame;
-import javax.swing.JOptionPane;
 
 import uk.ac.vamsas.client.ClientHandle;
 import uk.ac.vamsas.client.IClient;
@@ -821,7 +821,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
               {
                 // TODO: rationalise : can only clear a selection over a
                 // referred to object
-                ssm.sendSelection(null, null, me);
+                ssm.sendSelection(null, null, null, me);
                 return;
               }
               Class type = null;
@@ -955,7 +955,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
               }
               if (send)
               {
-                ssm.sendSelection(jselection, colsel, me);
+                ssm.sendSelection(jselection, colsel, null, me);
               }
               // discard message.
               for (int c = 0; c < jvobjs.length; c++)
@@ -1004,7 +1004,8 @@ public class VamsasApplication implements SelectionSource, VamsasSource
 
           @Override
           public void selection(SequenceGroup seqsel,
-                  ColumnSelection colsel, SelectionSource source)
+                  ColumnSelection colsel, HiddenColumns hidden,
+                  SelectionSource source)
           {
             if (vobj2jv == null)
             {
@@ -1079,7 +1080,9 @@ public class VamsasApplication implements SelectionSource, VamsasSource
                   }
                   else
                   {
-                    int[] intervals = colsel.getVisibleContigs(
+                    // int[] intervals = colsel.getVisibleContigs(
+                    // seqsel.getStartRes(), seqsel.getEndRes() + 1);
+                    int[] intervals = hidden.getVisibleContigs(
                             seqsel.getStartRes(), seqsel.getEndRes() + 1);
                     for (int iv = 0; iv < intervals.length; iv += 2)
                     {
index ef903e3..c3e71da 100755 (executable)
@@ -27,6 +27,7 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.GraphLine;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -114,14 +115,12 @@ public class AnnotationFile
 
     public final HiddenSequences hidseqs;
 
-    public final ColumnSelection hiddencols;
-
-    // public final Vector visibleGroups;
+    public final HiddenColumns hiddencols;
 
     public final Hashtable hiddenRepSeqs;
 
     public ViewDef(String vname, HiddenSequences hseqs,
-            ColumnSelection hcols, Hashtable hRepSeqs)
+            HiddenColumns hcols, Hashtable hRepSeqs)
     {
       this.viewname = vname;
       this.hidseqs = hseqs;
@@ -142,7 +141,8 @@ public class AnnotationFile
    */
   public String printAnnotations(AlignmentAnnotation[] annotations,
           List<SequenceGroup> list, Hashtable properties,
-          ColumnSelection cs, AlignmentI al, ViewDef view)
+ HiddenColumns cs,
+          AlignmentI al, ViewDef view)
   {
     if (view != null)
     {
@@ -171,7 +171,7 @@ public class AnnotationFile
     if (cs != null && cs.hasHiddenColumns())
     {
       text.append("VIEW_HIDECOLS\t");
-      List<int[]> hc = cs.getHiddenColumns();
+      List<int[]> hc = cs.getHiddenRegions();
       boolean comma = false;
       for (int[] r : hc)
       {
@@ -666,15 +666,21 @@ public class AnnotationFile
           String file, DataSourceType protocol)
   {
     ColumnSelection colSel = viewport.getColumnSelection();
+    HiddenColumns hidden = viewport.getAlignment().getHiddenColumns();
     if (colSel == null)
     {
       colSel = new ColumnSelection();
     }
-    boolean rslt = readAnnotationFile(viewport.getAlignment(), colSel,
+    if (hidden == null)
+    {
+      hidden = new HiddenColumns();
+    }
+    boolean rslt = readAnnotationFile(viewport.getAlignment(), hidden,
             file, protocol);
-    if (rslt && (colSel.hasSelectedColumns() || colSel.hasHiddenColumns()))
+    if (rslt && (colSel.hasSelectedColumns() || hidden.hasHiddenColumns()))
     {
       viewport.setColumnSelection(colSel);
+      viewport.getAlignment().setHiddenColumns(hidden);
     }
 
     return rslt;
@@ -686,7 +692,7 @@ public class AnnotationFile
     return readAnnotationFile(al, null, file, sourceType);
   }
 
-  public boolean readAnnotationFile(AlignmentI al, ColumnSelection colSel,
+  public boolean readAnnotationFile(AlignmentI al, HiddenColumns hidden,
           String file, DataSourceType sourceType)
   {
     BufferedReader in = null;
@@ -715,7 +721,7 @@ public class AnnotationFile
       }
       if (in != null)
       {
-        return parseAnnotationFrom(al, colSel, in);
+        return parseAnnotationFrom(al, hidden, in);
       }
 
     } catch (Exception ex)
@@ -738,7 +744,7 @@ public class AnnotationFile
 
   private static String GRAPHLINE = "GRAPHLINE", COMBINE = "COMBINE";
 
-  public boolean parseAnnotationFrom(AlignmentI al, ColumnSelection colSel,
+  public boolean parseAnnotationFrom(AlignmentI al, HiddenColumns hidden,
           BufferedReader in) throws Exception
   {
     nlinesread = 0;
@@ -949,11 +955,11 @@ public class AnnotationFile
         {
           if (st.hasMoreTokens())
           {
-            if (colSel == null)
+            if (hidden == null)
             {
-              colSel = new ColumnSelection();
+              hidden = new HiddenColumns();
             }
-            parseHideCols(colSel, st.nextToken());
+            parseHideCols(hidden, st.nextToken());
           }
           modified = true;
           continue;
@@ -967,7 +973,7 @@ public class AnnotationFile
           }
           if (sr != null)
           {
-            if (colSel == null)
+            if (hidden == null)
             {
               System.err
                       .println("Cannot process HIDE_INSERTIONS without an alignment view: Ignoring line: "
@@ -976,7 +982,7 @@ public class AnnotationFile
             else
             {
               // consider deferring this till after the file has been parsed ?
-              colSel.hideInsertionsFor(sr);
+              hidden.hideInsertionsFor(sr);
             }
           }
           modified = true;
@@ -1182,7 +1188,7 @@ public class AnnotationFile
     return modified;
   }
 
-  private void parseHideCols(ColumnSelection colSel, String nextToken)
+  private void parseHideCols(HiddenColumns hidden, String nextToken)
   {
     StringTokenizer inval = new StringTokenizer(nextToken, ",");
     while (inval.hasMoreTokens())
@@ -1194,7 +1200,7 @@ public class AnnotationFile
         from = to = Integer.parseInt(range);
         if (from >= 0)
         {
-          colSel.hideColumns(from, to);
+          hidden.hideColumns(from, to);
         }
       }
       else
@@ -1210,7 +1216,7 @@ public class AnnotationFile
         }
         if (from > 0 && to >= from)
         {
-          colSel.hideColumns(from, to);
+          hidden.hideColumns(from, to);
         }
       }
     }
@@ -1789,7 +1795,7 @@ public class AnnotationFile
     return printAnnotations(viewport.isShowAnnotation() ? viewport
             .getAlignment().getAlignmentAnnotation() : null, viewport
             .getAlignment().getGroups(), viewport.getAlignment()
-            .getProperties(), viewport.getColumnSelection(),
+            .getProperties(), viewport.getAlignment().getHiddenColumns(),
             viewport.getAlignment(), null);
   }
 
index 4f83ab1..7c6d181 100755 (executable)
@@ -27,7 +27,7 @@ import jalview.api.FeaturesSourceI;
 import jalview.bin.Cache;
 import jalview.bin.Jalview;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
@@ -372,8 +372,8 @@ public class FileLoader implements Runnable
 
             if (source instanceof ComplexAlignFile)
             {
-              ColumnSelection colSel = ((ComplexAlignFile) source)
-                      .getColumnSelection();
+              HiddenColumns colSel = ((ComplexAlignFile) source)
+                      .getHiddenColumns();
               SequenceI[] hiddenSeqs = ((ComplexAlignFile) source)
                       .getHiddenSequences();
               String colourSchemeName = ((ComplexAlignFile) source)
index d9dd79d..f09e8a0 100755 (executable)
@@ -26,7 +26,7 @@ import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -165,14 +165,14 @@ public class FormatAdapter extends AppletFormatAdapter
   }
 
   public String formatSequences(FileFormatI format, AlignmentI alignment,
-          String[] omitHidden, int[] exportRange, ColumnSelection colSel)
+          String[] omitHidden, int[] exportRange, HiddenColumns hidden)
   {
     return formatSequences(format, alignment, omitHidden, exportRange,
-            getCacheSuffixDefault(format), colSel, null);
+            getCacheSuffixDefault(format), hidden, null);
   }
 
   /**
-   * hack function to replace seuqences with visible sequence strings before
+   * hack function to replace sequences with visible sequence strings before
    * generating a string of the alignment in the given format.
    * 
    * @param format
@@ -185,15 +185,15 @@ public class FormatAdapter extends AppletFormatAdapter
    */
   public String formatSequences(FileFormatI format, AlignmentI alignment,
           String[] omitHidden, int[] exportRange, boolean suffix,
-          ColumnSelection colSel)
+          HiddenColumns hidden)
   {
     return formatSequences(format, alignment, omitHidden, exportRange,
-            suffix, colSel, null);
+            suffix, hidden, null);
   }
 
   public String formatSequences(FileFormatI format, AlignmentI alignment,
           String[] omitHidden, int[] exportRange, boolean suffix,
-          ColumnSelection colSel, SequenceGroup selgp)
+          HiddenColumns hidden, SequenceGroup selgp)
   {
     if (omitHidden != null)
     {
@@ -211,12 +211,12 @@ public class FormatAdapter extends AppletFormatAdapter
           AlignmentAnnotation na = new AlignmentAnnotation(ala[i]);
           if (selgp != null)
           {
-            colSel.makeVisibleAnnotation(selgp.getStartRes(),
+            hidden.makeVisibleAnnotation(selgp.getStartRes(),
                     selgp.getEndRes(), na);
           }
           else
           {
-            colSel.makeVisibleAnnotation(na);
+            hidden.makeVisibleAnnotation(na);
           }
           alv.addAnnotation(na);
         }
index 68f3e2c..77006db 100755 (executable)
@@ -91,8 +91,8 @@ public abstract class HTMLOutput implements Runnable
     String bioJSON = new FormatAdapter(ap, exportData.getSettings())
             .formatSequences(FileFormat.Json, exportData.getAlignment(),
                     exportData.getOmitHidden(), exportData
-                            .getStartEndPostions(), ap.getAlignViewport()
-                            .getColumnSelection());
+.getStartEndPostions(), ap.getAlignViewport()
+                            .getAlignment().getHiddenColumns());
     return bioJSON;
   }
 
index af3fb5d..9256278 100644 (file)
@@ -24,7 +24,7 @@ package jalview.io;
 import jalview.api.ComplexAlignFile;
 import jalview.api.FeatureSettingsModelI;
 import jalview.api.FeaturesDisplayedI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceI;
 
 import java.io.IOException;
@@ -44,7 +44,7 @@ public class HtmlFile extends AlignFile implements ComplexAlignFile
 
   private boolean showSeqFeatures;
 
-  private ColumnSelection columnSelection;
+  private HiddenColumns hiddenColumns;
 
   private SequenceI[] hiddenSequences;
 
@@ -111,7 +111,7 @@ public class HtmlFile extends AlignFile implements ComplexAlignFile
       this.showSeqFeatures = jsonFile.isShowSeqFeatures();
       this.globalColourScheme = jsonFile.getGlobalColourScheme();
       this.hiddenSequences = jsonFile.getHiddenSequences();
-      this.columnSelection = jsonFile.getColumnSelection();
+      this.hiddenColumns = jsonFile.getHiddenColumns();
       this.displayedFeatures = jsonFile.getDisplayedFeatures();
     } catch (Exception e)
     {
@@ -149,14 +149,14 @@ public class HtmlFile extends AlignFile implements ComplexAlignFile
   }
 
   @Override
-  public ColumnSelection getColumnSelection()
+  public HiddenColumns getHiddenColumns()
   {
-    return columnSelection;
+    return hiddenColumns;
   }
 
-  public void setColumnSelection(ColumnSelection columnSelection)
+  public void setHiddenColumns(HiddenColumns hidden)
   {
-    this.columnSelection = columnSelection;
+    this.hiddenColumns = hidden;
   }
 
   @Override
index 20148b4..816346a 100644 (file)
@@ -32,7 +32,7 @@ import jalview.bin.BuildDetails;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
@@ -84,9 +84,7 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
 
   private FeatureRenderer fr;
 
-  private List<int[]> hiddenColumns;
-
-  private ColumnSelection columnSelection;
+  private HiddenColumns hiddenColumns;
 
   private List<String> hiddenSeqRefs;
 
@@ -281,8 +279,9 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
     // hidden column business
     if (getViewport().hasHiddenColumns())
     {
-      List<int[]> hiddenCols = getViewport().getColumnSelection()
-              .getHiddenColumns();
+      List<int[]> hiddenCols = getViewport().getAlignment()
+              .getHiddenColumns()
+              .getHiddenRegions();
       StringBuilder hiddenColsBuilder = new StringBuilder();
       for (int[] range : hiddenCols)
       {
@@ -667,12 +666,12 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
     String hiddenCols = (String) jvSettingsJson.get("hiddenCols");
     if (hiddenCols != null && !hiddenCols.isEmpty())
     {
-      columnSelection = new ColumnSelection();
+      hiddenColumns = new HiddenColumns();
       String[] rangeStrings = hiddenCols.split(";");
       for (String rangeString : rangeStrings)
       {
         String[] range = rangeString.split("-");
-        columnSelection.hideColumns(Integer.valueOf(range[0]),
+        hiddenColumns.hideColumns(Integer.valueOf(range[0]),
                 Integer.valueOf(range[1]));
       }
     }
@@ -791,20 +790,15 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
     return annotations;
   }
 
-  public List<int[]> getHiddenColumns()
-  {
-    return hiddenColumns;
-  }
-
   @Override
-  public ColumnSelection getColumnSelection()
+  public HiddenColumns getHiddenColumns()
   {
-    return columnSelection;
+    return hiddenColumns;
   }
 
-  public void setColumnSelection(ColumnSelection columnSelection)
+  public void setHiddenColumns(HiddenColumns hidden)
   {
-    this.columnSelection = columnSelection;
+    this.hiddenColumns = hidden;
   }
 
   @Override
index dc08b59..fdf8b58 100644 (file)
@@ -23,6 +23,7 @@ package jalview.javascript;
 import jalview.appletgui.AlignFrame;
 import jalview.bin.JalviewLite;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceGroup;
 import jalview.structure.SelectionSource;
 
@@ -44,7 +45,7 @@ public class JsSelectionSender extends JSFunctionExec implements
 
   @Override
   public void selection(SequenceGroup seqsel, ColumnSelection colsel,
-          SelectionSource source)
+          HiddenColumns hidden, SelectionSource source)
   {
     // System.err.println("Testing selection event relay to jsfunction:"+_listener);
     try
index 58034d9..88cc0a8 100755 (executable)
@@ -1853,12 +1853,6 @@ public class GAlignFrame extends JInternalFrame
     // selectMenu.add(listenToViewSelections);
   }
 
-  protected void configureSelectMenu()
-  {
-    // TODO Auto-generated method stub
-
-  }
-
   /**
    * Constructs the entries on the Colour menu (but does not add them to the
    * menu).
index 8c893a2..5c15e80 100755 (executable)
@@ -63,6 +63,8 @@ public class GFontChooser extends JPanel
 
   protected JCheckBox scaleAsCdna = new JCheckBox();
 
+  protected JCheckBox fontAsCdna = new JCheckBox();
+
   /**
    * Creates a new GFontChooser object.
    */
@@ -98,9 +100,10 @@ public class GFontChooser extends JPanel
     fontSize.setPreferredSize(new Dimension(50, 21));
     fontSize.addActionListener(new java.awt.event.ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
-        fontSize_actionPerformed(e);
+        fontSize_actionPerformed();
       }
     });
 
@@ -109,9 +112,10 @@ public class GFontChooser extends JPanel
     fontStyle.setPreferredSize(new Dimension(90, 21));
     fontStyle.addActionListener(new java.awt.event.ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
-        fontStyle_actionPerformed(e);
+        fontStyle_actionPerformed();
       }
     });
 
@@ -132,9 +136,10 @@ public class GFontChooser extends JPanel
     fontName.setPreferredSize(new Dimension(180, 21));
     fontName.addActionListener(new java.awt.event.ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
-        fontName_actionPerformed(e);
+        fontName_actionPerformed();
       }
     });
 
@@ -142,9 +147,10 @@ public class GFontChooser extends JPanel
     ok.setFont(VERDANA_11PT);
     ok.addActionListener(new java.awt.event.ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
-        ok_actionPerformed(e);
+        ok_actionPerformed();
       }
     });
 
@@ -152,9 +158,10 @@ public class GFontChooser extends JPanel
     cancel.setFont(VERDANA_11PT);
     cancel.addActionListener(new java.awt.event.ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
-        cancel_actionPerformed(e);
+        cancel_actionPerformed();
       }
     });
 
@@ -162,37 +169,57 @@ public class GFontChooser extends JPanel
     defaultButton.setText(MessageManager.getString("label.set_as_default"));
     defaultButton.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
-        defaultButton_actionPerformed(e);
+        defaultButton_actionPerformed();
       }
     });
 
     smoothFont.setFont(JvSwingUtils.getLabelFont());
     smoothFont.setOpaque(false);
     smoothFont.setText(MessageManager.getString("label.anti_alias_fonts"));
-    smoothFont.setBounds(new Rectangle(41, 65, 260, 23));
+    smoothFont.setBounds(new Rectangle(1, 65, 300, 23));
     smoothFont.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
-        smoothFont_actionPerformed(e);
+        smoothFont_actionPerformed();
       }
     });
 
     /*
-     * Scale protein as cDNA is only visible in SplitFrame protein alignment
+     * Scale protein as cDNA is only visible in SplitFrame
      */
     scaleAsCdna.setVisible(false);
     scaleAsCdna.setFont(JvSwingUtils.getLabelFont());
     scaleAsCdna.setOpaque(false);
     scaleAsCdna.setText(MessageManager.getString("label.scale_as_cdna"));
-    scaleAsCdna.setBounds(new Rectangle(41, 85, 260, 23));
+    scaleAsCdna.setBounds(new Rectangle(1, 85, 300, 23));
     scaleAsCdna.addActionListener(new ActionListener()
     {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        scaleAsCdna_actionPerformed();
+      }
+    });
+
+    /*
+     * Same font for cDNA/peptide is only visible in SplitFrame
+     */
+    fontAsCdna.setVisible(false);
+    fontAsCdna.setFont(JvSwingUtils.getLabelFont());
+    fontAsCdna.setOpaque(false);
+    fontAsCdna.setText(MessageManager.getString("label.font_as_cdna"));
+    fontAsCdna.setBounds(new Rectangle(1, 105, 350, 23));
+    fontAsCdna.addActionListener(new ActionListener()
+    {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
-        scaleAsCdna_actionPerformed(e);
+        mirrorFonts_actionPerformed();
       }
     });
 
@@ -239,85 +266,53 @@ public class GFontChooser extends JPanel
      */
     JPanel jPanel4 = new JPanel();
     jPanel4.setOpaque(false);
-    jPanel4.setBounds(new Rectangle(24, 112, 300, 35));
+    jPanel4.setBounds(new Rectangle(24, 132, 300, 35));
     jPanel4.add(defaultButton);
     jPanel4.add(ok);
     jPanel4.add(cancel);
 
     this.add(smoothFont);
     this.add(scaleAsCdna);
+    this.add(fontAsCdna);
     this.add(jPanel3, null);
     this.add(jPanel2, null);
     this.add(jPanel4);
     this.add(jPanel1, null);
   }
 
-  protected void scaleAsCdna_actionPerformed(ActionEvent e)
+  protected void mirrorFonts_actionPerformed()
   {
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
-   */
-  protected void ok_actionPerformed(ActionEvent e)
+  protected void scaleAsCdna_actionPerformed()
   {
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
-   */
-  protected void cancel_actionPerformed(ActionEvent e)
+  protected void ok_actionPerformed()
   {
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
-   */
-  protected void fontName_actionPerformed(ActionEvent e)
+  protected void cancel_actionPerformed()
   {
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
-   */
-  protected void fontSize_actionPerformed(ActionEvent e)
+  protected void fontName_actionPerformed()
   {
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
-   */
-  protected void fontStyle_actionPerformed(ActionEvent e)
+  protected void fontSize_actionPerformed()
   {
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
-   */
-  public void defaultButton_actionPerformed(ActionEvent e)
+  protected void fontStyle_actionPerformed()
   {
   }
 
-  public void smoothFont_actionPerformed(ActionEvent e)
+  public void defaultButton_actionPerformed()
   {
+  }
 
+  protected void smoothFont_actionPerformed()
+  {
   }
 }
index 3a064d2..041fefd 100644 (file)
@@ -33,6 +33,7 @@ import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
 import java.awt.CardLayout;
+import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.GridLayout;
@@ -54,11 +55,14 @@ import javax.swing.JComboBox;
 import javax.swing.JFrame;
 import javax.swing.JInternalFrame;
 import javax.swing.JLabel;
+import javax.swing.JList;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
 import javax.swing.JTabbedPane;
 import javax.swing.JTable;
 import javax.swing.JTextField;
+import javax.swing.ListCellRenderer;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 import javax.swing.event.DocumentEvent;
@@ -488,6 +492,19 @@ public abstract class GStructureChooser extends JPanel implements
     });
 
     cmb_filterOption.addItemListener(this);
+
+    // add CustomComboSeparatorsRenderer to filter option combo-box
+    cmb_filterOption.setRenderer(new CustomComboSeparatorsRenderer(
+            (ListCellRenderer<Object>) cmb_filterOption.getRenderer())
+    {
+      @Override
+      protected boolean addSeparatorAfter(JList list, FilterOption value,
+              int index)
+      {
+        return value.isAddSeparatorAfter();
+      }
+    });
+
     chk_invertFilter.addItemListener(this);
 
     pnl_actions.add(chk_rememberSettings);
@@ -643,11 +660,28 @@ public abstract class GStructureChooser extends JPanel implements
 
     private String view;
 
-    public FilterOption(String name, String value, String view)
+    private boolean addSeparatorAfter;
+
+    /**
+     * Model for structure filter option
+     * 
+     * @param name
+     *          - the name of the Option
+     * @param value
+     *          - the value of the option
+     * @param view
+     *          - the category of the filter option
+     * @param addSeparatorAfter
+     *          - if true, a horizontal separator is rendered immediately after
+     *          this filter option, otherwise
+     */
+    public FilterOption(String name, String value, String view,
+            boolean addSeparatorAfter)
     {
       this.name = name;
       this.value = value;
       this.view = view;
+      this.addSeparatorAfter = addSeparatorAfter;
     }
 
     public String getName()
@@ -685,6 +719,16 @@ public abstract class GStructureChooser extends JPanel implements
     {
       return this.name;
     }
+
+    public boolean isAddSeparatorAfter()
+    {
+      return addSeparatorAfter;
+    }
+
+    public void setAddSeparatorAfter(boolean addSeparatorAfter)
+    {
+      this.addSeparatorAfter = addSeparatorAfter;
+    }
   }
 
   /**
@@ -800,6 +844,54 @@ public abstract class GStructureChooser extends JPanel implements
     return cmb_filterOption;
   }
 
+  /**
+   * Custom ListCellRenderer for adding a separator between different categories
+   * of structure chooser filter option drop-down.
+   * 
+   * @author tcnofoegbu
+   *
+   */
+  public abstract class CustomComboSeparatorsRenderer implements
+          ListCellRenderer<Object>
+  {
+    private ListCellRenderer<Object> regent;
+
+    private JPanel separatorPanel = new JPanel(new BorderLayout());
+
+    private JSeparator jSeparator = new JSeparator();
+
+    public CustomComboSeparatorsRenderer(ListCellRenderer<Object> listCellRenderer)
+    {
+      this.regent = listCellRenderer;
+    }
+
+    @Override
+    public Component getListCellRendererComponent(JList list,
+            Object value,
+            int index, boolean isSelected, boolean cellHasFocus)
+    {
+
+      Component comp = regent.getListCellRendererComponent(list, value,
+              index, isSelected, cellHasFocus);
+      if (index != -1
+              && addSeparatorAfter(list, (FilterOption) value, index))
+      { 
+        separatorPanel.removeAll();
+        separatorPanel.add(comp, BorderLayout.CENTER);
+        separatorPanel.add(jSeparator, BorderLayout.SOUTH);
+        return separatorPanel;
+      }
+      else
+      {
+        return comp;
+      }
+    }
+
+    protected abstract boolean addSeparatorAfter(JList list,
+            FilterOption value,
+            int index);
+  }
+
   protected abstract void stateChanged(ItemEvent e);
 
   protected abstract void ok_ActionPerformed();
@@ -816,4 +908,4 @@ public abstract class GStructureChooser extends JPanel implements
   public abstract void tabRefresh();
 
   public abstract void validateSelections();
-}
+}
\ No newline at end of file
index 3a27c7d..518c179 100644 (file)
@@ -28,6 +28,7 @@ import jalview.api.AlignViewportI;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.ProfilesI;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.NucleotideColourScheme;
@@ -75,6 +76,8 @@ public class AnnotationRenderer
   ResidueShaderI profcolour = null;
 
   private ColumnSelection columnSelection;
+  
+  private HiddenColumns hiddenColumns;
 
   private ProfilesI hconsensus;
 
@@ -327,6 +330,7 @@ public class AnnotationRenderer
       profcolour = new ResidueShader(col);
     }
     columnSelection = av.getColumnSelection();
+    hiddenColumns = av.getAlignment().getHiddenColumns();
     hconsensus = av.getSequenceConsensusHash();
     complementConsensus = av.getComplementConsensusHash();
     hStrucConsensus = av.getRnaStructureConsensusHash();
@@ -589,7 +593,7 @@ hconsensus.get(column),
         {
           if (hasHiddenColumns)
           {
-            column = columnSelection.adjustForHiddenColumns(startRes + x);
+            column = hiddenColumns.adjustForHiddenColumns(startRes + x);
             if (column > row_annotations.length - 1)
             {
               break;
@@ -1231,7 +1235,7 @@ hconsensus.get(column),
       column = sRes + x;
       if (hasHiddenColumns)
       {
-        column = columnSelection.adjustForHiddenColumns(column);
+        column = hiddenColumns.adjustForHiddenColumns(column);
       }
 
       if (column > aaMax)
@@ -1310,7 +1314,7 @@ hconsensus.get(column),
       column = sRes + x;
       if (hasHiddenColumns)
       {
-        column = columnSelection.adjustForHiddenColumns(column);
+        column = hiddenColumns.adjustForHiddenColumns(column);
       }
 
       if (column > aaMax)
diff --git a/src/jalview/renderer/OverviewRenderer.java b/src/jalview/renderer/OverviewRenderer.java
new file mode 100644 (file)
index 0000000..9291ca6
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * 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.renderer;
+
+import jalview.api.AlignmentColsCollectionI;
+import jalview.api.AlignmentRowsCollectionI;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
+import jalview.renderer.seqfeatures.FeatureRenderer;
+import jalview.viewmodel.OverviewDimensions;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+
+public class OverviewRenderer
+{
+  private FeatureColourFinder finder;
+
+  private jalview.api.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(jalview.api.SequenceRenderer seqRenderer,
+          FeatureRenderer fr, OverviewDimensions od)
+  // FeatureColourFinder colfinder, OverviewDimensions od)
+  {
+    sr = seqRenderer;
+    finder = new FeatureColourFinder(fr); // 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(AlignmentRowsCollectionI rows,
+          AlignmentColsCollectionI 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);
+
+        // don't do expensive colour determination if we're not going to use it
+        // NB this is important to avoid performance issues in the overview
+        // panel
+        if (pixelCol <= endCol)
+        {
+          // 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 fcfinder)
+  {
+    Color color = Color.white;
+
+    if ((seq != null) && (seq.getLength() > lastcol))
+    {
+      color = sr.getResidueColour(seq, lastcol, fcfinder);
+    }
+
+    if (isHidden)
+    {
+      color = color.darker().darker();
+    }
+
+    return color.getRGB();
+  }
+
+  /**
+   * Draw the alignment annotation in the overview panel
+   * 
+   * @param g
+   *          the graphics object to draw on
+   * @param anno
+   *          alignment annotation information
+   * @param charWidth
+   *          alignment character width value
+   * @param y
+   *          y-position for the annotation graph
+   * @param cols
+   *          the collection of columns used in the overview panel
+   */
+  public void drawGraph(Graphics g, AlignmentAnnotation anno, int charWidth,
+          int y, AlignmentColsCollectionI cols)
+  {
+    Annotation[] annotations = anno.annotations;
+    g.setColor(Color.white);
+    g.fillRect(0, 0, miniMe.getWidth(), y);
+
+    int height;
+    int colIndex = 0;
+    int pixelCol = 0;
+    for (int alignmentCol : cols)
+    {
+      if (alignmentCol >= annotations.length)
+      {
+        break; // no more annotations to draw here
+      }
+      else
+      {
+        int endCol = Math.min(
+                Math.round((colIndex + 1) * pixelsPerCol) - 1,
+                miniMe.getWidth() - 1);
+
+        if (annotations[alignmentCol] != null)
+        {
+          if (annotations[alignmentCol].colour == null)
+          {
+            g.setColor(Color.black);
+          }
+          else
+          {
+            g.setColor(annotations[alignmentCol].colour);
+          }
+
+          height = (int) ((annotations[alignmentCol].value / anno.graphMax) * y);
+          if (height > y)
+          {
+            height = y;
+          }
+
+          g.fillRect(pixelCol, y - height, endCol - pixelCol + 1, height);
+        }
+        pixelCol = endCol + 1;
+        colIndex++;
+      }
+    }
+  }
+}
index 82536d4..9fec256 100644 (file)
@@ -73,7 +73,7 @@ public class ScaleRenderer
     {
       // find bounds and set origin appopriately
       // locate first visible position for this sequence
-      int[] refbounds = av.getColumnSelection()
+      int[] refbounds = av.getAlignment().getHiddenColumns()
               .locateVisibleBoundsOfSequence(refSeq);
 
       refSp = refbounds[0];
@@ -96,12 +96,14 @@ public class ScaleRenderer
       {
         if (refSeq == null)
         {
-          iadj = av.getColumnSelection().adjustForHiddenColumns(i - 1) + 1;
+          iadj = av.getAlignment().getHiddenColumns()
+                  .adjustForHiddenColumns(i - 1) + 1;
           string = String.valueOf(iadj);
         }
         else
         {
-          iadj = av.getColumnSelection().adjustForHiddenColumns(i - 1);
+          iadj = av.getAlignment().getHiddenColumns()
+                  .adjustForHiddenColumns(i - 1);
           refN = refSeq.findPosition(iadj);
           // TODO show bounds if position is a gap
           // - ie L--R -> "1L|2R" for
index 2877d46..fe878ce 100644 (file)
@@ -38,5 +38,7 @@ public interface SelectionListener
    *          - source of the selection event
    */
   public void selection(jalview.datamodel.SequenceGroup seqsel,
-          jalview.datamodel.ColumnSelection colsel, SelectionSource source);
+          jalview.datamodel.ColumnSelection colsel,
+          jalview.datamodel.HiddenColumns hidden,
+          SelectionSource source);
 }
index 0990b56..72da7ae 100644 (file)
@@ -29,6 +29,7 @@ import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
@@ -1201,13 +1202,14 @@ public class StructureSelectionManager
 
   public synchronized void sendSelection(
           jalview.datamodel.SequenceGroup selection,
-          jalview.datamodel.ColumnSelection colsel, SelectionSource source)
+          jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
+          SelectionSource source)
   {
     for (SelectionListener slis : sel_listeners)
     {
       if (slis != source)
       {
-        slis.selection(selection, colsel, source);
+        slis.selection(selection, colsel, hidden, source);
       }
     }
   }
index 84475fe..b336e45 100644 (file)
@@ -25,7 +25,7 @@ import jalview.api.SequenceRenderer;
 import jalview.api.StructureSelectionManagerProvider;
 import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.io.DataSourceType;
@@ -716,8 +716,8 @@ public abstract class AAStructureBindingModel extends
    *          an array of corresponding hidden columns for each alignment
    * @return
    */
-  public abstract String superposeStructures(AlignmentI[] alignments, int[] structureIndices,
-          ColumnSelection[] hiddenCols);
+  public abstract String superposeStructures(AlignmentI[] alignments,
+          int[] structureIndices, HiddenColumns[] hiddenCols);
 
   public abstract void setBackgroundColour(Color col);
 
index 2e30132..926ccc7 100644 (file)
@@ -31,6 +31,7 @@ import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
@@ -508,18 +509,20 @@ public final class MappingUtils
    * @param mapTo
    * @return
    */
-  public static ColumnSelection mapColumnSelection(ColumnSelection colsel,
-          AlignViewportI mapFrom, AlignViewportI mapTo)
+  public static void mapColumnSelection(ColumnSelection colsel,
+          HiddenColumns hiddencols, AlignViewportI mapFrom,
+          AlignViewportI mapTo, ColumnSelection newColSel,
+          HiddenColumns newHidden)
   {
     boolean targetIsNucleotide = mapTo.isNucleotide();
     AlignViewportI protein = targetIsNucleotide ? mapFrom : mapTo;
     List<AlignedCodonFrame> codonFrames = protein.getAlignment()
             .getCodonFrames();
-    ColumnSelection mappedColumns = new ColumnSelection();
+    // ColumnSelection mappedColumns = new ColumnSelection();
 
     if (colsel == null)
     {
-      return mappedColumns;
+      return; // mappedColumns;
     }
 
     char fromGapChar = mapFrom.getAlignment().getGapCharacter();
@@ -533,16 +536,16 @@ public final class MappingUtils
 
     for (Integer sel : colsel.getSelected())
     {
-      mapColumn(sel.intValue(), codonFrames, mappedColumns, fromSequences,
+      mapColumn(sel.intValue(), codonFrames, newColSel, fromSequences,
               toSequences, fromGapChar);
     }
 
-    for (int[] hidden : colsel.getHiddenColumns())
+    for (int[] hidden : hiddencols.getHiddenRegions())
     {
-      mapHiddenColumns(hidden, codonFrames, mappedColumns, fromSequences,
+      mapHiddenColumns(hidden, codonFrames, newHidden, fromSequences,
               toSequences, fromGapChar);
     }
-    return mappedColumns;
+    return; // mappedColumns;
   }
 
   /**
@@ -557,7 +560,7 @@ public final class MappingUtils
    * @param fromGapChar
    */
   protected static void mapHiddenColumns(int[] hidden,
-          List<AlignedCodonFrame> mappings, ColumnSelection mappedColumns,
+          List<AlignedCodonFrame> mappings, HiddenColumns mappedColumns,
           List<SequenceI> fromSequences, List<SequenceI> toSequences,
           char fromGapChar)
   {
index fa3a8a7..cdf0758 100644 (file)
  */
 package jalview.viewmodel;
 
-import java.awt.Color;
-import java.beans.PropertyChangeSupport;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.analysis.Conservation;
 import jalview.api.AlignCalcManagerI;
@@ -46,6 +35,7 @@ import jalview.datamodel.AlignmentView;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.CigarArray;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.ProfilesI;
 import jalview.datamodel.SearchResultsI;
@@ -69,6 +59,17 @@ import jalview.workers.ComplementConsensusThread;
 import jalview.workers.ConsensusThread;
 import jalview.workers.StrucConsensusThread;
 
+import java.awt.Color;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
 /**
  * base class holding visualization and analysis attributes and common logic for
  * an active alignment view displayed in the GUI
@@ -79,7 +80,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();
 
@@ -96,6 +97,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)
    */
@@ -555,10 +567,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()
@@ -600,7 +609,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
 
   protected boolean ignoreGapsInConsensusCalculation = false;
 
-  protected ResidueShaderI residueShading;
+  protected ResidueShaderI residueShading = new ResidueShader();
 
   @Override
   public void setGlobalColourScheme(ColourSchemeI cs)
@@ -1101,9 +1110,10 @@ public abstract class AlignmentViewport implements AlignViewportI,
     }
   }
 
-  public void setHiddenColumns(ColumnSelection colsel)
+  public void setHiddenColumns(HiddenColumns hidden)
   {
-    this.colSel = colsel;
+    this.alignment.setHiddenColumns(hidden);
+    // this.colSel = colsel;
   }
 
   @Override
@@ -1150,7 +1160,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
   @Override
   public boolean hasHiddenColumns()
   {
-    return colSel != null && colSel.hasHiddenColumns();
+    return colSel != null
+            && alignment.getHiddenColumns().hasHiddenColumns();
   }
 
   public void updateHiddenColumns()
@@ -1347,7 +1358,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
       return;
     }
 
-    colSel.hideSelectedColumns();
+    colSel.hideSelectedColumns(alignment);
     setSelectionGroup(null);
     isColSelChanged(true);
   }
@@ -1356,24 +1367,24 @@ public abstract class AlignmentViewport implements AlignViewportI,
   {
     if (start == end)
     {
-      colSel.hideColumns(start);
+      colSel.hideSelectedColumns(start, alignment.getHiddenColumns());
     }
     else
     {
-      colSel.hideColumns(start, end);
+      alignment.getHiddenColumns().hideColumns(start, end);
     }
     isColSelChanged(true);
   }
 
   public void showColumn(int col)
   {
-    colSel.revealHiddenColumns(col);
+    alignment.getHiddenColumns().revealHiddenColumns(col, colSel);
     isColSelChanged(true);
   }
 
   public void showAllHiddenColumns()
   {
-    colSel.revealAllHiddenColumns();
+    alignment.getHiddenColumns().revealAllHiddenColumns(colSel);
     isColSelChanged(true);
   }
 
@@ -1595,7 +1606,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
   @Override
   public void invertColumnSelection()
   {
-    colSel.invertColumnSelection(0, alignment.getWidth());
+    colSel.invertColumnSelection(0, alignment.getWidth(), alignment);
   }
 
   @Override
@@ -1643,7 +1654,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
   @Override
   public CigarArray getViewAsCigars(boolean selectedRegionOnly)
   {
-    return new CigarArray(alignment, colSel,
+    return new CigarArray(alignment, alignment.getHiddenColumns(),
             (selectedRegionOnly ? selectionGroup : null));
   }
 
@@ -1658,8 +1669,10 @@ public abstract class AlignmentViewport implements AlignViewportI,
   public jalview.datamodel.AlignmentView getAlignmentView(
           boolean selectedOnly, boolean markGroups)
   {
-    return new AlignmentView(alignment, colSel, selectionGroup,
-            colSel != null && colSel.hasHiddenColumns(), selectedOnly,
+    return new AlignmentView(alignment, alignment.getHiddenColumns(),
+            selectionGroup, alignment.getHiddenColumns() != null
+                    && alignment.getHiddenColumns().hasHiddenColumns(),
+            selectedOnly,
             markGroups);
   }
 
@@ -1703,9 +1716,11 @@ public abstract class AlignmentViewport implements AlignViewportI,
     }
 
     selection = new String[iSize];
-    if (colSel != null && colSel.hasHiddenColumns())
+    if (alignment.getHiddenColumns() != null
+            && alignment.getHiddenColumns().hasHiddenColumns())
     {
-      selection = colSel.getVisibleSequenceStrings(start, end, seqs);
+      selection = alignment.getHiddenColumns().getVisibleSequenceStrings(
+              start, end, seqs);
     }
     else
     {
@@ -1727,14 +1742,15 @@ public abstract class AlignmentViewport implements AlignViewportI,
 
     do
     {
-      if (colSel != null && colSel.hasHiddenColumns())
+      HiddenColumns hidden = alignment.getHiddenColumns();
+      if (hidden != null && hidden.hasHiddenColumns())
       {
         if (start == 0)
         {
-          start = colSel.adjustForHiddenColumns(start);
+          start = hidden.adjustForHiddenColumns(start);
         }
 
-        end = colSel.getHiddenBoundaryRight(start);
+        end = hidden.getHiddenBoundaryRight(start);
         if (start == end)
         {
           end = max;
@@ -1747,10 +1763,10 @@ public abstract class AlignmentViewport implements AlignViewportI,
 
       regions.add(new int[] { start, end });
 
-      if (colSel != null && colSel.hasHiddenColumns())
+      if (hidden != null && hidden.hasHiddenColumns())
       {
-        start = colSel.adjustForHiddenColumns(end);
-        start = colSel.getHiddenBoundaryLeft(start) + 1;
+        start = hidden.adjustForHiddenColumns(end);
+        start = hidden.getHiddenBoundaryLeft(start) + 1;
       }
     } while (end < max);
 
@@ -1772,12 +1788,13 @@ public abstract class AlignmentViewport implements AlignViewportI,
         AlignmentAnnotation clone = new AlignmentAnnotation(annot);
         if (selectedOnly && selectionGroup != null)
         {
-          colSel.makeVisibleAnnotation(selectionGroup.getStartRes(),
+          alignment.getHiddenColumns().makeVisibleAnnotation(
+                  selectionGroup.getStartRes(),
                   selectionGroup.getEndRes(), clone);
         }
         else
         {
-          colSel.makeVisibleAnnotation(clone);
+          alignment.getHiddenColumns().makeVisibleAnnotation(clone);
         }
         ala.add(clone);
       }
@@ -2658,6 +2675,18 @@ public abstract class AlignmentViewport implements AlignViewportI,
     viewStyle.setScaleProteinAsCdna(b);
   }
 
+  @Override
+  public boolean isProteinFontAsCdna()
+  {
+    return viewStyle.isProteinFontAsCdna();
+  }
+
+  @Override
+  public void setProteinFontAsCdna(boolean b)
+  {
+    viewStyle.setProteinFontAsCdna(b);
+  }
+
   /**
    * @return true if view should scroll to show the highlighted region of a
    *         sequence
index 43680b5..a837d53 100644 (file)
  */
 package jalview.viewmodel;
 
-import jalview.datamodel.ColumnSelection;
+import jalview.api.AlignmentColsCollectionI;
+import jalview.api.AlignmentRowsCollectionI;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
 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;
+  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;
 
-  // 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;
+  private static final int DEFAULT_GRAPH_HEIGHT = 20;
 
-  // scroll position in viewport corresponding to boxY
-  private int scrollRow = -1;
+  protected int width;
+  protected int sequencesHeight;
+  protected int graphHeight = DEFAULT_GRAPH_HEIGHT;
+  protected int boxX = -1;
+  protected int boxY = -1;
+  protected int boxWidth = -1;
+  protected int boxHeight = -1;
+  protected int scrollCol = -1;
+  protected int scrollRow = -1;
+  protected int alwidth;
+  protected int alheight;
 
-  /**
-   * Create an OverviewDimensions object
-   * 
-   * @param ranges
-   *          positional properties of the viewport
-   * @param showAnnotationPanel
-   *          true if the annotation panel is to be shown, false otherwise
-   */
   public OverviewDimensions(ViewportRanges ranges,
           boolean showAnnotationPanel)
   {
@@ -111,159 +86,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,42 +107,26 @@ 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;
   }
 
-  public void setWidth(int w)
-  {
-    width = w;
-  }
-
-  public void setHeight(int h)
-  {
-    sequencesHeight = h - graphHeight;
-  }
-
   public int getWidth()
   {
     return width;
@@ -340,4 +146,94 @@ public class OverviewDimensions
   {
     return graphHeight;
   }
-}
+
+  public float getPixelsPerCol()
+  {
+    resetAlignmentDims();
+    return (float) width / alwidth;
+  }
+
+  public float getPixelsPerSeq()
+  {
+    resetAlignmentDims();
+    return (float) sequencesHeight / alheight;
+  }
+
+  public void setWidth(int w)
+  {
+    width = w;
+  }
+
+  public void setHeight(int h)
+  {
+    sequencesHeight = h - graphHeight;
+  }
+
+  /**
+   * Update the viewport location from a mouse click in the overview panel
+   * 
+   * @param mousex
+   *          x location of mouse
+   * @param mousey
+   *          y location of mouse
+   * @param hiddenSeqs
+   *          the alignment's hidden sequences
+   * @param hiddenCols
+   *          the alignment's hidden columns
+   */
+  public abstract void updateViewportFromMouse(int mousex, int mousey,
+          HiddenSequences hiddenSeqs, HiddenColumns hiddenCols);
+
+  /**
+   * Set the overview panel's box position to match the viewport
+   * 
+   * @param hiddenSeqs
+   *          the alignment's hidden sequences
+   * @param hiddenCols
+   *          the alignment's hidden columns
+   */
+  public abstract void setBoxPosition(HiddenSequences hiddenSeqs,
+          HiddenColumns hiddenCols);
+
+  /**
+   * Get the collection of columns used by this overview dimensions object
+   * 
+   * @param hiddenCols
+   *          the alignment's hidden columns
+   * @return a column collection
+   */
+  public abstract AlignmentColsCollectionI getColumns(AlignmentI al);
+
+  /**
+   * Get the collection of rows used by this overview dimensions object
+   * 
+   * @param al
+   *          the alignment
+   * @return a row collection
+   */
+  public abstract AlignmentRowsCollectionI getRows(AlignmentI al);
+
+  /**
+   * Updates overview dimensions to account for current alignment dimensions
+   */
+  protected abstract void resetAlignmentDims();
+
+  protected void setBoxPosition(int startRes, int endRes, int startSeq,
+          int endSeq)
+  {
+    resetAlignmentDims();
+
+    // 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);
+  }
+}
\ No newline at end of file
diff --git a/src/jalview/viewmodel/OverviewDimensionsHideHidden.java b/src/jalview/viewmodel/OverviewDimensionsHideHidden.java
new file mode 100644 (file)
index 0000000..b03f9ac
--- /dev/null
@@ -0,0 +1,137 @@
+package jalview.viewmodel;
+
+import jalview.api.AlignmentColsCollectionI;
+import jalview.api.AlignmentRowsCollectionI;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.HiddenSequences;
+import jalview.datamodel.VisibleColsCollection;
+import jalview.datamodel.VisibleRowsCollection;
+
+public class OverviewDimensionsHideHidden extends OverviewDimensions
+{
+  private ViewportRanges ranges;
+
+  public OverviewDimensionsHideHidden(ViewportRanges vpranges,
+          boolean showAnnotationPanel)
+  {
+    super(vpranges, showAnnotationPanel);
+    ranges = vpranges;
+    resetAlignmentDims();
+  }
+
+  @Override
+  public void updateViewportFromMouse(int mousex, int mousey,
+          HiddenSequences hiddenSeqs, HiddenColumns hiddenCols)
+  {
+    resetAlignmentDims();
+
+    int x = mousex;
+    int y = mousey;
+
+    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,
+          HiddenColumns hiddenCols)
+  {
+    // work with visible values of startRes and endRes
+    int startRes = ranges.getStartRes();
+    int endRes = ranges.getEndRes();
+
+    // work with visible values of startSeq and endSeq
+    int startSeq = ranges.getStartSeq();
+    int endSeq = ranges.getEndSeq();
+
+    setBoxPosition(startRes, endRes, startSeq, endSeq);
+  }
+
+  @Override
+  public AlignmentColsCollectionI getColumns(AlignmentI al)
+  {
+    return new VisibleColsCollection(0,
+            ranges.getAbsoluteAlignmentWidth() - 1, al);
+  }
+
+  @Override
+  public AlignmentRowsCollectionI getRows(AlignmentI al)
+  {
+    return new VisibleRowsCollection(0,
+            ranges.getAbsoluteAlignmentHeight() - 1, al);
+  }
+
+  @Override
+  protected void resetAlignmentDims()
+  {
+    alwidth = ranges.getVisibleAlignmentWidth();
+    alheight = ranges.getVisibleAlignmentHeight();
+  }
+}
diff --git a/src/jalview/viewmodel/OverviewDimensionsShowHidden.java b/src/jalview/viewmodel/OverviewDimensionsShowHidden.java
new file mode 100644 (file)
index 0000000..b897189
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * 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.api.AlignmentColsCollectionI;
+import jalview.api.AlignmentRowsCollectionI;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AllColsCollection;
+import jalview.datamodel.AllRowsCollection;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.HiddenSequences;
+
+public class OverviewDimensionsShowHidden extends OverviewDimensions
+{
+  private ViewportRanges ranges;
+
+  /**
+   * 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 OverviewDimensionsShowHidden(ViewportRanges vpranges,
+          boolean showAnnotationPanel)
+  {
+    super(vpranges, showAnnotationPanel);
+    ranges = vpranges;
+    resetAlignmentDims();
+  }
+
+  /**
+   * 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, HiddenColumns hiddenCols)
+  {
+    int x = mousex;
+    int y = mousey;
+
+    resetAlignmentDims();
+
+    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,
+          HiddenColumns hiddenCols)
+  {
+    // 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());
+
+    setBoxPosition(startRes, endRes, startSeq, endSeq);
+  }
+
+  @Override
+  public AlignmentColsCollectionI getColumns(AlignmentI al)
+  {
+    return new AllColsCollection(0,
+            ranges.getAbsoluteAlignmentWidth() - 1, al);
+  }
+
+  @Override
+  public AlignmentRowsCollectionI getRows(AlignmentI al)
+  {
+    return new AllRowsCollection(0,
+            ranges.getAbsoluteAlignmentHeight() - 1,
+            al);
+  }
+
+  @Override
+  protected void resetAlignmentDims()
+  {
+    alwidth = ranges.getAbsoluteAlignmentWidth();
+    alheight = ranges.getAbsoluteAlignmentHeight();
+  }
+}
index c91d2d9..fc163e0 100644 (file)
@@ -79,6 +79,22 @@ public class ViewportRanges extends ViewportProperties
   }
 
   /**
+   * Get alignment width in cols, excluding hidden cols
+   */
+  public int getVisibleAlignmentWidth()
+  {
+    return al.getWidth() - al.getHiddenColumns().getSize();
+  }
+
+  /**
+   * Get alignment height in rows, excluding hidden rows
+   */
+  public int getVisibleAlignmentHeight()
+  {
+    return al.getHeight();
+  }
+
+  /**
    * Set first residue visible in the viewport
    * 
    * @param res
index 14a1bde..f01047d 100644 (file)
@@ -168,6 +168,12 @@ public class ViewStyle implements ViewStyleI
    */
   private boolean scaleProteinAsCdna = true;
 
+  /*
+   * if true, font changes to protein or cDNA are applied to both
+   * sides of a split screen
+   */
+  private boolean proteinFontAsCdna = true;
+
   /**
    * Copy constructor
    * 
@@ -195,6 +201,7 @@ public class ViewStyle implements ViewStyleI
     setScaleAboveWrapped(vs.getScaleAboveWrapped());
     setScaleLeftWrapped(vs.getScaleLeftWrapped());
     setScaleProteinAsCdna(vs.isScaleProteinAsCdna());
+    setProteinFontAsCdna(vs.isProteinFontAsCdna());
     setScaleRightWrapped(vs.getScaleRightWrapped());
     setSeqNameItalics(vs.isSeqNameItalics());
     setShowAnnotation(vs.isShowAnnotation());
@@ -255,6 +262,7 @@ public class ViewStyle implements ViewStyleI
             && getScaleAboveWrapped() == vs.getScaleAboveWrapped()
             && getScaleLeftWrapped() == vs.getScaleLeftWrapped()
             && isScaleProteinAsCdna() == vs.isScaleProteinAsCdna()
+            && isProteinFontAsCdna() == vs.isProteinFontAsCdna()
             && getScaleRightWrapped() == vs.getScaleRightWrapped()
             && isSeqNameItalics() == vs.isSeqNameItalics()
             && isShowAnnotation() == vs.isShowAnnotation()
@@ -1094,4 +1102,16 @@ public class ViewStyle implements ViewStyleI
   {
     this.scaleProteinAsCdna = b;
   }
+
+  @Override
+  public boolean isProteinFontAsCdna()
+  {
+    return proteinFontAsCdna;
+  }
+
+  @Override
+  public void setProteinFontAsCdna(boolean b)
+  {
+    proteinFontAsCdna = b;
+  }
 }
index beee1eb..b0392d4 100644 (file)
@@ -48,35 +48,17 @@ public class AlignmentAnnotationFactory
    * @param counter
    *          provider of feature counts per alignment position
    */
-  public static void newCalculator(FeatureCounterI counter)
+  public static void newCalculator(FeatureSetCounterI counter)
   {
-    // TODO need an interface for AlignFrame by which to access
-    // its AlignViewportI and AlignmentViewPanel
     AlignmentViewPanel currentAlignFrame = Jalview.getCurrentAlignFrame().alignPanel;
-    if (currentAlignFrame != null)
-    {
-      newCalculator(currentAlignFrame.getAlignViewport(),
-              currentAlignFrame, counter);
-    }
-    else
+    if (currentAlignFrame == null)
     {
       System.err
               .println("Can't register calculator as no alignment window has focus");
+      return;
     }
-  }
-
-  /**
-   * Constructs and registers a new alignment annotation worker
-   * 
-   * @param viewport
-   * @param panel
-   * @param counter
-   *          provider of feature counts per alignment position
-   */
-  public static void newCalculator(AlignViewportI viewport,
-          AlignmentViewPanel panel, FeatureCounterI counter)
-  {
-    new ColumnCounterWorker(viewport, panel, counter);
+    new ColumnCounterSetWorker(currentAlignFrame.getAlignViewport(),
+            currentAlignFrame, counter);
   }
 
   /**
@@ -92,8 +74,8 @@ public class AlignmentAnnotationFactory
     AlignFrame currentAlignFrame = Jalview.getCurrentAlignFrame();
     if (currentAlignFrame != null)
     {
-      newCalculator(currentAlignFrame.getViewport(), currentAlignFrame
-              .getAlignPanels().get(0), calculator);
+      new AnnotationWorker(currentAlignFrame.getViewport(),
+              currentAlignFrame.getAlignPanels().get(0), calculator);
     }
     else
     {
@@ -36,16 +36,16 @@ import java.util.ArrayList;
 import java.util.List;
 
 /**
- * A class to compute an alignment annotation with column counts of any
- * properties of interest of positions in an alignment. <br>
+ * A class to compute alignment annotations with column counts for a set of
+ * properties of interest on positions in an alignment. <br>
  * This is designed to be extensible, by supplying to the constructor an object
- * that computes a count for each residue position, based on the residue value
- * and any sequence features at that position.
+ * that computes a vector of counts for each residue position, based on the
+ * residue and and sequence features at that position.
  * 
  */
-class ColumnCounterWorker extends AlignCalcWorker
+class ColumnCounterSetWorker extends AlignCalcWorker
 {
-  FeatureCounterI counter;
+  FeatureSetCounterI counter;
 
   /**
    * Constructor registers the annotation for the given alignment frame
@@ -53,8 +53,8 @@ class ColumnCounterWorker extends AlignCalcWorker
    * @param af
    * @param counter
    */
-  public ColumnCounterWorker(AlignViewportI viewport,
-          AlignmentViewPanel panel, FeatureCounterI counter)
+  public ColumnCounterSetWorker(AlignViewportI viewport,
+          AlignmentViewPanel panel, FeatureSetCounterI counter)
   {
     super(viewport, panel);
     ourAnnots = new ArrayList<AlignmentAnnotation>();
@@ -69,6 +69,7 @@ class ColumnCounterWorker extends AlignCalcWorker
   @Override
   public void run()
   {
+    boolean annotationAdded = false;
     try
     {
       calcMan.notifyStart(this);
@@ -93,7 +94,7 @@ class ColumnCounterWorker extends AlignCalcWorker
       {
         try
         {
-          computeAnnotations();
+          annotationAdded = computeAnnotations();
         } catch (IndexOutOfBoundsException x)
         {
           // probable race condition. just finish and return without any fuss.
@@ -111,7 +112,10 @@ class ColumnCounterWorker extends AlignCalcWorker
 
     if (ap != null)
     {
-      ap.adjustAnnotationHeight();
+      if (annotationAdded)
+      {
+        ap.adjustAnnotationHeight();
+      }
       ap.paintAlignment(true);
     }
 
@@ -120,8 +124,10 @@ class ColumnCounterWorker extends AlignCalcWorker
   /**
    * Scan each column of the alignment to calculate a count by feature type. Set
    * the count as the value of the alignment annotation for that feature type.
+   * 
+   * @return
    */
-  void computeAnnotations()
+  boolean computeAnnotations()
   {
     FeatureRenderer fr = new FeatureRenderer(alignViewport);
     // TODO use the commented out code once JAL-2075 is fixed
@@ -130,56 +136,90 @@ class ColumnCounterWorker extends AlignCalcWorker
     // AlignmentView alignmentView = alignViewport.getAlignmentView(false);
     // AlignmentI alignment = alignmentView.getVisibleAlignment(' ');
 
-    // int width = alignmentView.getWidth();
+    int rows = counter.getNames().length;
+
     int width = alignment.getWidth();
     int height = alignment.getHeight();
-    int[] counts = new int[width];
-    int max = 0;
+    int[][] counts = new int[width][rows];
+    int max[] = new int[rows];
+    for (int crow = 0; crow < rows; crow++)
+    {
+      max[crow] = 0;
+    }
+
+    int[] minC = counter.getMinColour();
+    int[] maxC = counter.getMaxColour();
+    Color minColour = new Color(minC[0], minC[1], minC[2]);
+    Color maxColour = new Color(maxC[0], maxC[1], maxC[2]);
 
     for (int col = 0; col < width; col++)
     {
-      int count = 0;
+      int[] count = counts[col];
+      for (int crow = 0; crow < rows; crow++)
+      {
+        count[crow] = 0;
+      }
       for (int row = 0; row < height; row++)
       {
-        count += countFeaturesAt(alignment, col, row, fr);
+        int[] colcount = countFeaturesAt(alignment, col, row, fr);
+        if (colcount != null)
+        {
+          for (int crow = 0; crow < rows; crow++)
+          {
+            count[crow] += colcount[crow];
+          }
+        }
       }
       counts[col] = count;
-      max = Math.max(count, max);
+      for (int crow = 0; crow < rows; crow++)
+      {
+        max[crow] = Math.max(count[crow], max[crow]);
+      }
     }
 
-    Annotation[] anns = new Annotation[width];
-    /*
-     * add non-zero counts as annotations
-     */
-    for (int i = 0; i < counts.length; i++)
+    boolean annotationAdded = false;
+
+    for (int anrow = 0; anrow < rows; anrow++)
     {
-      int count = counts[i];
-      if (count > 0)
+      Annotation[] anns = new Annotation[width];
+      /*
+       * add non-zero counts as annotations
+       */
+      for (int i = 0; i < counts.length; i++)
       {
-        Color color = ColorUtils.getGraduatedColour(count, 0, Color.cyan,
-                max, Color.blue);
-        String str = String.valueOf(count);
-        anns[i] = new Annotation(str, str, '0', count, color);
+        int count = counts[i][anrow];
+        if (count > 0)
+        {
+          Color color = ColorUtils.getGraduatedColour(count, 0, minColour,
+                  max[anrow], maxColour);
+          String str = String.valueOf(count);
+          anns[i] = new Annotation(str, str, '0', count, color);
+        }
       }
-    }
 
-    /*
-     * construct or update the annotation
-     */
-    AlignmentAnnotation ann = alignViewport.getAlignment()
-            .findOrCreateAnnotation(counter.getName(),
-                    counter.getDescription(), false, null, null);
-    ann.description = counter.getDescription();
-    ann.showAllColLabels = true;
-    ann.scaleColLabel = true;
-    ann.graph = AlignmentAnnotation.BAR_GRAPH;
-    ann.annotations = anns;
-    setGraphMinMax(ann, anns);
-    ann.validateRangeAndDisplay();
-    if (!ourAnnots.contains(ann))
-    {
-      ourAnnots.add(ann);
+      /*
+       * construct or update the annotation
+       */
+      String description = counter.getDescriptions()[anrow];
+      if (!alignment.findAnnotation(description).iterator().hasNext())
+      {
+        annotationAdded = true;
+      }
+      AlignmentAnnotation ann = alignment.findOrCreateAnnotation(
+              counter.getNames()[anrow], description, false, null, null);
+      ann.description = description;
+      ann.showAllColLabels = true;
+      ann.scaleColLabel = true;
+      ann.graph = AlignmentAnnotation.BAR_GRAPH;
+      ann.annotations = anns;
+      setGraphMinMax(ann, anns);
+      ann.validateRangeAndDisplay();
+      if (!ourAnnots.contains(ann))
+      {
+        ourAnnots.add(ann);
+      }
     }
+    return annotationAdded;
   }
 
   /**
@@ -191,22 +231,22 @@ class ColumnCounterWorker extends AlignCalcWorker
    * @param row
    * @param fr
    */
-  int countFeaturesAt(AlignmentI alignment, int col, int row,
+  int[] countFeaturesAt(AlignmentI alignment, int col, int row,
           FeatureRenderer fr)
   {
     SequenceI seq = alignment.getSequenceAt(row);
     if (seq == null)
     {
-      return 0;
+      return null;
     }
     if (col >= seq.getLength())
     {
-      return 0;// sequence doesn't extend this far
+      return null;// sequence doesn't extend this far
     }
     char res = seq.getCharAt(col);
     if (Comparison.isGap(res))
     {
-      return 0;
+      return null;
     }
     int pos = seq.findPosition(col);
 
@@ -216,7 +256,7 @@ class ColumnCounterWorker extends AlignCalcWorker
     // NB have to adjust pos if using AlignmentView.getVisibleAlignment
     // see JAL-2075
     List<SequenceFeature> features = fr.findFeaturesAtRes(seq, pos);
-    int count = this.counter.count(String.valueOf(res), features);
+    int[] count = this.counter.count(String.valueOf(res), features);
     return count;
   }
 
similarity index 76%
rename from src/jalview/workers/FeatureCounterI.java
rename to src/jalview/workers/FeatureSetCounterI.java
index 3a080ec..e14952f 100644 (file)
@@ -18,6 +18,7 @@
  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
+
 package jalview.workers;
 
 import jalview.datamodel.SequenceFeature;
@@ -25,15 +26,16 @@ import jalview.datamodel.SequenceFeature;
 import java.util.List;
 
 /**
- * An interface for a type that returns counts of any value of interest at a
- * sequence position that can be determined from the sequence character and any
- * features present at that position
+ * An interface for a type that returns counts (per computed annotation type) of
+ * any value of interest at a sequence position that can be determined from the
+ * sequence character and any features present at that position
  * 
  */
-public interface FeatureCounterI
+public interface FeatureSetCounterI
 {
   /**
-   * Returns a count of some property of interest, for example
+   * Returns counts (per annotation type) of some properties of interest, for
+   * example
    * <ul>
    * <li>the number of variant features at the position</li>
    * <li>the number of Cath features of status 'True Positive'</li>
@@ -46,22 +48,22 @@ public interface FeatureCounterI
    * @param a
    *          list of any sequence features which include the position
    */
-  int count(String residue, List<SequenceFeature> features);
+  int[] count(String residue, List<SequenceFeature> features);
 
   /**
-   * Returns a name for the annotation that this is counting, for use as the
-   * displayed label
+   * Returns names for the annotations that this is counting, for use as the
+   * displayed labels
    * 
    * @return
    */
-  String getName();
+  String[] getNames();
 
   /**
-   * Returns a description for the annotation, for display as a tooltip
+   * Returns descriptions for the annotations, for display as tooltips
    * 
    * @return
    */
-  String getDescription();
+  String[] getDescriptions();
 
   /**
    * Returns the colour (as [red, green, blue] values in the range 0-255) to use
index e685d00..b0210d8 100644 (file)
@@ -27,7 +27,7 @@ import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
@@ -114,7 +114,7 @@ class JPredThread extends JWS1Thread implements WSClientI
         return null;
       }
       AlignmentI al = null;
-      ColumnSelection alcsel = null;
+      HiddenColumns alhidden = null;
       int FirstSeq = -1; // the position of the query sequence in Alignment al
 
       JpredResult result = (JpredResult) this.result;
@@ -141,10 +141,10 @@ class JPredThread extends JWS1Thread implements WSClientI
           if (predMap != null)
           {
             Object[] alandcolsel = input
-                    .getAlignmentAndColumnSelection(getGapChar());
+                    .getAlignmentAndHiddenColumns(getGapChar());
             sqs = (SequenceI[]) alandcolsel[0];
             al = new Alignment(sqs);
-            alcsel = (ColumnSelection) alandcolsel[1];
+            alhidden = (HiddenColumns) alandcolsel[1];
           }
           else
           {
@@ -192,7 +192,7 @@ class JPredThread extends JWS1Thread implements WSClientI
         {
           char gc = getGapChar();
           SequenceI[] sqs = (SequenceI[]) input
-                  .getAlignmentAndColumnSelection(gc)[0];
+                  .getAlignmentAndHiddenColumns(gc)[0];
           if (this.msaIndex >= sqs.length)
           {
             throw new Error(
@@ -237,7 +237,7 @@ class JPredThread extends JWS1Thread implements WSClientI
           {
             // Adjust input view for gaps
             // propagate insertions into profile
-            alcsel = ColumnSelection.propagateInsertions(profileseq, al,
+            alhidden = HiddenColumns.propagateInsertions(profileseq, al,
                     input);
           }
         }
@@ -252,7 +252,7 @@ class JPredThread extends JWS1Thread implements WSClientI
                   alant.sequenceRef);
         }
       }
-      return new Object[] { al, alcsel }; // , FirstSeq, noMsa};
+      return new Object[] { al, alhidden }; // , FirstSeq, noMsa};
     }
 
     /**
@@ -625,7 +625,7 @@ class JPredThread extends JWS1Thread implements WSClientI
             if (res[1] != null)
             {
               af = new AlignFrame((Alignment) res[0],
-                      (ColumnSelection) res[1], AlignFrame.DEFAULT_WIDTH,
+                      (HiddenColumns) res[1], AlignFrame.DEFAULT_WIDTH,
                       AlignFrame.DEFAULT_HEIGHT);
             }
             else
@@ -651,7 +651,8 @@ class JPredThread extends JWS1Thread implements WSClientI
              */
 
             af = new AlignFrame((Alignment) res[0],
-                    (ColumnSelection) res[1], AlignFrame.DEFAULT_WIDTH,
+ (HiddenColumns) res[1],
+                    AlignFrame.DEFAULT_WIDTH,
                     AlignFrame.DEFAULT_HEIGHT);
           }
           Desktop.addInternalFrame(af, altitle, AlignFrame.DEFAULT_WIDTH,
index e4247f7..72d41c9 100644 (file)
@@ -26,7 +26,7 @@ import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.AlignmentView;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
@@ -632,7 +632,7 @@ class MsaWSThread extends JWS1Thread implements WSClientI
       orders[j] = null;
     }
     SequenceI[] alignment = (SequenceI[]) newview[0];
-    ColumnSelection columnselection = (ColumnSelection) newview[1];
+    HiddenColumns hidden = (HiddenColumns) newview[1];
     Alignment al = new Alignment(alignment);
     // TODO: add 'provenance' property to alignment from the method notes
     // accompanying each subjob
@@ -646,7 +646,7 @@ class MsaWSThread extends JWS1Thread implements WSClientI
 
     if (newFrame)
     {
-      AlignFrame af = new AlignFrame(al, columnselection,
+      AlignFrame af = new AlignFrame(al, hidden,
               AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
 
       // initialise with same renderer settings as in parent alignframe.
index e425624..2187f46 100644 (file)
@@ -26,7 +26,7 @@ import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.AlignmentView;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
@@ -961,7 +961,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
       orders[j] = null;
     }
     SequenceI[] alignment = (SequenceI[]) newview[0];
-    ColumnSelection columnselection = (ColumnSelection) newview[1];
+    HiddenColumns hidden = (HiddenColumns) newview[1];
     Alignment al = new Alignment(alignment);
     // TODO: add 'provenance' property to alignment from the method notes
     if (lastProgram != null)
@@ -979,7 +979,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
 
     if (newFrame)
     {
-      displayInNewFrame(al, alorders, columnselection);
+      displayInNewFrame(al, alorders, hidden);
 
     }
     else
@@ -1000,9 +1000,9 @@ class MsaWSThread extends AWS2Thread implements WSClientI
    * @param columnselection
    */
   protected void displayInNewFrame(AlignmentI al,
-          List<AlignmentOrder> alorders, ColumnSelection columnselection)
+          List<AlignmentOrder> alorders, HiddenColumns hidden)
   {
-    AlignFrame af = new AlignFrame(al, columnselection,
+    AlignFrame af = new AlignFrame(al, hidden,
             AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
 
     // initialise with same renderer settings as in parent alignframe.
index 7fbae89..27f5271 100644 (file)
@@ -259,7 +259,8 @@ public class RestClient extends WSClient implements WSClientI,
         {
           // intersect groups with selected region
           _input = new AlignmentView(av.getAlignment(),
-                  av.getColumnSelection(), av.getSelectionGroup(),
+ av.getAlignment()
+                  .getHiddenColumns(), av.getSelectionGroup(),
                   av.hasHiddenColumns(), true, true);
           viewTitle = MessageManager.formatMessage(
                   "label.select_visible_region_of",
@@ -272,7 +273,8 @@ public class RestClient extends WSClient implements WSClientI,
         {
           // use selected region to partition alignment
           _input = new AlignmentView(av.getAlignment(),
-                  av.getColumnSelection(), av.getSelectionGroup(),
+ av.getAlignment()
+                  .getHiddenColumns(), av.getSelectionGroup(),
                   av.hasHiddenColumns(), false, true);
         }
         viewTitle = MessageManager.formatMessage(
@@ -286,7 +288,8 @@ public class RestClient extends WSClient implements WSClientI,
       {
         // just take selected region intersection
         _input = new AlignmentView(av.getAlignment(),
-                av.getColumnSelection(), av.getSelectionGroup(),
+ av.getAlignment()
+                .getHiddenColumns(), av.getSelectionGroup(),
                 av.hasHiddenColumns(), true, true);
         viewTitle = MessageManager.formatMessage(
                 "label.select_visible_region_of",
@@ -300,7 +303,8 @@ public class RestClient extends WSClient implements WSClientI,
     {
       // standard alignment view without selection present
       _input = new AlignmentView(av.getAlignment(),
-              av.getColumnSelection(), null, av.hasHiddenColumns(), false,
+ av.getAlignment()
+              .getHiddenColumns(), null, av.hasHiddenColumns(), false,
               true);
       viewTitle = ""
               + (av.hasHiddenColumns() ? (new StringBuffer(" ")
index 75d2cd4..0592426 100644 (file)
@@ -26,7 +26,7 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.Annotation;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
@@ -173,9 +173,13 @@ public class RestJobThread extends AWSThread
   private String getStage(Stage stg)
   {
     if (stg == Stage.SUBMIT)
+    {
       return "submitting ";
+    }
     if (stg == Stage.POLL)
+    {
       return "checking status of ";
+    }
 
     return (" being confused about ");
   }
@@ -609,7 +613,7 @@ public class RestJobThread extends AWSThread
     // total number of distinct alignment sets generated by job set.
     int numAlSets = 0, als = 0;
     List<AlignmentI> destAls = new ArrayList<AlignmentI>();
-    List<jalview.datamodel.ColumnSelection> destColsel = new ArrayList<jalview.datamodel.ColumnSelection>();
+    List<jalview.datamodel.HiddenColumns> destColsel = new ArrayList<jalview.datamodel.HiddenColumns>();
     List<List<NewickFile>> trees = new ArrayList<List<NewickFile>>();
 
     do
@@ -715,7 +719,7 @@ public class RestJobThread extends AWSThread
           RestJob rj = (RestJob) jobs[nrj];
           int contigs[] = input.getVisibleContigs();
           AlignmentI destAl = null;
-          jalview.datamodel.ColumnSelection destCs = null;
+          jalview.datamodel.HiddenColumns destHCs = null;
           // Resolve destAl for this data.
           if (als == 0 && rj.isInputContextModified())
           {
@@ -731,7 +735,7 @@ public class RestJobThread extends AWSThread
               if (!restClient.isAlignmentModified() && merge)
               {
                 destAl = restClient.av.getAlignment();
-                destCs = restClient.av.getColumnSelection();
+                destHCs = restClient.av.getAlignment().getHiddenColumns();
                 resultDest
                         .add(restClient.isShowResultsInNewView() ? AddDataTo.newView
                                 : AddDataTo.currentView);
@@ -742,15 +746,15 @@ public class RestJobThread extends AWSThread
                 newAlignment = true;
                 // recreate the input alignment data
                 Object[] idat = input
-                        .getAlignmentAndColumnSelection(gapCharacter);
+                        .getAlignmentAndHiddenColumns(gapCharacter);
                 destAl = new Alignment((SequenceI[]) idat[0]);
-                destCs = (ColumnSelection) idat[1];
+                destHCs = (HiddenColumns) idat[1];
                 resultDest.add(AddDataTo.newAlignment);
                 // but do not add to the alignment panel list - since we need to
                 // create a whole new alignFrame set.
               }
               destAls.add(destAl);
-              destColsel.add(destCs);
+              destColsel.add(destHCs);
             }
           }
           else
@@ -769,7 +773,7 @@ public class RestJobThread extends AWSThread
               // recover reference to last alignment created for this rest frame
               // ready for extension
               destAl = destAls.get(als);
-              destCs = destColsel.get(als);
+              destHCs = destColsel.get(als);
             }
             else
             {
@@ -798,12 +802,12 @@ public class RestJobThread extends AWSThread
                 newview = input.getUpdatedView(rseqs, orders, gapCharacter);
               }
               destAl = new Alignment((SequenceI[]) newview[0]);
-              destCs = (ColumnSelection) newview[1];
+              destHCs = (HiddenColumns) newview[1];
               newAlignment = true;
               // TODO create alignment from result data with propagated
               // references.
               destAls.add(destAl);
-              destColsel.add(destCs);
+              destColsel.add(destHCs);
               resultDest.add(AddDataTo.newAlignment);
               throw new Error(
                       MessageManager
@@ -1043,7 +1047,7 @@ public class RestJobThread extends AWSThread
     for (AddDataTo action : resultDest)
     {
       AlignmentI destal;
-      ColumnSelection destcs;
+      HiddenColumns destcs;
       String alTitle = MessageManager.formatMessage(
               "label.webservice_job_title_on", new String[] {
                   restClient.service.details.Action,
index 2e21d9c..d2fa99a 100644 (file)
@@ -28,7 +28,7 @@ import jalview.api.AlignViewportI;
 import jalview.datamodel.AlignedCodon;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignViewport;
@@ -133,7 +133,7 @@ public class DnaTest
     AlignmentI alf = new FormatAdapter().readFile(
             JAL_1312_example_align_fasta, DataSourceType.PASTE,
             FileFormat.Fasta);
-    ColumnSelection cs = new ColumnSelection();
+    HiddenColumns cs = new HiddenColumns();
     AlignViewportI av = new AlignViewport(alf, cs);
     Dna dna = new Dna(av, new int[] { 0, alf.getWidth() - 1 });
     AlignmentI translated = dna.translateCdna();
@@ -157,7 +157,7 @@ public class DnaTest
     int vwidth = 15;
     for (int ipos = 0; ipos + vwidth < alf.getWidth(); ipos += vwidth)
     {
-      ColumnSelection cs = new ColumnSelection();
+      HiddenColumns cs = new HiddenColumns();
       if (ipos > 0)
       {
         cs.hideColumns(0, ipos - 1);
@@ -188,7 +188,7 @@ public class DnaTest
   {
     AlignmentI alf = new FormatAdapter().readFile(fasta,
             DataSourceType.PASTE, FileFormat.Fasta);
-    ColumnSelection cs = new ColumnSelection();
+    HiddenColumns cs = new HiddenColumns();
     AlignViewportI av = new AlignViewport(alf, cs);
     Dna dna = new Dna(av, new int[] { 0, alf.getWidth() - 1 });
     AlignmentI translated = dna.translateCdna();
@@ -208,7 +208,7 @@ public class DnaTest
   {
     AlignmentI alf = new FormatAdapter().readFile(fasta,
             DataSourceType.PASTE, FileFormat.Fasta);
-    ColumnSelection cs = new ColumnSelection();
+    HiddenColumns cs = new HiddenColumns();
     cs.hideColumns(6, 14); // hide codons 3/4/5
     cs.hideColumns(24, 35); // hide codons 9-12
     cs.hideColumns(177, 191); // hide codons 60-64
@@ -296,7 +296,7 @@ public class DnaTest
      */
     AlignmentI cdna = new AlignmentGenerator(true)
             .generate(12, 8, 97, 5, 5);
-    ColumnSelection cs = new ColumnSelection();
+    HiddenColumns cs = new HiddenColumns();
     AlignViewportI av = new AlignViewport(cdna, cs);
     Dna dna = new Dna(av, new int[] { 0, cdna.getWidth() - 1 });
     AlignmentI translated = dna.translateCdna();
@@ -542,7 +542,7 @@ public class DnaTest
     assertEquals(seqDs, al.getSequenceAt(0).getDatasetSequence()
             .getSequenceAsString());
 
-    ColumnSelection cs = new ColumnSelection();
+    HiddenColumns cs = new HiddenColumns();
     AlignViewportI av = new AlignViewport(al, cs);
     Dna testee = new Dna(av, new int[] { 0, al.getWidth() - 1 });
     AlignmentI reversed = testee.reverseCdna(false);
diff --git a/test/jalview/datamodel/AllColsIteratorTest.java b/test/jalview/datamodel/AllColsIteratorTest.java
new file mode 100644 (file)
index 0000000..fbb20be
--- /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
+{
+  HiddenColumns hiddenCols;
+  
+  @BeforeClass
+  public void setup()
+  {
+    hiddenCols = new HiddenColumns();
+   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);
+  }
+}
index 4d3f611..7237e63 100644 (file)
@@ -22,10 +22,10 @@ package jalview.datamodel;
 
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
-import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 import static org.testng.AssertJUnit.fail;
 
+import jalview.analysis.AlignmentGenerator;
 import jalview.gui.JvOptionPane;
 
 import java.util.Arrays;
@@ -59,6 +59,30 @@ public class ColumnSelectionTest
     assertEquals("[2, 5, 3]", sel.toString());
   }
 
+  @Test(groups = { "Functional" })
+  public void testSetElementsFrom()
+  {
+    ColumnSelection fromcs = new ColumnSelection();
+    ColumnSelection tocs = new ColumnSelection();
+    HiddenColumns hidden = new HiddenColumns();
+
+    fromcs.addElement(2);
+    fromcs.addElement(3);
+    fromcs.addElement(5);
+
+    tocs.setElementsFrom(fromcs, hidden);
+    assertTrue(tocs.equals(fromcs));
+
+    hidden.hideColumns(4, 6);
+    tocs.setElementsFrom(fromcs, hidden);
+
+    // expect cols 2 and 3 to be selected but not 5
+    ColumnSelection expectcs = new ColumnSelection();
+    expectcs.addElement(2);
+    expectcs.addElement(3);
+    assertTrue(tocs.equals(expectcs));
+  }
+
   /**
    * Test the remove method - in particular to verify that remove(int i) removes
    * the element whose value is i, _NOT_ the i'th element.
@@ -88,264 +112,6 @@ public class ColumnSelectionTest
   }
 
   /**
-   * Test the method that finds the visible column position of an alignment
-   * column, allowing for hidden columns.
-   */
-  @Test(groups = { "Functional" })
-  public void testFindColumnPosition()
-  {
-    ColumnSelection cs = new ColumnSelection();
-    assertEquals(5, cs.findColumnPosition(5));
-
-    // hiding column 6 makes no difference
-    cs.hideColumns(6, 6);
-    assertEquals(5, cs.findColumnPosition(5));
-
-    // hiding column 4 moves column 5 to column 4
-    cs.hideColumns(4, 4);
-    assertEquals(4, cs.findColumnPosition(5));
-
-    // hiding column 4 moves column 4 to position 3
-    assertEquals(3, cs.findColumnPosition(4));
-
-    // hiding columns 1 and 2 moves column 5 to column 2
-    cs.hideColumns(1, 2);
-    assertEquals(2, cs.findColumnPosition(5));
-
-    // check with > 1 hidden column regions
-    // where some columns are in the hidden regions
-    ColumnSelection cs2 = new ColumnSelection();
-    cs2.hideColumns(5, 10);
-    cs2.hideColumns(20, 27);
-    cs2.hideColumns(40, 44);
-
-    // hiding columns 5-10 and 20-27 moves column 8 to column 4
-    assertEquals(4, cs2.findColumnPosition(8));
-
-    // and moves column 24 to 13
-    assertEquals(13, cs2.findColumnPosition(24));
-
-    // and moves column 28 to 14
-    assertEquals(14, cs2.findColumnPosition(28));
-
-    // and moves column 40 to 25
-    assertEquals(25, cs2.findColumnPosition(40));
-
-    // check when hidden columns start at 0 that the visible column
-    // is returned as 0
-    ColumnSelection cs3 = new ColumnSelection();
-    cs3.hideColumns(0, 4);
-    assertEquals(0, cs3.findColumnPosition(2));
-
-  }
-
-  /**
-   * Test the method that finds the visible column position a given distance
-   * before another column
-   */
-  @Test(groups = { "Functional" })
-  public void testFindColumnNToLeft()
-  {
-    ColumnSelection cs = new ColumnSelection();
-
-    // test that without hidden columns, findColumnNToLeft returns
-    // position n to left of provided position
-    int pos = cs.subtractVisibleColumns(3, 10);
-    assertEquals(7, pos);
-
-    // 0 returns same position
-    pos = cs.subtractVisibleColumns(0, 10);
-    assertEquals(10, pos);
-
-    // overflow to left returns negative number
-    pos = cs.subtractVisibleColumns(3, 0);
-    assertEquals(-3, pos);
-
-    // test that with hidden columns to left of result column
-    // behaviour is the same as above
-    cs.hideColumns(1, 3);
-
-    // position n to left of provided position
-    pos = cs.subtractVisibleColumns(3, 10);
-    assertEquals(7, pos);
-
-    // 0 returns same position
-    pos = cs.subtractVisibleColumns(0, 10);
-    assertEquals(10, pos);
-
-    // test with one set of hidden columns between start and required position
-    cs.hideColumns(12, 15);
-    pos = cs.subtractVisibleColumns(8, 17);
-    assertEquals(5, pos);
-
-    // test with two sets of hidden columns between start and required position
-    cs.hideColumns(20, 21);
-    pos = cs.subtractVisibleColumns(8, 23);
-    assertEquals(9, pos);
-
-    // repeat last 2 tests with no hidden columns to left of required position
-    cs.revealAllHiddenColumns();
-
-    // test with one set of hidden columns between start and required position
-    cs.hideColumns(12, 15);
-    pos = cs.subtractVisibleColumns(8, 17);
-    assertEquals(5, pos);
-
-    // test with two sets of hidden columns between start and required position
-    cs.hideColumns(20, 21);
-    pos = cs.subtractVisibleColumns(8, 23);
-    assertEquals(9, pos);
-
-  }
-
-  /**
-   * Test the code used to locate the reference sequence ruler origin
-   */
-  @Test(groups = { "Functional" })
-  public void testLocateVisibleBoundsofSequence()
-  {
-    ColumnSelection cs = new ColumnSelection();
-    SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---");
-    assertEquals(2, seq.findIndex(seq.getStart()));
-
-    // no hidden columns
-    assertEquals(
-            Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
-                seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
-                seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
-                seq.findIndex(seq.getEnd()) - 1 }),
-            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
-
-    // hidden column on gap after end of sequence - should not affect bounds
-    cs.hideColumns(13);
-    assertEquals(
-            Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
-                seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
-                seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
-                seq.findIndex(seq.getEnd()) - 1 }),
-            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
-
-    cs.revealAllHiddenColumns();
-    // hidden column on gap before beginning of sequence - should vis bounds by
-    // one
-    cs.hideColumns(0);
-    assertEquals(
-            Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 2,
-                seq.findIndex(seq.getEnd()) - 2, seq.getStart(),
-                seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
-                seq.findIndex(seq.getEnd()) - 1 }),
-            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
-
-    cs.revealAllHiddenColumns();
-    // hide columns around most of sequence - leave one residue remaining
-    cs.hideColumns(1, 3);
-    cs.hideColumns(6, 11);
-    assertEquals("-D",
-            cs.getVisibleSequenceStrings(0, 5, new SequenceI[] { seq })[0]);
-    assertEquals(
-            Arrays.toString(new int[] { 1, 1, 3, 3,
-                seq.findIndex(seq.getStart()) - 1,
-                seq.findIndex(seq.getEnd()) - 1 }),
-            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
-    cs.revealAllHiddenColumns();
-
-    // hide whole sequence - should just get location of hidden region
-    // containing sequence
-    cs.hideColumns(1, 11);
-    assertEquals(
-            Arrays.toString(new int[] { 0, 1, 0, 0,
-                seq.findIndex(seq.getStart()) - 1,
-                seq.findIndex(seq.getEnd()) - 1 }),
-            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
-
-  }
-
-  @Test(groups = { "Functional" })
-  public void testLocateVisibleBoundsPathologicals()
-  {
-    // test some pathological cases we missed
-    AlignmentI al = new Alignment(new SequenceI[] { new Sequence(
-            "refseqGaptest", "KTDVTI----------NFI-----G----L") });
-    ColumnSelection cs = new ColumnSelection();
-    cs.hideInsertionsFor(al.getSequenceAt(0));
-    assertEquals(
-            "G",
-            ""
-                    + al.getSequenceAt(0).getCharAt(
-                            cs.adjustForHiddenColumns(9)));
-
-  }
-
-  @Test(groups = { "Functional" })
-  public void testHideColumns()
-  {
-    ColumnSelection cs = new ColumnSelection();
-    cs.hideColumns(5);
-    List<int[]> hidden = cs.getHiddenColumns();
-    assertEquals(1, hidden.size());
-    assertEquals("[5, 5]", Arrays.toString(hidden.get(0)));
-
-    cs.hideColumns(3);
-    assertEquals(2, hidden.size());
-    // two hidden ranges, in order:
-    assertSame(hidden, cs.getHiddenColumns());
-    assertEquals("[3, 3]", Arrays.toString(hidden.get(0)));
-    assertEquals("[5, 5]", Arrays.toString(hidden.get(1)));
-
-    // hiding column 4 expands [3, 3] to [3, 4]
-    // and merges to [5, 5] to make [3, 5]
-    cs.hideColumns(4);
-    hidden = cs.getHiddenColumns();
-    assertEquals(1, hidden.size());
-    assertEquals("[3, 5]", Arrays.toString(hidden.get(0)));
-
-    // clear hidden columns (note they are added to selected)
-    cs.revealAllHiddenColumns();
-    // it is now actually null but getter returns an empty list
-    assertTrue(cs.getHiddenColumns().isEmpty());
-
-    cs.hideColumns(3, 6);
-    hidden = cs.getHiddenColumns();
-    int[] firstHiddenRange = hidden.get(0);
-    assertEquals("[3, 6]", Arrays.toString(firstHiddenRange));
-
-    // adding a subrange of already hidden should do nothing
-    cs.hideColumns(4, 5);
-    assertEquals(1, hidden.size());
-    assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
-    cs.hideColumns(3, 5);
-    assertEquals(1, hidden.size());
-    assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
-    cs.hideColumns(4, 6);
-    assertEquals(1, hidden.size());
-    assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
-    cs.hideColumns(3, 6);
-    assertEquals(1, hidden.size());
-    assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
-
-    cs.revealAllHiddenColumns();
-    cs.hideColumns(2, 4);
-    hidden = cs.getHiddenColumns();
-    assertEquals(1, hidden.size());
-    assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
-
-    // extend contiguous with 2 positions overlap
-    cs.hideColumns(3, 5);
-    assertEquals(1, hidden.size());
-    assertEquals("[2, 5]", Arrays.toString(hidden.get(0)));
-
-    // extend contiguous with 1 position overlap
-    cs.hideColumns(5, 6);
-    assertEquals(1, hidden.size());
-    assertEquals("[2, 6]", Arrays.toString(hidden.get(0)));
-
-    // extend contiguous with overlap both ends:
-    cs.hideColumns(1, 7);
-    assertEquals(1, hidden.size());
-    assertEquals("[1, 7]", Arrays.toString(hidden.get(0)));
-  }
-
-  /**
    * Test the method that hides a specified column including any adjacent
    * selected columns. This is a convenience method for the case where multiple
    * column regions are selected and then hidden using menu option View | Hide |
@@ -354,48 +120,55 @@ public class ColumnSelectionTest
   @Test(groups = { "Functional" })
   public void testHideColumns_withSelection()
   {
+    // create random alignment
+    AlignmentGenerator gen = new AlignmentGenerator(false);
+    AlignmentI al = gen.generate(50, 20, 123, 5, 5);
+
     ColumnSelection cs = new ColumnSelection();
     // select columns 4-6
     cs.addElement(4);
     cs.addElement(5);
     cs.addElement(6);
     // hide column 5 (and adjacent):
-    cs.hideColumns(5);
+    cs.hideSelectedColumns(5, al.getHiddenColumns());
     // 4,5,6 now hidden:
-    List<int[]> hidden = cs.getHiddenColumns();
+    List<int[]> hidden = al.getHiddenColumns().getHiddenRegions();
     assertEquals(1, hidden.size());
     assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
     // none now selected:
     assertTrue(cs.getSelected().isEmpty());
 
     // repeat, hiding column 4 (5 and 6)
+    al = gen.generate(50, 20, 123, 5, 5);
     cs = new ColumnSelection();
     cs.addElement(4);
     cs.addElement(5);
     cs.addElement(6);
-    cs.hideColumns(4);
-    hidden = cs.getHiddenColumns();
+    cs.hideSelectedColumns(4, al.getHiddenColumns());
+    hidden = al.getHiddenColumns().getHiddenRegions();
     assertEquals(1, hidden.size());
     assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
     assertTrue(cs.getSelected().isEmpty());
 
     // repeat, hiding column (4, 5 and) 6
+    al = gen.generate(50, 20, 123, 5, 5);
     cs = new ColumnSelection();
     cs.addElement(4);
     cs.addElement(5);
     cs.addElement(6);
-    cs.hideColumns(6);
-    hidden = cs.getHiddenColumns();
+    cs.hideSelectedColumns(6, al.getHiddenColumns());
+    hidden = al.getHiddenColumns().getHiddenRegions();
     assertEquals(1, hidden.size());
     assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
     assertTrue(cs.getSelected().isEmpty());
 
     // repeat, with _only_ adjacent columns selected
+    al = gen.generate(50, 20, 123, 5, 5);
     cs = new ColumnSelection();
     cs.addElement(4);
     cs.addElement(6);
-    cs.hideColumns(5);
-    hidden = cs.getHiddenColumns();
+    cs.hideSelectedColumns(5, al.getHiddenColumns());
+    hidden = al.getHiddenColumns().getHiddenRegions();
     assertEquals(1, hidden.size());
     assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
     assertTrue(cs.getSelected().isEmpty());
@@ -407,17 +180,23 @@ public class ColumnSelectionTest
   @Test(groups = { "Functional" })
   public void testHideSelectedColumns()
   {
+    // create random alignment
+    AlignmentGenerator gen = new AlignmentGenerator(false);
+    AlignmentI al = gen.generate(50, 20, 123, 5, 5);
+
     ColumnSelection cs = new ColumnSelection();
     int[] sel = { 2, 3, 4, 7, 8, 9, 20, 21, 22 };
     for (int col : sel)
     {
       cs.addElement(col);
     }
-    cs.hideColumns(15, 18);
 
-    cs.hideSelectedColumns();
+    HiddenColumns cols = al.getHiddenColumns();
+    cols.hideColumns(15, 18);
+
+    cs.hideSelectedColumns(al);
     assertTrue(cs.getSelected().isEmpty());
-    List<int[]> hidden = cs.getHiddenColumns();
+    List<int[]> hidden = cols.getHiddenRegions();
     assertEquals(4, hidden.size());
     assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
     assertEquals("[7, 9]", Arrays.toString(hidden.get(1)));
@@ -455,104 +234,27 @@ public class ColumnSelectionTest
     assertEquals("[0, 4]", Arrays.toString(range.get(0)));
   }
 
-  /**
-   * Test the method that reveals a range of hidden columns given the start
-   * column of the range
-   */
-  @Test(groups = { "Functional" })
-  public void testRevealHiddenColumns()
-  {
-    ColumnSelection cs = new ColumnSelection();
-    cs.hideColumns(5, 8);
-    cs.addElement(10);
-    cs.revealHiddenColumns(5);
-    // hidden columns list now null but getter returns empty list:
-    assertTrue(cs.getHiddenColumns().isEmpty());
-    // revealed columns are marked as selected (added to selection):
-    assertEquals("[10, 5, 6, 7, 8]", cs.getSelected().toString());
-
-    // calling with a column other than the range start does nothing:
-    cs = new ColumnSelection();
-    cs.hideColumns(5, 8);
-    List<int[]> hidden = cs.getHiddenColumns();
-    cs.revealHiddenColumns(6);
-    assertSame(hidden, cs.getHiddenColumns());
-    assertTrue(cs.getSelected().isEmpty());
-  }
-
-  @Test(groups = { "Functional" })
-  public void testRevealAllHiddenColumns()
-  {
-    ColumnSelection cs = new ColumnSelection();
-    cs.hideColumns(5, 8);
-    cs.hideColumns(2, 3);
-    cs.addElement(11);
-    cs.addElement(1);
-    cs.revealAllHiddenColumns();
-
-    /*
-     * revealing hidden columns adds them (in order) to the (unordered)
-     * selection list
-     */
-    assertTrue(cs.getHiddenColumns().isEmpty());
-    assertEquals("[11, 1, 2, 3, 5, 6, 7, 8]", cs.getSelected().toString());
-  }
-
-  @Test(groups = { "Functional" })
-  public void testIsVisible()
-  {
-    ColumnSelection cs = new ColumnSelection();
-    cs.hideColumns(2, 4);
-    cs.hideColumns(6, 7);
-    assertTrue(cs.isVisible(0));
-    assertTrue(cs.isVisible(-99));
-    assertTrue(cs.isVisible(1));
-    assertFalse(cs.isVisible(2));
-    assertFalse(cs.isVisible(3));
-    assertFalse(cs.isVisible(4));
-    assertTrue(cs.isVisible(5));
-    assertFalse(cs.isVisible(6));
-    assertFalse(cs.isVisible(7));
-  }
-
-  @Test(groups = { "Functional" })
-  public void testGetVisibleContigs()
-  {
-    ColumnSelection cs = new ColumnSelection();
-    cs.hideColumns(3, 6);
-    cs.hideColumns(8, 9);
-    cs.hideColumns(12, 12);
-
-    // start position is inclusive, end position exclusive:
-    int[] visible = cs.getVisibleContigs(1, 13);
-    assertEquals("[1, 2, 7, 7, 10, 11]", Arrays.toString(visible));
-
-    visible = cs.getVisibleContigs(4, 14);
-    assertEquals("[7, 7, 10, 11, 13, 13]", Arrays.toString(visible));
-
-    visible = cs.getVisibleContigs(3, 10);
-    assertEquals("[7, 7]", Arrays.toString(visible));
-
-    visible = cs.getVisibleContigs(4, 6);
-    assertEquals("[]", Arrays.toString(visible));
-  }
-
   @Test(groups = { "Functional" })
   public void testInvertColumnSelection()
   {
+    // create random alignment
+    AlignmentGenerator gen = new AlignmentGenerator(false);
+    AlignmentI al = gen.generate(50, 20, 123, 5, 5);
+
     ColumnSelection cs = new ColumnSelection();
     cs.addElement(4);
     cs.addElement(6);
     cs.addElement(8);
-    cs.hideColumns(3, 3);
-    cs.hideColumns(6, 6);
+
+    HiddenColumns cols = al.getHiddenColumns();
+    cols.hideColumns(3, 3);
+    cols.hideColumns(6, 6);
 
     // invert selection from start (inclusive) to end (exclusive)
-    // hidden columns are _not_ changed
-    cs.invertColumnSelection(2, 9);
+    cs.invertColumnSelection(2, 9, al);
     assertEquals("[2, 5, 7]", cs.getSelected().toString());
 
-    cs.invertColumnSelection(1, 9);
+    cs.invertColumnSelection(1, 9, al);
     assertEquals("[1, 4, 8]", cs.getSelected().toString());
   }
 
@@ -595,9 +297,6 @@ public class ColumnSelectionTest
     cs.addElement(0);
     cs.addElement(513);
     cs.addElement(1);
-    cs.hideColumns(3);
-    cs.hideColumns(7);
-    cs.hideColumns(5, 9);
 
     // same selections added in a different order
     ColumnSelection cs2 = new ColumnSelection();
@@ -605,15 +304,6 @@ public class ColumnSelectionTest
     cs2.addElement(513);
     cs2.addElement(0);
 
-    // with no hidden columns
-    assertFalse(cs.equals(cs2));
-    assertFalse(cs2.equals(cs));
-
-    // with hidden columns added in a different order
-    cs2.hideColumns(6, 9);
-    cs2.hideColumns(5, 8);
-    cs2.hideColumns(3);
-
     assertTrue(cs.equals(cs2));
     assertTrue(cs.equals(cs));
     assertTrue(cs2.equals(cs));
@@ -625,18 +315,20 @@ public class ColumnSelectionTest
 
     cs2.removeElement(12);
     assertTrue(cs.equals(cs2));
-
-    cs2.hideColumns(88);
-    assertFalse(cs.equals(cs2));
-    /*
-     * unhiding a column adds it to selection!
-     */
-    cs2.revealHiddenColumns(88);
-    assertFalse(cs.equals(cs2));
-    cs.addElement(88);
-    assertTrue(cs.equals(cs2));
   }
 
+  /*
+      cs2.hideSelectedColumns(88);
+      assertFalse(cs.equals(cs2));
+      /*
+       * unhiding a column adds it to selection!
+       */
+  /*    cs2.revealHiddenColumns(88);
+      assertFalse(cs.equals(cs2));
+      cs.addElement(88);
+      assertTrue(cs.equals(cs2));
+    */
+
   /**
    * Test the method that returns selected columns, in the order in which they
    * were added
@@ -834,75 +526,14 @@ public class ColumnSelectionTest
     ColumnSelection cs = new ColumnSelection();
     cs.addElement(3);
     cs.addElement(1);
-    cs.hideColumns(10, 11);
-    cs.hideColumns(5, 7);
-    assertEquals("[5, 7]", Arrays.toString(cs.getHiddenColumns().get(0)));
 
     ColumnSelection cs2 = new ColumnSelection(cs);
     assertTrue(cs2.hasSelectedColumns());
-    assertTrue(cs2.hasHiddenColumns());
+
     // order of column selection is preserved
     assertEquals("[3, 1]", cs2.getSelected().toString());
-    assertEquals(2, cs2.getHiddenColumns().size());
-    // hidden columns are held in column order
-    assertEquals("[5, 7]", Arrays.toString(cs2.getHiddenColumns().get(0)));
-    assertEquals("[10, 11]", Arrays.toString(cs2.getHiddenColumns().get(1)));
   }
 
-  /**
-   * Test for the case when a hidden range encloses more one already hidden
-   * range
-   */
-  @Test(groups = { "Functional" })
-  public void testHideColumns_subsumingHidden()
-  {
-    /*
-     * JAL-2370 bug scenario:
-     * two hidden ranges subsumed by a third
-     */
-    ColumnSelection cs = new ColumnSelection();
-    cs.hideColumns(49, 59);
-    cs.hideColumns(69, 79);
-    List<int[]> hidden = cs.getHiddenColumns();
-    assertEquals(2, hidden.size());
-    assertEquals("[49, 59]", Arrays.toString(hidden.get(0)));
-    assertEquals("[69, 79]", Arrays.toString(hidden.get(1)));
-  
-    cs.hideColumns(48, 80);
-    hidden = cs.getHiddenColumns();
-    assertEquals(1, hidden.size());
-    assertEquals("[48, 80]", Arrays.toString(hidden.get(0)));
-
-    /*
-     * another...joining hidden ranges
-     */
-    cs = new ColumnSelection();
-    cs.hideColumns(10, 20);
-    cs.hideColumns(30, 40);
-    cs.hideColumns(50, 60);
-    // hiding 21-49 should merge to one range
-    cs.hideColumns(21, 49);
-    hidden = cs.getHiddenColumns();
-    assertEquals(1, hidden.size());
-    assertEquals("[10, 60]", Arrays.toString(hidden.get(0)));
-
-    /*
-     * another...lef overlap, subsumption, right overlap,
-     * no overlap of existing hidden ranges
-     */
-    cs = new ColumnSelection();
-    cs.hideColumns(10, 20);
-    cs.hideColumns(10, 20);
-    cs.hideColumns(30, 35);
-    cs.hideColumns(40, 50);
-    cs.hideColumns(60, 70);
-
-    cs.hideColumns(15, 45);
-    hidden = cs.getHiddenColumns();
-    assertEquals(2, hidden.size());
-    assertEquals("[10, 50]", Arrays.toString(hidden.get(0)));
-    assertEquals("[60, 70]", Arrays.toString(hidden.get(1)));
-  }
 
   @Test(groups = { "Functional" })
   public void testStretchGroup_expand()
diff --git a/test/jalview/datamodel/HiddenColumnsTest.java b/test/jalview/datamodel/HiddenColumnsTest.java
new file mode 100644 (file)
index 0000000..b767cf7
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * 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.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertSame;
+import static org.testng.AssertJUnit.assertTrue;
+
+import jalview.analysis.AlignmentGenerator;
+import jalview.gui.JvOptionPane;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class HiddenColumnsTest
+{
+
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+  }
+
+  /**
+   * Test the method which counts the number of hidden columns
+   */
+  @Test(groups = { "Functional" })
+  public void testGetSize()
+  {
+    HiddenColumns hidden = new HiddenColumns();
+    assertEquals(0, hidden.getSize());
+
+    hidden.hideColumns(3, 5);
+    assertEquals(3, hidden.getSize());
+
+    hidden.hideColumns(8, 8);
+    assertEquals(4, hidden.getSize());
+
+    hidden.hideColumns(9, 14);
+    assertEquals(10, hidden.getSize());
+
+    ColumnSelection cs = new ColumnSelection();
+    hidden.revealAllHiddenColumns(cs);
+    assertEquals(0, hidden.getSize());
+  }
+
+  /**
+   * Test the method that finds the visible column position of an alignment
+   * column, allowing for hidden columns.
+   */
+  @Test(groups = { "Functional" })
+  public void testFindColumnPosition()
+  {
+    HiddenColumns cs = new HiddenColumns();
+    assertEquals(5, cs.findColumnPosition(5));
+
+    // hiding column 6 makes no difference
+    cs.hideColumns(6, 6);
+    assertEquals(5, cs.findColumnPosition(5));
+
+    // hiding column 4 moves column 5 to column 4
+    cs.hideColumns(4, 4);
+    assertEquals(4, cs.findColumnPosition(5));
+
+    // hiding column 4 moves column 4 to position 3
+    assertEquals(3, cs.findColumnPosition(4));
+
+    // hiding columns 1 and 2 moves column 5 to column 2
+    cs.hideColumns(1, 2);
+    assertEquals(2, cs.findColumnPosition(5));
+
+    // check with > 1 hidden column regions
+    // where some columns are in the hidden regions
+    HiddenColumns cs2 = new HiddenColumns();
+    cs2.hideColumns(5, 10);
+    cs2.hideColumns(20, 27);
+    cs2.hideColumns(40, 44);
+
+    // hiding columns 5-10 and 20-27 moves column 8 to column 4
+    assertEquals(4, cs2.findColumnPosition(8));
+
+    // and moves column 24 to 13
+    assertEquals(13, cs2.findColumnPosition(24));
+
+    // and moves column 28 to 14
+    assertEquals(14, cs2.findColumnPosition(28));
+
+    // and moves column 40 to 25
+    assertEquals(25, cs2.findColumnPosition(40));
+
+    // check when hidden columns start at 0 that the visible column
+    // is returned as 0
+    HiddenColumns cs3 = new HiddenColumns();
+    cs3.hideColumns(0, 4);
+    assertEquals(0, cs3.findColumnPosition(2));
+
+  }
+
+  /**
+   * Test the method that finds the visible column position a given distance
+   * before another column
+   */
+  @Test(groups = { "Functional" })
+  public void testFindColumnNToLeft()
+  {
+    HiddenColumns cs = new HiddenColumns();
+
+    // test that without hidden columns, findColumnNToLeft returns
+    // position n to left of provided position
+    int pos = cs.subtractVisibleColumns(3, 10);
+    assertEquals(7, pos);
+
+    // 0 returns same position
+    pos = cs.subtractVisibleColumns(0, 10);
+    assertEquals(10, pos);
+
+    // overflow to left returns negative number
+    pos = cs.subtractVisibleColumns(3, 0);
+    assertEquals(-3, pos);
+
+    // test that with hidden columns to left of result column
+    // behaviour is the same as above
+    cs.hideColumns(1, 3);
+
+    // position n to left of provided position
+    pos = cs.subtractVisibleColumns(3, 10);
+    assertEquals(7, pos);
+
+    // 0 returns same position
+    pos = cs.subtractVisibleColumns(0, 10);
+    assertEquals(10, pos);
+
+    // test with one set of hidden columns between start and required position
+    cs.hideColumns(12, 15);
+    pos = cs.subtractVisibleColumns(8, 17);
+    assertEquals(5, pos);
+
+    // test with two sets of hidden columns between start and required position
+    cs.hideColumns(20, 21);
+    pos = cs.subtractVisibleColumns(8, 23);
+    assertEquals(9, pos);
+
+    // repeat last 2 tests with no hidden columns to left of required position
+    ColumnSelection colsel = new ColumnSelection();
+    cs.revealAllHiddenColumns(colsel);
+
+    // test with one set of hidden columns between start and required position
+    cs.hideColumns(12, 15);
+    pos = cs.subtractVisibleColumns(8, 17);
+    assertEquals(5, pos);
+
+    // test with two sets of hidden columns between start and required position
+    cs.hideColumns(20, 21);
+    pos = cs.subtractVisibleColumns(8, 23);
+    assertEquals(9, pos);
+
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetVisibleContigs()
+  {
+    HiddenColumns cs = new HiddenColumns();
+    cs.hideColumns(3, 6);
+    cs.hideColumns(8, 9);
+    cs.hideColumns(12, 12);
+
+    // start position is inclusive, end position exclusive:
+    int[] visible = cs.getVisibleContigs(1, 13);
+    assertEquals("[1, 2, 7, 7, 10, 11]", Arrays.toString(visible));
+
+    visible = cs.getVisibleContigs(4, 14);
+    assertEquals("[7, 7, 10, 11, 13, 13]", Arrays.toString(visible));
+
+    visible = cs.getVisibleContigs(3, 10);
+    assertEquals("[7, 7]", Arrays.toString(visible));
+
+    visible = cs.getVisibleContigs(4, 6);
+    assertEquals("[]", Arrays.toString(visible));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testEquals()
+  {
+    HiddenColumns cs = new HiddenColumns();
+    cs.hideColumns(5, 9);
+
+    // a different set of hidden columns
+    HiddenColumns cs2 = new HiddenColumns();
+
+    // with no hidden columns
+    assertFalse(cs.equals(cs2));
+    assertFalse(cs2.equals(cs));
+
+    // with hidden columns added in a different order
+    cs2.hideColumns(6, 9);
+    cs2.hideColumns(5, 8);
+
+    assertTrue(cs.equals(cs2));
+    assertTrue(cs.equals(cs));
+    assertTrue(cs2.equals(cs));
+    assertTrue(cs2.equals(cs2));
+  }
+
+  @Test(groups = "Functional")
+  public void testCopyConstructor()
+  {
+    HiddenColumns cs = new HiddenColumns();
+    cs.hideColumns(10, 11);
+    cs.hideColumns(5, 7);
+    assertEquals("[5, 7]", Arrays.toString(cs.getHiddenRegions().get(0)));
+
+    HiddenColumns cs2 = new HiddenColumns(cs);
+    assertTrue(cs2.hasHiddenColumns());
+    assertEquals(2, cs2.getHiddenRegions().size());
+    // hidden columns are held in column order
+    assertEquals("[5, 7]", Arrays.toString(cs2.getHiddenRegions().get(0)));
+    assertEquals("[10, 11]", Arrays.toString(cs2.getHiddenRegions().get(1)));
+  }
+
+  /**
+   * Test the code used to locate the reference sequence ruler origin
+   */
+  @Test(groups = { "Functional" })
+  public void testLocateVisibleBoundsofSequence()
+  {
+    // create random alignment
+    AlignmentGenerator gen = new AlignmentGenerator(false);
+    AlignmentI al = gen.generate(50, 20, 123, 5, 5);
+
+    HiddenColumns cs = al.getHiddenColumns();
+    ColumnSelection colsel = new ColumnSelection();
+
+    SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---");
+    assertEquals(2, seq.findIndex(seq.getStart()));
+
+    // no hidden columns
+    assertEquals(
+            Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
+                seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+    // hidden column on gap after end of sequence - should not affect bounds
+    colsel.hideSelectedColumns(13, al.getHiddenColumns());
+    assertEquals(
+            Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
+                seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+    cs.revealAllHiddenColumns(colsel);
+    // hidden column on gap before beginning of sequence - should vis bounds by
+    // one
+    colsel.hideSelectedColumns(0, al.getHiddenColumns());
+    assertEquals(
+            Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 2,
+                seq.findIndex(seq.getEnd()) - 2, seq.getStart(),
+                seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+    cs.revealAllHiddenColumns(colsel);
+    // hide columns around most of sequence - leave one residue remaining
+    cs.hideColumns(1, 3);
+    cs.hideColumns(6, 11);
+    assertEquals("-D",
+            cs.getVisibleSequenceStrings(0, 5, new SequenceI[] { seq })[0]);
+    assertEquals(
+            Arrays.toString(new int[] { 1, 1, 3, 3,
+                seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+    cs.revealAllHiddenColumns(colsel);
+
+    // hide whole sequence - should just get location of hidden region
+    // containing sequence
+    cs.hideColumns(1, 11);
+    assertEquals(
+            Arrays.toString(new int[] { 0, 1, 0, 0,
+                seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+  }
+
+  @Test(groups = { "Functional" })
+  public void testLocateVisibleBoundsPathologicals()
+  {
+    // test some pathological cases we missed
+    AlignmentI al = new Alignment(new SequenceI[] { new Sequence(
+            "refseqGaptest", "KTDVTI----------NFI-----G----L") });
+    HiddenColumns cs = new HiddenColumns();
+    cs.hideInsertionsFor(al.getSequenceAt(0));
+    assertEquals(
+            "G",
+            ""
+                    + al.getSequenceAt(0).getCharAt(
+                            cs.adjustForHiddenColumns(9)));
+
+  }
+
+  @Test(groups = { "Functional" })
+  public void testHideColumns()
+  {
+    // create random alignment
+    AlignmentGenerator gen = new AlignmentGenerator(false);
+    AlignmentI al = gen.generate(50, 20, 123, 5, 5);
+
+    ColumnSelection colsel = new ColumnSelection();
+    HiddenColumns cs = al.getHiddenColumns();
+    colsel.hideSelectedColumns(5, al.getHiddenColumns());
+    List<int[]> hidden = cs.getHiddenRegions();
+    assertEquals(1, hidden.size());
+    assertEquals("[5, 5]", Arrays.toString(hidden.get(0)));
+
+    colsel.hideSelectedColumns(3, al.getHiddenColumns());
+    assertEquals(2, hidden.size());
+    // two hidden ranges, in order:
+    assertSame(hidden, cs.getHiddenRegions());
+    assertEquals("[3, 3]", Arrays.toString(hidden.get(0)));
+    assertEquals("[5, 5]", Arrays.toString(hidden.get(1)));
+
+    // hiding column 4 expands [3, 3] to [3, 4]
+    // and merges to [5, 5] to make [3, 5]
+    colsel.hideSelectedColumns(4, al.getHiddenColumns());
+    hidden = cs.getHiddenRegions();
+    assertEquals(1, hidden.size());
+    assertEquals("[3, 5]", Arrays.toString(hidden.get(0)));
+
+    // clear hidden columns (note they are added to selected)
+    cs.revealAllHiddenColumns(colsel);
+    // it is now actually null but getter returns an empty list
+    assertTrue(cs.getHiddenRegions().isEmpty());
+
+    cs.hideColumns(3, 6);
+    hidden = cs.getHiddenRegions();
+    int[] firstHiddenRange = hidden.get(0);
+    assertEquals("[3, 6]", Arrays.toString(firstHiddenRange));
+
+    // adding a subrange of already hidden should do nothing
+    cs.hideColumns(4, 5);
+    assertEquals(1, hidden.size());
+    assertSame(firstHiddenRange, cs.getHiddenRegions().get(0));
+    cs.hideColumns(3, 5);
+    assertEquals(1, hidden.size());
+    assertSame(firstHiddenRange, cs.getHiddenRegions().get(0));
+    cs.hideColumns(4, 6);
+    assertEquals(1, hidden.size());
+    assertSame(firstHiddenRange, cs.getHiddenRegions().get(0));
+    cs.hideColumns(3, 6);
+    assertEquals(1, hidden.size());
+    assertSame(firstHiddenRange, cs.getHiddenRegions().get(0));
+
+    cs.revealAllHiddenColumns(colsel);
+    cs.hideColumns(2, 4);
+    hidden = cs.getHiddenRegions();
+    assertEquals(1, hidden.size());
+    assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
+
+    // extend contiguous with 2 positions overlap
+    cs.hideColumns(3, 5);
+    assertEquals(1, hidden.size());
+    assertEquals("[2, 5]", Arrays.toString(hidden.get(0)));
+
+    // extend contiguous with 1 position overlap
+    cs.hideColumns(5, 6);
+    assertEquals(1, hidden.size());
+    assertEquals("[2, 6]", Arrays.toString(hidden.get(0)));
+
+    // extend contiguous with overlap both ends:
+    cs.hideColumns(1, 7);
+    assertEquals(1, hidden.size());
+    assertEquals("[1, 7]", Arrays.toString(hidden.get(0)));
+  }
+
+  /**
+   * Test the method that reveals a range of hidden columns given the start
+   * column of the range
+   */
+  @Test(groups = { "Functional" })
+  public void testRevealHiddenColumns()
+  {
+    ColumnSelection colsel = new ColumnSelection();
+    HiddenColumns cs = new HiddenColumns();
+    cs.hideColumns(5, 8);
+    colsel.addElement(10);
+    cs.revealHiddenColumns(5, colsel);
+    // hidden columns list now null but getter returns empty list:
+    assertTrue(cs.getHiddenRegions().isEmpty());
+    // revealed columns are marked as selected (added to selection):
+    assertEquals("[10, 5, 6, 7, 8]", colsel.getSelected().toString());
+
+    // calling with a column other than the range start does nothing:
+    colsel = new ColumnSelection();
+    cs = new HiddenColumns();
+    cs.hideColumns(5, 8);
+    List<int[]> hidden = cs.getHiddenRegions();
+    cs.revealHiddenColumns(6, colsel);
+    assertSame(hidden, cs.getHiddenRegions());
+    assertTrue(colsel.getSelected().isEmpty());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testRevealAllHiddenColumns()
+  {
+    HiddenColumns cs = new HiddenColumns();
+    ColumnSelection colsel = new ColumnSelection();
+    cs.hideColumns(5, 8);
+    cs.hideColumns(2, 3);
+    colsel.addElement(11);
+    colsel.addElement(1);
+    cs.revealAllHiddenColumns(colsel);
+
+    /*
+     * revealing hidden columns adds them (in order) to the (unordered)
+     * selection list
+     */
+    assertTrue(cs.getHiddenRegions().isEmpty());
+    assertEquals("[11, 1, 2, 3, 5, 6, 7, 8]", colsel.getSelected()
+            .toString());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testIsVisible()
+  {
+    HiddenColumns cs = new HiddenColumns();
+    cs.hideColumns(2, 4);
+    cs.hideColumns(6, 7);
+    assertTrue(cs.isVisible(0));
+    assertTrue(cs.isVisible(-99));
+    assertTrue(cs.isVisible(1));
+    assertFalse(cs.isVisible(2));
+    assertFalse(cs.isVisible(3));
+    assertFalse(cs.isVisible(4));
+    assertTrue(cs.isVisible(5));
+    assertFalse(cs.isVisible(6));
+    assertFalse(cs.isVisible(7));
+  }
+
+  /**
+   * Test for the case when a hidden range encloses more one already hidden
+   * range
+   */
+  @Test(groups = { "Functional" })
+  public void testHideColumns_subsumingHidden()
+  {
+    /*
+     * JAL-2370 bug scenario:
+     * two hidden ranges subsumed by a third
+     */
+    HiddenColumns cs = new HiddenColumns();
+    cs.hideColumns(49, 59);
+    cs.hideColumns(69, 79);
+    List<int[]> hidden = cs.getHiddenRegions();
+    assertEquals(2, hidden.size());
+    assertEquals("[49, 59]", Arrays.toString(hidden.get(0)));
+    assertEquals("[69, 79]", Arrays.toString(hidden.get(1)));
+
+    cs.hideColumns(48, 80);
+    hidden = cs.getHiddenRegions();
+    assertEquals(1, hidden.size());
+    assertEquals("[48, 80]", Arrays.toString(hidden.get(0)));
+
+    /*
+     * another...joining hidden ranges
+     */
+    cs = new HiddenColumns();
+    cs.hideColumns(10, 20);
+    cs.hideColumns(30, 40);
+    cs.hideColumns(50, 60);
+    // hiding 21-49 should merge to one range
+    cs.hideColumns(21, 49);
+    hidden = cs.getHiddenRegions();
+    assertEquals(1, hidden.size());
+    assertEquals("[10, 60]", Arrays.toString(hidden.get(0)));
+
+    /*
+     * another...left overlap, subsumption, right overlap,
+     * no overlap of existing hidden ranges
+     */
+    cs = new HiddenColumns();
+    cs.hideColumns(10, 20);
+    cs.hideColumns(10, 20);
+    cs.hideColumns(30, 35);
+    cs.hideColumns(40, 50);
+    cs.hideColumns(60, 70);
+
+    cs.hideColumns(15, 45);
+    hidden = cs.getHiddenRegions();
+    assertEquals(2, hidden.size());
+    assertEquals("[10, 50]", Arrays.toString(hidden.get(0)));
+    assertEquals("[60, 70]", Arrays.toString(hidden.get(1)));
+  }
+
+}
diff --git a/test/jalview/datamodel/VisibleColsIteratorTest.java b/test/jalview/datamodel/VisibleColsIteratorTest.java
new file mode 100644 (file)
index 0000000..b2d747b
--- /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
+{
+  HiddenColumns hiddenCols;
+
+  HiddenColumns hiddenColsAtStart;
+
+  @BeforeClass(groups = { "Functional" })
+  public void setup()
+  {
+    hiddenCols = new HiddenColumns();
+    hiddenCols.hideColumns(2, 4);
+
+    hiddenColsAtStart = new HiddenColumns();
+    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 HiddenColumns());
+    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 HiddenColumns());
+    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..4a021c5
--- /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(groups = { "Functional" })
+  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 2ea94a4..fed5992 100644 (file)
@@ -85,11 +85,13 @@ public class AlignFrameTest
      */
     assertFalse(alignFrame.hideFeatureColumns("exon", true));
     assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
-    assertTrue(alignFrame.getViewport().getColumnSelection().getHiddenColumns()
+    assertTrue(alignFrame.getViewport().getAlignment().getHiddenColumns()
+            .getHiddenRegions()
             .isEmpty());
     assertFalse(alignFrame.hideFeatureColumns("exon", false));
     assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
-    assertTrue(alignFrame.getViewport().getColumnSelection().getHiddenColumns()
+    assertTrue(alignFrame.getViewport().getAlignment().getHiddenColumns()
+            .getHiddenRegions()
             .isEmpty());
 
     /*
@@ -97,8 +99,9 @@ public class AlignFrameTest
      */
     assertFalse(alignFrame.hideFeatureColumns("Metal", true));
     assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
-    List<int[]> hidden = alignFrame.getViewport().getColumnSelection()
-            .getHiddenColumns();
+    List<int[]> hidden = alignFrame.getViewport().getAlignment()
+            .getHiddenColumns()
+            .getHiddenRegions();
     assertTrue(hidden.isEmpty());
 
     /*
@@ -107,7 +110,8 @@ public class AlignFrameTest
      * [1-3], [6-8] base zero
      */
     assertTrue(alignFrame.hideFeatureColumns("Turn", true));
-    hidden = alignFrame.getViewport().getColumnSelection().getHiddenColumns();
+    hidden = alignFrame.getViewport().getAlignment().getHiddenColumns()
+            .getHiddenRegions();
     assertEquals(hidden.size(), 2);
     assertEquals(hidden.get(0)[0], 1);
     assertEquals(hidden.get(0)[1], 3);
index 62bd0b9..6a00cde 100644 (file)
@@ -24,7 +24,7 @@ import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.gui.JvOptionPane;
 import jalview.io.AnnotationFile.ViewDef;
 
@@ -115,7 +115,7 @@ public class AnnotationFileIOTest
     try
     {
       AlignmentI al = readAlignmentFile(f);
-      ColumnSelection cs = new ColumnSelection();
+      HiddenColumns cs = new HiddenColumns();
       assertTrue(
               "Test "
                       + testname
index acde68d..2aff5cc 100644 (file)
@@ -27,7 +27,7 @@ import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceGroup;
@@ -79,7 +79,7 @@ public class JSONFileTest
 
   private HashMap<String, SequenceGroup> expectedGrps = new HashMap<String, SequenceGroup>();
 
-  private ColumnSelection expectedColSel = new ColumnSelection();
+  private HiddenColumns expectedColSel = new HiddenColumns();
 
   private SequenceI[] expectedHiddenSeqs = new SequenceI[1];
 
@@ -195,7 +195,7 @@ public class JSONFileTest
     TEST_SEQ_HEIGHT = expectedSeqs.size();
     TEST_GRP_HEIGHT = expectedGrps.size();
     TEST_ANOT_HEIGHT = expectedAnnots.size();
-    TEST_CS_HEIGHT = expectedColSel.getHiddenColumns().size();
+    TEST_CS_HEIGHT = expectedColSel.getHiddenRegions().size();
 
     exportSettings = new AlignExportSettingI()
     {
@@ -244,7 +244,7 @@ public class JSONFileTest
       jf = (JSONFile) formatAdapter.getAlignFile();
 
       AlignFrame af = new AlignFrame(alignment, jf.getHiddenSequences(),
-              jf.getColumnSelection(), AlignFrame.DEFAULT_WIDTH,
+              jf.getHiddenColumns(), AlignFrame.DEFAULT_WIDTH,
               AlignFrame.DEFAULT_HEIGHT);
       af.getViewport().setShowSequenceFeatures(jf.isShowSeqFeatures());
       String colourSchemeName = jf.getGlobalColourScheme();
@@ -313,13 +313,13 @@ public class JSONFileTest
   @Test(groups = { "Functional" })
   public void hiddenColsTest()
   {
-    ColumnSelection cs = testJsonFile.getColumnSelection();
+    HiddenColumns cs = testJsonFile.getHiddenColumns();
     Assert.assertNotNull(cs);
-    Assert.assertNotNull(cs.getHiddenColumns());
-    List<int[]> hiddenCols = cs.getHiddenColumns();
+    Assert.assertNotNull(cs.getHiddenRegions());
+    List<int[]> hiddenCols = cs.getHiddenRegions();
     Assert.assertEquals(hiddenCols.size(), TEST_CS_HEIGHT);
     Assert.assertEquals(hiddenCols.get(0), expectedColSel
-            .getHiddenColumns().get(0),
+            .getHiddenRegions().get(0),
             "Mismatched hidden columns!");
   }
 
@@ -359,7 +359,7 @@ public class JSONFileTest
       JSONFile bioJsonFile = (JSONFile) formatAdapter.getAlignFile();
       AlignFrame alignFrame = new AlignFrame(_alignment,
               bioJsonFile.getHiddenSequences(),
-              bioJsonFile.getColumnSelection(), AlignFrame.DEFAULT_WIDTH,
+              bioJsonFile.getHiddenColumns(), AlignFrame.DEFAULT_WIDTH,
               AlignFrame.DEFAULT_HEIGHT);
 
       /*
index 7ba22b4..a7e483e 100644 (file)
@@ -29,7 +29,7 @@ import jalview.api.FeatureRenderer;
 import jalview.api.SequenceRenderer;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.PDBEntry.Type;
 import jalview.datamodel.Sequence;
@@ -171,7 +171,7 @@ public class AAStructureBindingModelTest
 
       @Override
       public String superposeStructures(AlignmentI[] als, int[] alm,
-              ColumnSelection[] alc)
+              HiddenColumns[] alc)
       {
         return null;
       }
index b84e770..19c8438 100644 (file)
@@ -33,6 +33,7 @@ import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.Sequence;
@@ -300,49 +301,60 @@ public class MappingUtilsTest
     setupMappedAlignments();
 
     ColumnSelection colsel = new ColumnSelection();
+    HiddenColumns hidden = new HiddenColumns();
 
     /*
      * Column 0 in protein picks up Seq2/L, Seq3/G which map to cols 0-4 and 0-3
      * in dna respectively, overall 0-4
      */
     colsel.addElement(0);
-    ColumnSelection cs = MappingUtils.mapColumnSelection(colsel,
-            proteinView, dnaView);
+    ColumnSelection cs = new ColumnSelection();
+    HiddenColumns hs = new HiddenColumns();
+    MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
+            cs, hs);
     assertEquals("[0, 1, 2, 3, 4]", cs.getSelected().toString());
 
     /*
      * Column 1 in protein picks up Seq1/K which maps to cols 0-3 in dna
      */
+    cs.clear();
     colsel.clear();
     colsel.addElement(1);
-    cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
+    MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
+            cs, hs);
     assertEquals("[0, 1, 2, 3]", cs.getSelected().toString());
 
     /*
      * Column 2 in protein picks up gaps only - no mapping
      */
+    cs.clear();
     colsel.clear();
     colsel.addElement(2);
-    cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
+    MappingUtils.mapColumnSelection(colsel, hidden, proteinView,
+            dnaView, cs, hs);
     assertEquals("[]", cs.getSelected().toString());
 
     /*
      * Column 3 in protein picks up Seq1/P, Seq2/Q, Seq3/S which map to columns
      * 6-9, 6-10, 5-8 respectively, overall to 5-10
      */
+    cs.clear();
     colsel.clear();
     colsel.addElement(3);
-    cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
+    MappingUtils.mapColumnSelection(colsel, hidden, proteinView,
+            dnaView, cs, hs);
     assertEquals("[5, 6, 7, 8, 9, 10]", cs.getSelected().toString());
 
     /*
      * Combine selection of columns 1 and 3 to get a discontiguous mapped
      * selection
      */
+    cs.clear();
     colsel.clear();
     colsel.addElement(1);
     colsel.addElement(3);
-    cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
+    MappingUtils.mapColumnSelection(colsel, hidden, proteinView,
+            dnaView, cs, hs);
     assertEquals("[0, 1, 2, 3, 5, 6, 7, 8, 9, 10]", cs.getSelected()
             .toString());
   }
@@ -407,14 +419,17 @@ public class MappingUtilsTest
     setupMappedAlignments();
 
     ColumnSelection colsel = new ColumnSelection();
+    HiddenColumns hidden = new HiddenColumns();
 
     /*
      * Column 0 in dna picks up first bases which map to residue 1, columns 0-1
      * in protein.
      */
+    ColumnSelection cs = new ColumnSelection();
+    HiddenColumns hs = new HiddenColumns();
     colsel.addElement(0);
-    ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, dnaView,
-            proteinView);
+    MappingUtils.mapColumnSelection(colsel, hidden, dnaView, proteinView,
+            cs, hs);
     assertEquals("[0, 1]", cs.getSelected().toString());
 
     /*
@@ -424,7 +439,9 @@ public class MappingUtilsTest
     colsel.addElement(3);
     colsel.addElement(4);
     colsel.addElement(5);
-    cs = MappingUtils.mapColumnSelection(colsel, dnaView, proteinView);
+    cs.clear();
+    MappingUtils.mapColumnSelection(colsel, hidden, dnaView, proteinView,
+            cs, hs);
     assertEquals("[0, 1, 3]", cs.getSelected().toString());
   }
 
@@ -432,8 +449,10 @@ public class MappingUtilsTest
   public void testMapColumnSelection_null() throws IOException
   {
     setupMappedAlignments();
-    ColumnSelection cs = MappingUtils.mapColumnSelection(null, dnaView,
-            proteinView);
+    ColumnSelection cs = new ColumnSelection();
+    HiddenColumns hs = new HiddenColumns();
+    MappingUtils.mapColumnSelection(null, null, dnaView, proteinView, cs,
+            hs);
     assertTrue("mapped selection not empty", cs.getSelected().isEmpty());
   }
 
@@ -882,69 +901,80 @@ public class MappingUtilsTest
     setupMappedAlignments();
 
     ColumnSelection proteinSelection = new ColumnSelection();
+    HiddenColumns hiddenCols = new HiddenColumns();
 
     /*
      * Column 0 in protein picks up Seq2/L, Seq3/G which map to cols 0-4 and 0-3
      * in dna respectively, overall 0-4
      */
-    proteinSelection.hideColumns(0);
-    ColumnSelection dnaSelection = MappingUtils.mapColumnSelection(
-            proteinSelection, proteinView, dnaView);
+    proteinSelection.hideSelectedColumns(0, hiddenCols);
+    ColumnSelection dnaSelection = new ColumnSelection();
+    HiddenColumns dnaHidden = new HiddenColumns();
+    MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
+            proteinView, dnaView, dnaSelection, dnaHidden);
     assertEquals("[]", dnaSelection.getSelected().toString());
-    List<int[]> hidden = dnaSelection.getHiddenColumns();
+    List<int[]> hidden = dnaHidden.getHiddenRegions();
     assertEquals(1, hidden.size());
     assertEquals("[0, 4]", Arrays.toString(hidden.get(0)));
 
     /*
      * Column 1 in protein picks up Seq1/K which maps to cols 0-3 in dna
      */
-    proteinSelection.revealAllHiddenColumns();
+    dnaSelection = new ColumnSelection();
+    dnaHidden = new HiddenColumns();
+    hiddenCols.revealAllHiddenColumns(proteinSelection);
     // the unhidden columns are now marked selected!
     assertEquals("[0]", proteinSelection.getSelected().toString());
     // deselect these or hideColumns will be expanded to include 0
     proteinSelection.clear();
-    proteinSelection.hideColumns(1);
-    dnaSelection = MappingUtils.mapColumnSelection(proteinSelection,
-            proteinView, dnaView);
-    hidden = dnaSelection.getHiddenColumns();
+    proteinSelection.hideSelectedColumns(1, hiddenCols);
+    MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
+            proteinView, dnaView, dnaSelection, dnaHidden);
+    hidden = dnaHidden.getHiddenRegions();
     assertEquals(1, hidden.size());
     assertEquals("[0, 3]", Arrays.toString(hidden.get(0)));
 
     /*
      * Column 2 in protein picks up gaps only - no mapping
      */
-    proteinSelection.revealAllHiddenColumns();
+    dnaSelection = new ColumnSelection();
+    dnaHidden = new HiddenColumns();
+    hiddenCols.revealAllHiddenColumns(proteinSelection);
     proteinSelection.clear();
-    proteinSelection.hideColumns(2);
-    dnaSelection = MappingUtils.mapColumnSelection(proteinSelection,
-            proteinView, dnaView);
-    assertTrue(dnaSelection.getHiddenColumns().isEmpty());
+    proteinSelection.hideSelectedColumns(2, hiddenCols);
+    MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
+            proteinView, dnaView, dnaSelection, dnaHidden);
+    assertTrue(dnaHidden.getHiddenRegions().isEmpty());
 
     /*
      * Column 3 in protein picks up Seq1/P, Seq2/Q, Seq3/S which map to columns
      * 6-9, 6-10, 5-8 respectively, overall to 5-10
      */
-    proteinSelection.revealAllHiddenColumns();
+    dnaSelection = new ColumnSelection();
+    dnaHidden = new HiddenColumns();
+    hiddenCols.revealAllHiddenColumns(proteinSelection);
     proteinSelection.clear();
-    proteinSelection.hideColumns(3); // 5-10 hidden in dna
+    proteinSelection.hideSelectedColumns(3, hiddenCols); // 5-10 hidden in dna
     proteinSelection.addElement(1); // 0-3 selected in dna
-    dnaSelection = MappingUtils.mapColumnSelection(proteinSelection,
-            proteinView, dnaView);
+    MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
+            proteinView, dnaView, dnaSelection, dnaHidden);
     assertEquals("[0, 1, 2, 3]", dnaSelection.getSelected().toString());
-    hidden = dnaSelection.getHiddenColumns();
+    hidden = dnaHidden.getHiddenRegions();
     assertEquals(1, hidden.size());
     assertEquals("[5, 10]", Arrays.toString(hidden.get(0)));
 
     /*
      * Combine hiding columns 1 and 3 to get discontiguous hidden columns
      */
-    proteinSelection.revealAllHiddenColumns();
+    dnaSelection = new ColumnSelection();
+    dnaHidden = new HiddenColumns();
+    hiddenCols.revealAllHiddenColumns(proteinSelection);
     proteinSelection.clear();
-    proteinSelection.hideColumns(1);
-    proteinSelection.hideColumns(3);
-    dnaSelection = MappingUtils.mapColumnSelection(proteinSelection,
-            proteinView, dnaView);
-    hidden = dnaSelection.getHiddenColumns();
+    proteinSelection.hideSelectedColumns(1, hiddenCols);
+    proteinSelection.hideSelectedColumns(3, hiddenCols);
+    MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
+            proteinView, dnaView, dnaSelection, dnaHidden);
+    hidden = dnaHidden.getHiddenRegions();
     assertEquals(2, hidden.size());
     assertEquals("[0, 3]", Arrays.toString(hidden.get(0)));
     assertEquals("[5, 10]", Arrays.toString(hidden.get(1)));
diff --git a/test/jalview/viewmodel/OverviewDimensionsHideHiddenTest.java b/test/jalview/viewmodel/OverviewDimensionsHideHiddenTest.java
new file mode 100644 (file)
index 0000000..2bd9c47
--- /dev/null
@@ -0,0 +1,989 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.viewmodel;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.analysis.AlignmentGenerator;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceCollectionI;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+
+import java.util.Hashtable;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+@Test(singleThreaded = true)
+public class OverviewDimensionsHideHiddenTest
+{
+  AlignmentI al;
+
+  OverviewDimensionsHideHidden od;
+
+  // cached widths and heights
+  int boxWidth;
+  int boxHeight;
+  int viewHeight;
+  int viewWidth;
+  int alheight;
+  int alwidth;
+
+  ViewportRanges vpranges;
+
+  Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences = new Hashtable<SequenceI, SequenceCollectionI>();
+
+  HiddenColumns hiddenCols = new HiddenColumns();
+
+  @BeforeClass(alwaysRun = true)
+  public void setUpAlignment()
+  {
+    // create random alignment
+    AlignmentGenerator gen = new AlignmentGenerator(false);
+    al = gen.generate(157, 525, 123, 5, 5);
+  }
+
+  @BeforeMethod(alwaysRun = true)
+  public void setUp()
+  {
+    if (!hiddenRepSequences.isEmpty())
+    {
+      al.getHiddenSequences().showAll(hiddenRepSequences);
+    }
+    ColumnSelection colsel = new ColumnSelection();
+    hiddenCols.revealAllHiddenColumns(colsel);
+    
+    vpranges = new ViewportRanges(al);
+    vpranges.setStartRes(0);
+    vpranges.setEndRes(62);
+    vpranges.setStartSeq(0);
+    vpranges.setEndSeq(17);
+
+    viewHeight = vpranges.getEndSeq() - vpranges.getStartSeq() + 1;
+    viewWidth = vpranges.getEndRes() - vpranges.getStartRes() + 1;
+
+    HiddenColumns hiddenCols = new HiddenColumns();
+
+    od = new OverviewDimensionsHideHidden(vpranges, true);
+    // Initial box sizing - default path through code
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+
+    mouseClick(od, 0, 0);
+    moveViewport(0, 0);
+
+    // calculate with visible values
+    alheight = vpranges.getVisibleAlignmentHeight();
+    alwidth = vpranges.getVisibleAlignmentWidth();
+
+    boxWidth = Math.round((float) (vpranges.getEndRes()
+            - vpranges.getStartRes() + 1)
+            * od.getWidth() / alwidth);
+    boxHeight = Math.round((float) (vpranges.getEndSeq()
+            - vpranges.getStartSeq() + 1)
+            * od.getSequencesHeight() / alheight);
+  }
+
+  @AfterClass(alwaysRun = true)
+  public void cleanUp()
+  {
+    al = null;
+  }
+
+  /**
+   * Test that the OverviewDimensions constructor sets width and height
+   * correctly
+   */
+  @Test(groups = { "Functional" })
+  public void testConstructor()
+  {
+    SequenceI seqa = new Sequence("Seq1", "ABC");
+    SequenceI seqb = new Sequence("Seq2", "ABC");
+    SequenceI seqc = new Sequence("Seq3", "ABC");
+    SequenceI seqd = new Sequence("Seq4", "ABC");
+    SequenceI seqe = new Sequence("Seq5",
+            "ABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+    int defaultGraphHeight = 20;
+    int maxWidth = 400;
+    int minWidth = 120;
+    int maxSeqHeight = 300;
+    int minSeqHeight = 40;
+
+    // test for alignment with width > height
+    SequenceI[] seqs1 = new SequenceI[] { seqa, seqb };
+    Alignment al1 = new Alignment(seqs1);
+    ViewportRanges props = new ViewportRanges(al1);
+
+    OverviewDimensions od = new OverviewDimensionsHideHidden(props, true);
+    int scaledHeight = 267;
+    assertEquals(od.getGraphHeight(), defaultGraphHeight);
+    assertEquals(od.getSequencesHeight(), scaledHeight);
+    assertEquals(od.getWidth(), maxWidth);
+    assertEquals(od.getHeight(), scaledHeight + defaultGraphHeight);
+
+    // test for alignment with width < height
+    SequenceI[] seqs2 = new SequenceI[] { seqa, seqb, seqc, seqd };
+    Alignment al2 = new Alignment(seqs2);
+    props = new ViewportRanges(al2);
+
+    od = new OverviewDimensionsHideHidden(props, true);
+    int scaledWidth = 300;
+    assertEquals(od.getGraphHeight(), defaultGraphHeight);
+    assertEquals(od.getSequencesHeight(), maxSeqHeight);
+    assertEquals(od.getWidth(), scaledWidth);
+    assertEquals(od.getHeight(), scaledWidth + defaultGraphHeight);
+
+    // test for alignment with width > height and sequence height scaled below
+    // min value
+    SequenceI[] seqs3 = new SequenceI[] { seqe };
+    Alignment al3 = new Alignment(seqs3);
+    props = new ViewportRanges(al3);
+
+    od = new OverviewDimensionsHideHidden(props, true);
+    assertEquals(od.getGraphHeight(), defaultGraphHeight);
+    assertEquals(od.getSequencesHeight(), minSeqHeight);
+    assertEquals(od.getWidth(), maxWidth);
+    assertEquals(od.getHeight(), minSeqHeight + defaultGraphHeight);
+
+    // test for alignment with width < height and width scaled below min value
+    SequenceI[] seqs4 = new SequenceI[] { seqa, seqb, seqc, seqd, seqa,
+        seqb, seqc, seqd, seqa, seqb, seqc, seqd, seqa, seqb, seqc, seqd };
+    Alignment al4 = new Alignment(seqs4);
+    props = new ViewportRanges(al4);
+
+    od = new OverviewDimensionsHideHidden(props, true);
+    assertEquals(od.getGraphHeight(), defaultGraphHeight);
+    assertEquals(od.getSequencesHeight(), maxSeqHeight);
+    assertEquals(od.getWidth(), minWidth);
+    assertEquals(od.getHeight(), maxSeqHeight + defaultGraphHeight);
+
+    Alignment al5 = new Alignment(seqs4);
+    props = new ViewportRanges(al5);
+
+    od = new OverviewDimensionsHideHidden(props, false);
+    assertEquals(od.getGraphHeight(), 0);
+    assertEquals(od.getSequencesHeight(), maxSeqHeight);
+    assertEquals(od.getWidth(), minWidth);
+    assertEquals(od.getHeight(), maxSeqHeight);
+  }
+
+  /**
+   * Test that validation after mouse adjustments to boxX and boxY sets box
+   * dimensions and scroll values correctly, when there are no hidden rows or
+   * columns.
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromMouseClick()
+  {
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+
+    // negative boxX value reset to 0
+    mouseClick(od, -5, 10);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollRow(),
+            Math.round((float) 10 * alheight / od.getSequencesHeight()));
+    assertEquals(od.getScrollCol(), 0);
+
+    // negative boxY value reset to 0
+    mouseClick(od, 6, -2);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) 6 * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(), 0);
+
+    // overly large boxX value reset to width-boxWidth
+    mouseClick(od, 100, 6);
+    assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+    assertEquals(od.getBoxY(), 6);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(),
+            Math.round((float) od.getBoxY() * alheight
+                    / od.getSequencesHeight()));
+
+    // overly large boxY value reset to sequenceHeight - boxHeight
+    mouseClick(od, 10, 520);
+    assertEquals(od.getBoxX(), 10);
+    assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight());
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+
+    // here (float) od.getBoxY() * alheight / od.getSequencesHeight() = 507.5
+    // and round rounds to 508; however we get 507 working with row values
+    // hence the subtraction of 1
+    assertEquals(od.getScrollRow(),
+            Math.round((float) od.getBoxY() * alheight
+                    / od.getSequencesHeight()) - 1);
+
+    // click past end of alignment, as above
+    mouseClick(od, 3000, 5);
+    assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(),
+            Math.round((float) od.getBoxY() * alheight
+                    / od.getSequencesHeight()));
+
+    // move viewport so startRes non-zero and then mouseclick
+    moveViewportH(50);
+
+    // click at viewport position
+    int oldboxx = od.getBoxX();
+    int oldboxy = od.getBoxY();
+    mouseClick(od, od.getBoxX() + 5, od.getBoxY() + 2);
+    assertEquals(od.getBoxX(), oldboxx + 5);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+    assertEquals(od.getBoxY(), oldboxy + 2);
+    assertEquals(od.getScrollRow(),
+            Math.round((float) od.getBoxY() * alheight
+                    / od.getSequencesHeight()));
+
+    // click at top corner
+    mouseClick(od, 0, 0);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getScrollRow(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /**
+   * Test setting of the box position, when there are hidden cols at the start
+   * of the alignment
+   */
+  @Test(groups = { "Functional" })
+  public void testFromMouseWithHiddenColsAtStart()
+  {
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+
+    // hide cols at start and check updated box position is correct
+    int lastHiddenCol = 30;
+    hiddenCols.hideColumns(0, lastHiddenCol);
+
+    testBoxIsAtClickPoint(0, 0);
+
+    // click to right of hidden columns, box moves to click point
+    testBoxIsAtClickPoint(40, 0);
+    assertEquals(od.getScrollRow(), 0);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) 40 * alwidth / od.getWidth()));
+
+    // click to right of hidden columns such that box runs over right hand side
+    // of alignment
+    // box position is adjusted away from the edge
+    // overly large boxX value reset to width-boxWidth
+    int xpos = 100;
+    mouseClick(od, xpos, 0);
+    assertEquals(od.getBoxX(), Math.round(od.getWidth()) - boxWidth);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(), 0);
+  }
+
+  /**
+   * Test setting of the box position, when there are hidden cols in the middle
+   * of the alignment
+   */
+  @Test(groups = { "Functional" })
+  public void testFromMouseWithHiddenColsInMiddle()
+  {
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+    testBoxIsAtClickPoint(0, 0);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+    
+    // hide columns 63-73, no change to box position or dimensions
+    int firstHidden = 63;
+    int lastHidden = 73;
+    hiddenCols.hideColumns(firstHidden, lastHidden);
+
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+    testBoxIsAtClickPoint(0, 0);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+
+    // move box so that it overlaps with hidden cols on one side
+    // box width, boxX and scrollCol as for unhidden case
+    int xpos = 55 - boxWidth; // 55 is position in overview approx halfway
+                              // between cols 60 and 70
+    mouseClick(od, xpos, 0);
+    testBoxIsAtClickPoint(xpos, 0);
+    assertEquals(od.getScrollCol(),
+            Math.round(xpos * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(), 0);
+
+    // move box so that it completely covers hidden cols
+    // box width, boxX and scrollCol as for unhidden case
+    xpos = 33;
+    mouseClick(od, xpos, 0);
+    testBoxIsAtClickPoint(xpos, 0);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) xpos * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(), 0);
+
+    // move box so boxX is in hidden cols, box overhangs at right
+    // boxX and scrollCol at left of hidden area, box width unchanged
+    xpos = 50;
+    mouseClick(od, xpos, 0);
+    testBoxIsAtClickPoint(xpos, 0);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) xpos * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(), 0);
+
+    // move box so boxX is to right of hidden cols, but does not go beyond full
+    // width of alignment
+    // box width, boxX and scrollCol all as for non-hidden case
+    xpos = 75;
+    testBoxIsAtClickPoint(xpos, 0);
+    assertEquals(od.getScrollRow(), 0);
+    assertEquals(od.getScrollCol(),
+            Math.round(xpos * alwidth / od.getWidth()));
+    
+    // move box so it goes beyond full width of alignment
+    // boxX, scrollCol adjusted back, box width normal
+    xpos = 3000;
+    mouseClick(od, xpos, 0);
+    assertEquals(od.getBoxX(), Math.round(od.getWidth()) - boxWidth);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(), 0);
+
+  }
+
+  /**
+   * Test setting of the box position, when there are hidden cols at the end of
+   * the alignment
+   */
+  @Test(groups = { "Functional" })
+  public void testFromMouseWithHiddenColsAtEnd()
+  {
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+
+    // hide columns 140-164, no change to box position or dimensions
+    int firstHidden = 140;
+    int lastHidden = 164;
+    hiddenCols.hideColumns(firstHidden, lastHidden);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+
+    // click to left of hidden cols, without overlapping
+    // boxX, scrollCol and width as normal
+    int xpos = 5;
+    testBoxIsAtClickPoint(xpos, 0);
+    assertEquals(od.getScrollRow(), 0);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) xpos * alwidth / od.getWidth()));
+
+    // click to left of hidden cols, with overlap
+    // boxX and scrollCol adjusted for hidden cols, width normal
+    xpos = Math.round((float) 145 * od.getWidth() / alwidth) - boxWidth;
+    mouseClick(od, xpos, 0);
+    testBoxIsAtClickPoint(xpos, 0);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) xpos * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(), 0);
+
+    // click off end of alignment
+    // boxX and scrollCol adjusted backwards, width normal
+    xpos = 3000;
+    mouseClick(od, xpos, 0);
+    assertEquals(od.getBoxX(), Math.round(od.getWidth()) - boxWidth);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(),
+            Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+    assertEquals(od.getScrollRow(), 0);
+  }
+
+  /**
+   * Test that the box position is set correctly when set from the viewport,
+   * with no hidden rows or columns
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromViewport()
+  {
+    // move viewport to start of alignment
+    moveViewport(0, 0);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to right
+    moveViewportH(70);
+    assertEquals(od.getBoxX(),
+            Math.round((float) 70 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport down
+    moveViewportV(100);
+    assertEquals(od.getBoxX(),
+            Math.round((float) 70 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(),
+            Math.round(100 * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to bottom right
+    moveViewport(98, 508);
+    assertEquals(od.getBoxX(),
+            Math.round((float) 98 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(),
+            Math.round((float) 508 * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /**
+   * Test that the box position is set correctly when there are hidden columns
+   * at the start
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromViewportHiddenColsAtStart()
+  {
+    int firstHidden = 0;
+    int lastHidden = 20;
+    hiddenCols.hideColumns(firstHidden, lastHidden);
+
+    // move viewport to start of alignment
+    moveViewport(0, 0);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to end of alignment - need to make startRes by removing
+    // hidden cols because of how viewport/overview are implemented
+    moveViewport(98 - lastHidden - 1, 0);
+    assertEquals(od.getBoxX(),
+            Math.round((float) (98 - lastHidden - 1) * od.getWidth()
+                    / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /**
+   * Test that the box position is set correctly when there are hidden columns
+   * in the middle
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromViewportHiddenColsInMiddle()
+  {
+    int firstHidden = 68;
+    int lastHidden = 78;
+    hiddenCols.hideColumns(firstHidden, lastHidden);
+
+    // move viewport before hidden columns
+    moveViewport(3, 0);
+
+    assertEquals(od.getBoxX(),
+            Math.round((float) 3 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to left of hidden columns with overlap
+    moveViewport(10, 0);
+    assertEquals(od.getBoxX(),
+            Math.round((float) 10 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to straddle hidden columns
+    moveViewport(63, 0);
+    assertEquals(od.getBoxX(),
+            Math.round((float) 63 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to right of hidden columns, no overlap
+    moveViewport(80 - (lastHidden - firstHidden + 1), 0);
+    assertEquals(od.getBoxX(),
+            Math.round((float) (80 - (lastHidden - firstHidden + 1))
+                    * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+  }
+
+  /**
+   * Test that the box position is set correctly when there are hidden columns
+   * at the end
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromViewportHiddenColsAtEnd()
+  {
+    int firstHidden = 152;
+    int lastHidden = 164;
+    hiddenCols.hideColumns(firstHidden, lastHidden);
+
+    // move viewport before hidden columns
+    moveViewport(3, 0);
+    assertEquals(od.getBoxX(),
+            Math.round((float) 3 * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to hidden columns
+    // viewport can't actually extend into hidden cols,
+    // so move to the far right edge of the viewport
+    moveViewport(firstHidden - viewWidth, 0);
+    assertEquals(od.getBoxX(),
+            Math.round((float) (firstHidden - viewWidth)
+                    * od.getWidth() / alwidth));
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /**
+   * Test that the box position is set correctly when there are hidden rows at
+   * the start
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromViewportHiddenRowsAtStart()
+  {
+    int firstHidden = 0;
+    int lastHidden = 20;
+    hideSequences(firstHidden, lastHidden);
+
+    // calculate with visible values
+    alheight = vpranges.getVisibleAlignmentHeight();
+    alwidth = vpranges.getVisibleAlignmentWidth();
+
+    boxWidth = Math.round((float) (vpranges.getEndRes()
+            - vpranges.getStartRes() + 1)
+            * od.getWidth() / alwidth);
+    boxHeight = Math.round((float) (vpranges.getEndSeq()
+            - vpranges.getStartSeq() + 1)
+            * od.getSequencesHeight() / alheight);
+
+    // move viewport to start of alignment:
+    // box moves to below hidden rows, height remains same
+    moveViewport(0, 0);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to end of alignment
+    moveViewport(0, 525 - viewHeight - lastHidden - 1);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(
+            od.getBoxY(),
+            Math.round((float) (525 - viewHeight - lastHidden - 1)
+                    * od.getSequencesHeight()
+                    / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /**
+   * Test that the box position is set correctly when there are hidden rows in
+   * the middle
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromViewportHiddenRowsInMiddle()
+  {
+    int firstHidden = 200;
+    int lastHidden = 210;
+    hideSequences(firstHidden, lastHidden);
+
+    // calculate with visible values
+    alheight = vpranges.getVisibleAlignmentHeight();
+    alwidth = vpranges.getVisibleAlignmentWidth();
+
+    boxWidth = Math.round((float) (vpranges.getEndRes()
+            - vpranges.getStartRes() + 1)
+            * od.getWidth() / alwidth);
+    boxHeight = Math.round((float) (vpranges.getEndSeq()
+            - vpranges.getStartSeq() + 1)
+            * od.getSequencesHeight() / alheight);
+
+    // move viewport to start of alignment:
+    // box, height etc as in non-hidden case
+    moveViewport(0, 0);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to straddle hidden rows
+    moveViewport(0, 198);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), Math.round ((float)198 * od.getSequencesHeight()
+            / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /**
+   * Test that the box position is set correctly when there are hidden rows at
+   * the bottom
+   */
+  @Test(groups = { "Functional" })
+  public void testSetBoxFromViewportHiddenRowsAtEnd()
+  {
+    int firstHidden = 500;
+    int lastHidden = 524;
+    hideSequences(firstHidden, lastHidden);
+
+    // calculate with visible values
+    alheight = vpranges.getVisibleAlignmentHeight();
+    alwidth = vpranges.getVisibleAlignmentWidth();
+
+    boxWidth = Math.round((float) (vpranges.getEndRes()
+            - vpranges.getStartRes() + 1)
+            * od.getWidth() / alwidth);
+    boxHeight = Math.round((float) (vpranges.getEndSeq()
+            - vpranges.getStartSeq() + 1)
+            * od.getSequencesHeight() / alheight);
+
+    // move viewport to start of alignment:
+    // box, height etc as in non-hidden case
+    moveViewport(0, 0);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // move viewport to end of alignment
+    // viewport sits above hidden rows and does not include them
+    moveViewport(0, firstHidden - viewHeight - 1);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(
+            od.getBoxY(),
+            Math.round((float) (firstHidden - viewHeight - 1)
+                    * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+  }
+
+  /**
+   * Test setting of the box position, when there are hidden rows at the start
+   * of the alignment
+   */
+  @Test(groups = { "Functional" })
+  public void testFromMouseWithHiddenRowsAtStart()
+  {
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+
+    // hide rows at start and check updated box position is correct
+    int lastHiddenRow = 30;
+    hideSequences(0, lastHiddenRow);
+
+    // calculate with visible values
+    alheight = vpranges.getVisibleAlignmentHeight();
+    alwidth = vpranges.getVisibleAlignmentWidth();
+
+    boxWidth = Math.round((float) (vpranges.getEndRes()
+            - vpranges.getStartRes() + 1)
+            * od.getWidth() / alwidth);
+    boxHeight = Math.round((float) (vpranges.getEndSeq()
+            - vpranges.getStartSeq() + 1)
+            * od.getSequencesHeight() / alheight);
+
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // click below hidden rows
+    mouseClick(od, 0, 150);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 150);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /**
+   * Test setting of the box position, when there are hidden rows at the middle
+   * of the alignment
+   */
+  @Test(groups = { "Functional" })
+  public void testFromMouseWithHiddenRowsInMiddle()
+  {
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+
+    // hide rows in middle and check updated box position is correct
+    // no changes
+    int firstHiddenRow = 50;
+    int lastHiddenRow = 54;
+    hideSequences(firstHiddenRow, lastHiddenRow);
+
+    // calculate with visible values
+    alheight = vpranges.getVisibleAlignmentHeight();
+    alwidth = vpranges.getVisibleAlignmentWidth();
+
+    boxWidth = Math.round((float) (vpranges.getEndRes()
+            - vpranges.getStartRes() + 1)
+            * od.getWidth() / alwidth);
+    boxHeight = Math.round((float) (vpranges.getEndSeq()
+            - vpranges.getStartSeq() + 1)
+            * od.getSequencesHeight() / alheight);
+
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // click above hidden rows, so that box overlaps
+    int ypos = 35; // column value in residues
+    mouseClick(od, 0,
+            Math.round((float) ypos * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(),
+            Math.round((float) ypos * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // click so that box straddles hidden rows
+    ypos = 44; // column value in residues
+    mouseClick(od, 0,
+            Math.round((float) ypos * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(),
+            Math.round((float) ypos * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /**
+   * Test setting of the box position, when there are hidden rows at the end of
+   * the alignment
+   */
+  @Test(groups = { "Functional" })
+  public void testFromMouseWithHiddenRowsAtEnd()
+  {
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+    assertEquals(od.getScrollCol(), 0);
+    assertEquals(od.getScrollRow(), 0);
+
+    // hide rows at end and check updated box position is correct
+    // no changes
+    int firstHidden = 500;
+    int lastHidden = 524;
+    hideSequences(firstHidden, lastHidden);
+
+    // calculate with visible values
+    alheight = vpranges.getVisibleAlignmentHeight();
+    alwidth = vpranges.getVisibleAlignmentWidth();
+
+    boxWidth = Math.round((float) (vpranges.getEndRes()
+            - vpranges.getStartRes() + 1)
+            * od.getWidth() / alwidth);
+    boxHeight = Math.round((float) (vpranges.getEndSeq()
+            - vpranges.getStartSeq() + 1)
+            * od.getSequencesHeight() / alheight);
+
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(), 0);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // click above hidden rows
+    int ypos = 40; // row 40
+    mouseClick(od, 0,
+            Math.round((float) ypos * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(od.getBoxY(),
+            Math.round((float) ypos * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+    // click above hidden rows so box overlaps
+    // boxY, boxHeight remains same
+    ypos = 497; // row 497
+    mouseClick(od, 0,
+            Math.round((float) ypos * od.getSequencesHeight() / alheight));
+    assertEquals(od.getBoxX(), 0);
+    assertEquals(
+            od.getBoxY(),
+            Math.round((float) firstHidden * od.getSequencesHeight()
+                    / alheight)
+                    - boxHeight);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+  }
+
+  /*
+   * Move viewport horizontally: startRes + previous width gives new horizontal extent. Vertical extent stays the same.
+   */
+  private void moveViewportH(int startRes)
+  {
+    vpranges.setStartRes(startRes);
+    vpranges.setEndRes(startRes + viewWidth - 1);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+  }
+
+  /*
+   * Move viewport vertically: startSeq and endSeq give new vertical extent. Horizontal extent stays the same.
+   */
+  private void moveViewportV(int startSeq)
+  {
+    vpranges.setStartSeq(startSeq);
+    vpranges.setEndSeq(startSeq + viewHeight - 1);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+  }
+
+  /*
+   * Move viewport horizontally and vertically.
+   */
+  private void moveViewport(int startRes, int startSeq)
+  {
+    vpranges.setStartRes(startRes);
+    vpranges.setEndRes(startRes + viewWidth - 1);
+    vpranges.setStartSeq(startSeq);
+    vpranges.setEndSeq(startSeq + viewHeight - 1);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+  }
+
+  /*
+   * Mouse click as position x,y in overview window
+   */
+  private void mouseClick(OverviewDimensionsHideHidden od, int x, int y)
+  {
+    od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols);
+
+    // updates require an OverviewPanel to exist which it doesn't here
+    // so call setBoxPosition() as it would be called by the AlignmentPanel
+    // normally
+
+    vpranges.setStartRes(od.getScrollCol());
+    vpranges.setEndRes(od.getScrollCol() + viewWidth - 1);
+    vpranges.setStartSeq(od.getScrollRow());
+    vpranges.setEndSeq(od.getScrollRow() + viewHeight - 1);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+  }
+  
+  /*
+   * Test that the box is positioned with the top left corner at xpos, ypos
+   * and with the original width and height
+   */
+  private void testBoxIsAtClickPoint(int xpos, int ypos)
+  {
+    mouseClick(od, xpos, ypos);
+    assertEquals(od.getBoxX(), xpos);
+    assertEquals(od.getBoxY(), ypos);
+    assertEquals(od.getBoxWidth(), boxWidth);
+    assertEquals(od.getBoxHeight(), boxHeight);
+
+  }
+
+  /*
+   * Hide sequences between start and end
+   */
+  private void hideSequences(int start, int end)
+  {
+    SequenceI[] allseqs = al.getSequencesArray();
+    SequenceGroup theseSeqs = new SequenceGroup();
+    
+    for (int i = start; i <= end; i++)
+    {
+      theseSeqs.addSequence(allseqs[i], false);
+      al.getHiddenSequences().hideSequence(allseqs[i]);
+    }
+
+    hiddenRepSequences.put(allseqs[start], theseSeqs);
+  }
+}
@@ -26,6 +26,7 @@ import jalview.analysis.AlignmentGenerator;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceGroup;
@@ -39,10 +40,10 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 @Test(singleThreaded = true)
-public class OverviewDimensionsTest
+public class OverviewDimensionsShowHiddenTest
 {
   AlignmentI al;
-  OverviewDimensions od;
+  OverviewDimensionsShowHidden od;
 
   // cached widths and heights
   int boxWidth;
@@ -56,10 +57,10 @@ public class OverviewDimensionsTest
 
   Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences = new Hashtable<SequenceI, SequenceCollectionI>();
 
-  ColumnSelection hiddenCols = new ColumnSelection();
+  HiddenColumns hiddenCols = new HiddenColumns();
 
   @BeforeClass(alwaysRun = true)
-  public void setUpJvOptionPane()
+  public void setUpAlignment()
   {
     // create random alignment
     AlignmentGenerator gen = new AlignmentGenerator(false);
@@ -73,7 +74,8 @@ public class OverviewDimensionsTest
     {
       al.getHiddenSequences().showAll(hiddenRepSequences);
     }
-    hiddenCols.revealAllHiddenColumns();
+    ColumnSelection colsel = new ColumnSelection();
+    hiddenCols.revealAllHiddenColumns(colsel);
     
     vpranges = new ViewportRanges(al);
     vpranges.setStartRes(0);
@@ -84,11 +86,11 @@ public class OverviewDimensionsTest
     viewHeight = vpranges.getEndSeq() - vpranges.getStartSeq() + 1;
     viewWidth = vpranges.getEndRes() - vpranges.getStartRes() + 1;
 
-    ColumnSelection hiddenCols = new ColumnSelection();
+    HiddenColumns hiddenCols = new HiddenColumns();
 
-    od = new OverviewDimensions(vpranges, true);
+    od = new OverviewDimensionsShowHidden(vpranges, true);
     // Initial box sizing - default path through code
-    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
 
     mouseClick(od, 0, 0);
     moveViewport(0, 0);
@@ -136,7 +138,7 @@ public class OverviewDimensionsTest
     Alignment al1 = new Alignment(seqs1);
     ViewportRanges props = new ViewportRanges(al1);
 
-    OverviewDimensions od = new OverviewDimensions(props, true);
+    OverviewDimensions od = new OverviewDimensionsShowHidden(props, true);
     int scaledHeight = 267;
     assertEquals(od.getGraphHeight(), defaultGraphHeight);
     assertEquals(od.getSequencesHeight(), scaledHeight);
@@ -148,7 +150,7 @@ public class OverviewDimensionsTest
     Alignment al2 = new Alignment(seqs2);
     props = new ViewportRanges(al2);
 
-    od = new OverviewDimensions(props, true);
+    od = new OverviewDimensionsShowHidden(props, true);
     int scaledWidth = 300;
     assertEquals(od.getGraphHeight(), defaultGraphHeight);
     assertEquals(od.getSequencesHeight(), maxSeqHeight);
@@ -161,7 +163,7 @@ public class OverviewDimensionsTest
     Alignment al3 = new Alignment(seqs3);
     props = new ViewportRanges(al3);
 
-    od = new OverviewDimensions(props, true);
+    od = new OverviewDimensionsShowHidden(props, true);
     assertEquals(od.getGraphHeight(), defaultGraphHeight);
     assertEquals(od.getSequencesHeight(), minSeqHeight);
     assertEquals(od.getWidth(), maxWidth);
@@ -173,7 +175,7 @@ public class OverviewDimensionsTest
     Alignment al4 = new Alignment(seqs4);
     props = new ViewportRanges(al4);
 
-    od = new OverviewDimensions(props, true);
+    od = new OverviewDimensionsShowHidden(props, true);
     assertEquals(od.getGraphHeight(), defaultGraphHeight);
     assertEquals(od.getSequencesHeight(), maxSeqHeight);
     assertEquals(od.getWidth(), minWidth);
@@ -182,7 +184,7 @@ public class OverviewDimensionsTest
     Alignment al5 = new Alignment(seqs4);
     props = new ViewportRanges(al5);
 
-    od = new OverviewDimensions(props, false);
+    od = new OverviewDimensionsShowHidden(props, false);
     assertEquals(od.getGraphHeight(), 0);
     assertEquals(od.getSequencesHeight(), maxSeqHeight);
     assertEquals(od.getWidth(), minWidth);
@@ -197,8 +199,7 @@ public class OverviewDimensionsTest
   @Test(groups = { "Functional" })
   public void testSetBoxFromMouseClick()
   {
-    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
-            vpranges);
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
@@ -296,8 +297,7 @@ public class OverviewDimensionsTest
   @Test(groups = { "Functional" })
   public void testFromMouseWithHiddenColsAtStart()
   {
-    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
-            vpranges);
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
@@ -309,7 +309,7 @@ public class OverviewDimensionsTest
     int lastHiddenCol = 30;
     hiddenCols.hideColumns(0, lastHiddenCol);
 
-    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
     assertEquals(od.getBoxX(),
             Math.round((float) (lastHiddenCol + 1) * od.getWidth()
                     / alwidth));
@@ -361,8 +361,7 @@ public class OverviewDimensionsTest
   @Test(groups = { "Functional" })
   public void testFromMouseWithHiddenColsInMiddle()
   {
-    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
-            vpranges);
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
@@ -374,7 +373,7 @@ public class OverviewDimensionsTest
     int lastHidden = 73;
     hiddenCols.hideColumns(firstHidden, lastHidden);
 
-    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
@@ -463,8 +462,7 @@ public class OverviewDimensionsTest
   @Test(groups = { "Functional" })
   public void testFromMouseWithHiddenColsAtEnd()
   {
-    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
-            vpranges);
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
@@ -475,7 +473,7 @@ public class OverviewDimensionsTest
     int firstHidden = 140;
     int lastHidden = 164;
     hiddenCols.hideColumns(firstHidden, lastHidden);
-    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
@@ -618,9 +616,7 @@ public class OverviewDimensionsTest
     assertEquals(od.getBoxX(),
             Math.round((float) 3 * od.getWidth() / alwidth));
     assertEquals(od.getBoxY(), 0);
-    System.out.println(od.getBoxWidth());
     assertEquals(od.getBoxWidth(), boxWidth);
-    System.out.println(od.getBoxWidth());
     assertEquals(od.getBoxHeight(), boxHeight);
 
     // move viewport to left of hidden columns with overlap
@@ -790,8 +786,7 @@ public class OverviewDimensionsTest
   @Test(groups = { "Functional" })
   public void testFromMouseWithHiddenRowsAtStart()
   {
-    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
-            vpranges);
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxHeight(), boxHeight);
@@ -804,7 +799,7 @@ public class OverviewDimensionsTest
     int lastHiddenRow = 30;
     hideSequences(0, lastHiddenRow);
 
-    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(),
             Math.round((float) (lastHiddenRow + 1)
@@ -837,8 +832,7 @@ public class OverviewDimensionsTest
   @Test(groups = { "Functional" })
   public void testFromMouseWithHiddenRowsInMiddle()
   {
-    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
-            vpranges);
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
 
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
@@ -853,7 +847,7 @@ public class OverviewDimensionsTest
     int lastHiddenRow = 54;
     hideSequences(firstHiddenRow, lastHiddenRow);
 
-    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
 
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
@@ -896,8 +890,7 @@ public class OverviewDimensionsTest
   @Test(groups = { "Functional" })
   public void testFromMouseWithHiddenRowsAtEnd()
   {
-    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
-            vpranges);
+    od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
@@ -911,7 +904,7 @@ public class OverviewDimensionsTest
     int lastHidden = 524;
     hideSequences(firstHidden, lastHidden);
 
-    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
@@ -960,7 +953,7 @@ public class OverviewDimensionsTest
   {
     vpranges.setStartRes(startRes);
     vpranges.setEndRes(startRes + viewWidth - 1);
-    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
 
   /*
@@ -970,7 +963,7 @@ public class OverviewDimensionsTest
   {
     vpranges.setStartSeq(startSeq);
     vpranges.setEndSeq(startSeq + viewHeight - 1);
-    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
 
   /*
@@ -982,16 +975,15 @@ public class OverviewDimensionsTest
     vpranges.setEndRes(startRes + viewWidth - 1);
     vpranges.setStartSeq(startSeq);
     vpranges.setEndSeq(startSeq + viewHeight - 1);
-    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
 
   /*
    * Mouse click as position x,y in overview window
    */
-  private void mouseClick(OverviewDimensions od, int x, int y)
+  private void mouseClick(OverviewDimensionsShowHidden od, int x, int y)
   {
-    od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols,
-            vpranges);
+    od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols);
 
     // updates require an OverviewPanel to exist which it doesn't here
     // so call setBoxPosition() as it would be called by the AlignmentPanel
@@ -1001,7 +993,7 @@ public class OverviewDimensionsTest
     vpranges.setEndRes(od.getScrollCol() + viewWidth - 1);
     vpranges.setStartSeq(od.getScrollRow());
     vpranges.setEndSeq(od.getScrollRow() + viewHeight - 1);
-    od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+    od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
   
   /*