Merge branch 'features/JAL-1648_cache_user_inputs' into develop
authorJim Procter <jprocter@issues.jalview.org>
Thu, 1 Jun 2017 13:17:05 +0000 (14:17 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Thu, 1 Jun 2017 13:17:05 +0000 (14:17 +0100)
80 files changed:
.classpath
help/html/releases.html
help/html/webServices/JABAWS.html
help/html/webServices/jnet.html
help/html/webServices/jnetprediction.gif [changed mode: 0755->0644]
help/html/webServices/msaclient.html
help/html/webServices/proteinDisorder.html
help/html/whatsNew.html
lib/jabaws-min-client-2.2.0.jar [moved from lib/min-jabaws-client-2.1.0.jar with 73% similarity]
src/MCview/AppletPDBCanvas.java
src/MCview/PDBCanvas.java
src/jalview/appletgui/APopupMenu.java
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AlignViewport.java
src/jalview/appletgui/AlignmentPanel.java
src/jalview/appletgui/AnnotationPanel.java
src/jalview/appletgui/FeatureRenderer.java
src/jalview/appletgui/Finder.java
src/jalview/appletgui/IdCanvas.java
src/jalview/appletgui/IdPanel.java
src/jalview/appletgui/OverviewPanel.java
src/jalview/appletgui/ScalePanel.java
src/jalview/appletgui/SeqCanvas.java
src/jalview/appletgui/SeqPanel.java
src/jalview/appletgui/UserDefinedColours.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/HiddenSequences.java
src/jalview/datamodel/SequenceGroup.java
src/jalview/datamodel/SequenceI.java
src/jalview/ext/jmol/JalviewJmolBinding.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/AnnotationPanel.java
src/jalview/gui/AppJmol.java
src/jalview/gui/AppVarnaBinding.java
src/jalview/gui/ChimeraViewFrame.java
src/jalview/gui/Desktop.java
src/jalview/gui/IdCanvas.java
src/jalview/gui/IdPanel.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/Jalview2XML_V1.java
src/jalview/gui/OverviewPanel.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/SeqCanvas.java
src/jalview/gui/SeqPanel.java
src/jalview/gui/StructureViewerBase.java
src/jalview/io/AppletFormatAdapter.java
src/jalview/io/FileLoader.java
src/jalview/io/StructureFile.java
src/jalview/javascript/MouseOverStructureListener.java
src/jalview/structure/StructureListener.java
src/jalview/structure/StructureSelectionManager.java
src/jalview/structures/models/AAStructureBindingModel.java
src/jalview/viewmodel/AlignmentViewport.java
src/jalview/viewmodel/OverviewDimensions.java
src/jalview/viewmodel/OverviewDimensionsHideHidden.java
src/jalview/viewmodel/OverviewDimensionsShowHidden.java
src/jalview/viewmodel/ViewportListenerI.java [new file with mode: 0644]
src/jalview/viewmodel/ViewportProperties.java
src/jalview/viewmodel/ViewportRanges.java
src/jalview/ws/jws2/JPred301Client.java [deleted file]
src/jalview/ws/jws2/jabaws2/Jws2InstanceFactory.java
src/jalview/ws/utils/UrlDownloadClient.java
test/jalview/datamodel/SequenceGroupTest.java
test/jalview/ext/jmol/JmolParserTest.java
test/jalview/ext/jmol/JmolViewerTest.java
test/jalview/ext/rbvi/chimera/JalviewChimeraView.java
test/jalview/gui/AlignViewportTest.java
test/jalview/gui/SeqPanelTest.java [new file with mode: 0644]
test/jalview/gui/StructureChooserTest.java
test/jalview/io/FileLoaderTest.java [new file with mode: 0644]
test/jalview/structures/models/AAStructureBindingModelTest.java
test/jalview/viewmodel/OverviewDimensionsHideHiddenTest.java
test/jalview/viewmodel/OverviewDimensionsShowHiddenTest.java
test/jalview/viewmodel/ViewportRangesTest.java
test/jalview/ws/jabaws/JpredJabaStructExportImport.java [deleted file]
test/jalview/ws/jabaws/MinJabawsClientTests.java
test/jalview/ws/jabaws/RNAStructExportImport.java

index 8aef745..c4a2832 100644 (file)
@@ -39,7 +39,7 @@
        <classpathentry kind="lib" path="lib/jdas-1.0.4.jar"/>
        <classpathentry kind="lib" path="lib/spring-core-3.0.5.RELEASE.jar"/>
        <classpathentry kind="lib" path="lib/spring-web-3.0.5.RELEASE.jar"/>
-       <classpathentry kind="lib" path="lib/min-jabaws-client-2.1.0.jar" sourcepath="/clustengine"/>
+       <classpathentry kind="lib" path="lib/jabaws-min-client-2.2.0.jar" sourcepath="/clustengine"/>
        <classpathentry kind="lib" path="lib/json_simple-1.1.jar" sourcepath="/Users/jimp/Downloads/json_simple-1.1-all.zip"/>
        <classpathentry kind="lib" path="lib/slf4j-api-1.7.7.jar"/>
        <classpathentry kind="lib" path="lib/jsoup-1.8.1.jar"/>
index 1fe2602..1ac87af 100755 (executable)
@@ -79,6 +79,19 @@ li:before {
           <ul>
           <li><!-- JAL-2360,JAL-2371, -->More robust colours and shader model for alignments and groups</li>
           <li><!--  JAL-384 -->Custom shading schemes created via groovy scripts</li>
+          <li><!--  JAL-2491 -->linked scrolling of CDS/Protein views via Overview or sequence motif search operations</li>
+          <li><!--  JAL-2526 -->Efficiency improvements for interacting with alignment and overview windows</li>
+          <li><!-- JAL-2388 -->Hidden columns and sequences can be omitted in Overview</li>
+            <li>
+              <!-- JAL-2535 -->Posterior probability annotation from
+              Stockholm files imported as sequence associated annotation
+            </li>
+            <li>
+              <!-- JAL-2533 -->Sequence names don't include file
+              extension when importing structure files without embedded
+              names or PDB accessions
+            </li>
+            <li><!-- JAL-2547 -->Amend sequence features dialog box can be opened by double clicking gaps within sequence feature extent</li>
           </ul>
           <em>Application</em>
           <ul>
@@ -90,7 +103,7 @@ li:before {
             <li><!-- JAL-1476 -->Warning in alignment status bar when there are not enough columns to superimpose structures in Chimera</li>
           <li><!-- JAL-1596 -->Faster Chimera/Jalview communication by file-based command exchange</li>  
           <li><!-- JAL-2316, -->URLs for viewing database cross-references provided by identifiers.org and the EMBL-EBI's MIRIAM DB</li>
-          
+          <li><!-- JAL-2549 -->Updated JABAWS client to v2.2</li>
           </ul>
           <em>Experimental features</em>
           <ul>
@@ -105,7 +118,7 @@ li:before {
           <li><!--  --></li>
           </ul>
           <em>Test Suite</em>
-          <li><!--  JAL-2474 -->Added PrivelegedAccessor to test suite</li>
+          <li><!--  JAL-2474 -->Added PrivilegedAccessor to test suite</li>
           <li><!-- JAL-2326 -->Prevent or clear modal dialogs raised during tests</li>
           <li><!--  -->  
           </ul>
@@ -115,7 +128,7 @@ li:before {
             <li>
               <!-- JAL-2398, -->Fixed incorrect value in BLOSUM 62 score
               matrix - C->R should be '3'<br />Old matrix restored with
-              this one-line groovy script:<br />jalview.schemes.ResidueProperties.BLOSUM62[4][1]=3
+              this one-line groovy script:<br />jalview.analysis.scoremodels.ScoreModels.instance.BLOSUM62.@matrix[4][1]=3
             </li>
             <li>
               <!-- JAL-2397 -->Fixed Jalview's treatment of gaps in PCA
@@ -147,7 +160,8 @@ li:before {
           <li><!-- JAL-2386 -->'Apply to all groups' setting when changing colour does not apply Conservation slider value to all groups</li>
           <li><!-- JAL-2385 -->Colour threshold slider doesn't update to reflect currently selected view or group's shading thresholds</li>
           <li><!-- JAL-2373 -->Percentage identity and conservation menu items do not show a tick or allow shading to be disabled</li>
-          <li><!-- JAL-2385 -->Conservation shading or PID threshold lost when base colourscheme changed if slider not visible</li> 
+          <li><!-- JAL-2385 -->Conservation shading or PID threshold lost when base colourscheme changed if slider not visible</li>
+          <li><!-- JAL-2547 -->Sequence features shown in tooltip for gaps before start of features</li>
           </ul>
           <em>Application</em>
           <ul>
@@ -162,16 +176,25 @@ li:before {
           <li><!-- JAL-2464 -->Tree Viewer's Print Dialog doesn't get shown again after pressing 'Cancel'</li>
           <li><!--  JAL-2461 -->DAS registry not found exceptions removed from console output</li>
           <li><!--  JAL-2383 -->Above PID colour threshold not recovered when alignment view imported from project</li> 
-          
+          <li><!-- JAL-2465 -->No mappings generated between structure and sequences extracted from structure files imported via URL</li>
+            <li>
+              <!-- JAL-2520 -->Structures loaded via URL are saved in
+              Jalview Projects rather than fetched via URL again when
+              the project is loaded and the structure viewed
+            </li>
+            <li><!-- JAL-1256 -->Trackpad horizontal scroll gesture adjusts start position in wrap mode</li>
+            <li><!-- JAL-2563 -->Status bar doesn't show positions for ambiguous amino acids</li>
           </ul>
           <em>Applet</em>
           <ul>
           <li><!-- JAL-2442 -->Features not rendered as transparent on overview or linked structure view</li> 
           <li><!--  JAL-2372 -->Colour group by conservation doesn't work (since 2.8)</li>
+          <li><!-- JAL-2517 -->Hitting Cancel after applying user-defined colourscheme doesn't restore original colourscheme</li>
           </ul>
           <em>New Known Issues</em>
           <ul>
-          <li></li>
+          <li><!--  JAL-2566 -->Protein/CDS view scrolling not always in phase after a sequence motif find operation</li>
+          <li><!-- JAL-2550 -->Importing annotation file with rows containing just upper and lower case letters are interpreted as WUSS rna secondary structure symbols</li>  
           </ul>
           
           </div>
index f74e4c4..84b2b86 100644 (file)
     <strong><em>A</em></strong>nalysis <strong><em>W</em></strong>eb <strong><em>S</em></strong>ervices
     <strong>system</strong> (<strong>JABAWS</strong>)<br> Jalview
     includes a client for interacting with programmatic (SOAP) web
-    services for the <a href="http://www.compbio.dundee.ac.uk/jabaws">JABAWS</a>
-    service model, developed at the University of Dundee by Peter
-    Troshin and Geoff Barton. This is an open source system that
-    provides a framework for wrapping command line bioinformatics
+    services provided by the <a href="http://www.compbio.dundee.ac.uk/jabaws">JABAWS</a>
+    system, developed at the University of Dundee by Peter
+    Troshin, Sasha Sherstnev, Dan Barton, Fabio Madeira-Marquez, Jim Procter and Geoff Barton.
+    This is an open source system that provides a framework for wrapping command line bioinformatics
     analysis programs that enables them to be executed locally or on a
     cluster using data and analysis parameters provided by a program
     linked with the JABA engine directly or accessing it remotely <em>via</em>
     each new server.
   </p>
   <p>
-    <em>Support for accessing JABAWS servers was introduced in
-      Jalview 2.6.</em>
+    <em>JABAWS Client updated to version 2.2 in Jalview 2.10.2</em>
   </p>
   <p>
     <em>Option for adding JABAWS servers which fails validation was
       introduced from version 2.8.2 </em>
   </p>
+  <p>
+    <em>Support for accessing JABAWS servers was introduced in
+      Jalview 2.6.</em>
+  </p>
 </body>
 </html>
index 077ace6..e42a4e6 100755 (executable)
     <li>Lupas_21, Lupas_14, Lupas_28<br> <em>Coiled-coil
         predictions for the sequence. These are binary predictions for
         each location.</em></li>
-    <li>JNETSOL25,JNETSOL5,JNETSOL0<br> <em>Solvent
-        accessibility predictions - binary predictions of 25%, 5% or 0%
-        solvent accessibility.</em></li>
+    <li>Jnet Burial<br> <em>Prediction of Solvent
+        Accessibility. levels are
+        <ul>
+          <li>0 - Exposed</li>
+          <li>3 - 25% or more S.A. accessible</li>
+          <li>6 - 5% or more S.A. accessible</li>
+          <li>9 - Buried (<5% exposed)</li>
+        </ul></li>
     <li>JNetPRED<br> <em>The consensus prediction -
         helices are marked as red tubes, and sheets as dark green
         arrows.</em></li>
     <li>JNetHMM<br> <em>HMM profile based prediction -
         helices are marked as red tubes, and sheets as dark green
         arrows.</em></li>
-    <li>jpred<br> <em>Jpred prediction - helices are
-        marked as red tubes, and sheets as dark green arrows.</em></li>
     <li>JNETPSSM<br> <em>PSSM based prediction - helices
         are marked as red tubes, and sheets as dark green arrows.</em></li>
-    <li>JNETFREQ<br> <em>Amino Acid frequency based
-        prediction - helices are marked as red tubes, and sheets as dark
-        green arrows.</em></li>
     <li>JNETJURY<br> <em>A '*' in this annotation
         indicates that the JNETJURY was invoked to rationalise
         significantly different primary predictions.</em></li>
     href="../features/annotation.html#seqannots">Add reference
       annotation</a> Sequence ID popup menu option.
   </em>
-  <em>As of Jalview 2.6, the JPred service accessed accessed via the
-    'Secondary structure prediction' submenu should be considered a
+  <em>As of Jalview 2.6, the JPred service accessed accessed via
+    the 'Secondary structure prediction' submenu should be considered a
     legacy Jalview SOAP service, and will be replaced in the near future
     by a JPred4 Rest service.</em>
 
old mode 100755 (executable)
new mode 100644 (file)
index 3f827d9..006c50d
Binary files a/help/html/webServices/jnetprediction.gif and b/help/html/webServices/jnetprediction.gif differ
index 2fbbdbc..d627c66 100644 (file)
   </p>
   <p>
     <strong>Alignment programs supported by JABAWS</strong>. <br />Versions
-    shown are those bundled with JABAWS 2.01 - if you are using a
+    shown are those bundled with JABAWS 2.2 - if you are using a
     different server, check its home page to find out which versions are
     provided.
-  <ul>
-    <li><a href="http://www.clustal.org/">Clustal Omega and
-        Clustal W</a> (version 2.0.12)</li>
-    <li><a href="http://mafft.cbrc.jp/alignment/software/">Mafft</a>
-      (version 6.8.57b)</li>
-    <li><a href="http://www.drive5.com/muscle">Muscle</a> (version
-      3.8.31)</li>
-    <li><a
-      href="http://www.tcoffee.org/Projects_home_page/t_coffee_home_page.html">Tcoffee</a>
-      (version 8.99)</li>
-    <li><a href="http://probcons.stanford.edu/">Probcons</a>
-      (version 1.12)</li>
+    <ul>
+      <li><a href="http://www.clustal.org/omega">Clustal Omega</a> (version 1.2.4)</li>
+      <li><a href="http://www.clustal.org/clustal2">ClustalW</a> (version 2.1)</li>
+      <li><a href="http://align.bmr.kyushu-u.ac.jp/mafft/software/">Mafft</a> (version 7.310)</li>
+      <li><a href="http://www.drive5.com/muscle">Muscle</a> (version 3.8.31)</li>
+      <li><a href="http://www.tcoffee.org/Projects_home_page/t_coffee_home_page.html">T-coffee</a> (version 11.00.8cbe486)</li>
+      <li><a href="http://probcons.stanford.edu/">Probcons</a> (version 1.12)</li>
+      <li><a href="http://msaprobs.sourceforge.net/">MSAProbs</a> (version 0.9.7)</li>
+      <li><a href="http://sourceforge.net/projects/glprobs/">GLProbs</a> (version 0.9.7)</li>
   </ul>
   </p>
 
index 1c35bf3..a06b3a9 100644 (file)
@@ -48,7 +48,7 @@
       By Annotation</a> dialog box to colour sequences according to the
     results of predictors shown as annotation rows.
   </p>
-  <p>JABAWS 2.0 provides four disorder predictors which are
+  <p>JABAWS 2.2 provides four disorder predictors which are
     described below:</p>
   <ul>
     <li><a href="#disembl">DisEMBL</a></li>
   </p>
   <p>
     <strong><a name="iupred"></a><a
-      href="http://iupred.enzim.hu/Help.php">IUPred</a></strong><br />
+      href="http://iupred.enzim.hu/">IUPred</a></strong><br />
     IUPred employs an empirical model to estimate likely regions of
     disorder. There are three different prediction types offered, each
     using different parameters optimized for slightly different
index f5fcf18..3f949f8 100755 (executable)
     highlights are below.
   </p>
   <ul>
-    <li>
+    <li><strong>Update to JABAWS 2.2</strong><br />Jalview's
+      alignment, protein conservation analysis, and protein disorder and
+      RNA secondary structure prediction services are now provided by <a
+      href="http://www.compbio.dundee.ac.uk/jabaws">JABAWS 2.2</a>.
+      Several of the programs provided as services have been updated, so
+      their options and parameters have changed.</li>
     <li>New preferences for <a href="webServices/urllinks.html">opening
         web pages for database cross-references</a> via the UK Elixir's
       EMBL-EBI's MIRIAM database and identifiers.org services.
   <p>
     <strong><a name="experimental">Experimental Features</a></strong>
   </p>
-  <p>This release of Jalview includes a new option in the Jalview Desktop
-  that allows you to try out features that are still in development. To
-  access the features described below, please first enable the
-  <strong>Tools&#8594;Enable Experimental Features</strong> option, and then restart Jalview.
+  <p>
+    This release of Jalview includes a new option in the Jalview Desktop
+    that allows you to try out features that are still in development.
+    To access the features described below, please first enable the <strong>Tools&#8594;Enable
+      Experimental Features</strong> option, and then restart Jalview.
   </p>
   <ul>
     <li><em>Annotation transfer between Chimera and Jalview</em><br />Two
-      <a href="features/chimera.html#experimental">new entries in the Chimera viewer's Chimera menu</a> allow positional
-      annotation to be exchanged between Chimera and Jalview.
-      </li>
+      <a href="features/chimera.html#experimental">new entries in
+        the Chimera viewer's Chimera menu</a> allow positional annotation to
+      be exchanged between Chimera and Jalview.</li>
   </ul>
 </body>
 </html>
similarity index 73%
rename from lib/min-jabaws-client-2.1.0.jar
rename to lib/jabaws-min-client-2.2.0.jar
index ea5a1f4..bf1e8b1 100644 (file)
Binary files a/lib/min-jabaws-client-2.1.0.jar and b/lib/jabaws-min-client-2.2.0.jar differ
index c454203..39111c3 100644 (file)
@@ -1119,7 +1119,7 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
   // ////////////////////////////////
   // /StructureListener
   @Override
-  public String[] getPdbFile()
+  public String[] getStructureFiles()
   {
     return new String[] { pdbentry.getFile() };
   }
index ff1211a..83642cc 100644 (file)
@@ -1075,7 +1075,7 @@ public class PDBCanvas extends JPanel implements MouseListener,
   // ////////////////////////////////
   // /StructureListener
   @Override
-  public String[] getPdbFile()
+  public String[] getStructureFiles()
   {
     return new String[] { pdbentry.getFile() };
   }
index 8fd317a..77ec373 100644 (file)
@@ -65,6 +65,7 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -819,9 +820,9 @@ public class APopupMenu extends java.awt.PopupMenu implements
         return;
       }
 
-      int rsize = 0, gSize = sg.getSize();
-      SequenceI[] rseqs, seqs = new SequenceI[gSize];
-      SequenceFeature[] tfeatures, features = new SequenceFeature[gSize];
+      int gSize = sg.getSize();
+      List<SequenceI> seqs = new ArrayList<SequenceI>();
+      List<SequenceFeature> features = new ArrayList<SequenceFeature>();
 
       for (int i = 0; i < gSize; i++)
       {
@@ -829,25 +830,17 @@ public class APopupMenu extends java.awt.PopupMenu implements
         int end = sg.findEndRes(sg.getSequenceAt(i));
         if (start <= end)
         {
-          seqs[rsize] = sg.getSequenceAt(i);
-          features[rsize] = new SequenceFeature(null, null, null, start,
-                  end, "Jalview");
-          rsize++;
+          seqs.add(sg.getSequenceAt(i));
+          features.add(new SequenceFeature(null, null, null, start, end,
+                  "Jalview"));
         }
       }
-      rseqs = new SequenceI[rsize];
-      tfeatures = new SequenceFeature[rsize];
-      System.arraycopy(seqs, 0, rseqs, 0, rsize);
-      System.arraycopy(features, 0, tfeatures, 0, rsize);
-      features = tfeatures;
-      seqs = rseqs;
 
       if (ap.seqPanel.seqCanvas.getFeatureRenderer().amendFeatures(seqs,
               features, true, ap))
       {
         ap.alignFrame.sequenceFeatures.setState(true);
         ap.av.setShowSequenceFeatures(true);
-        ;
         ap.highlightSearchResults(null);
       }
     }
index f914108..2eed311 100644 (file)
@@ -601,24 +601,22 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     case KeyEvent.VK_PAGE_UP:
       if (viewport.getWrapAlignment())
       {
-        alignPanel.scrollUp(true);
+        ranges.scrollUp(true);
       }
       else
       {
-        alignPanel.setScrollValues(ranges.getStartRes(),
-                2 * ranges.getStartSeq() - ranges.getEndSeq());
+        ranges.pageUp();
       }
       break;
 
     case KeyEvent.VK_PAGE_DOWN:
       if (viewport.getWrapAlignment())
       {
-        alignPanel.scrollUp(false);
+        ranges.scrollUp(false);
       }
       else
       {
-        alignPanel
-                .setScrollValues(ranges.getStartRes(), ranges.getEndSeq());
+        ranges.pageDown();
       }
       break;
 
index 9629a5f..73cd9e9 100644 (file)
@@ -449,8 +449,9 @@ public class AlignViewport extends AlignmentViewport implements
     int seqOffset = findComplementScrollTarget(sr);
     if (!sr.isEmpty())
     {
-      complementPanel.setFollowingComplementScroll(true);
+      complementPanel.setToScrollComplementPanel(false);
       complementPanel.scrollToCentre(sr, seqOffset);
+      complementPanel.setToScrollComplementPanel(true);
     }
   }
 
index 458ed54..e402b9b 100644 (file)
@@ -28,6 +28,7 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceI;
 import jalview.structure.StructureSelectionManager;
+import jalview.viewmodel.ViewportListenerI;
 import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BorderLayout;
@@ -42,10 +43,11 @@ import java.awt.event.AdjustmentEvent;
 import java.awt.event.AdjustmentListener;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
+import java.beans.PropertyChangeEvent;
 import java.util.List;
 
 public class AlignmentPanel extends Panel implements AdjustmentListener,
-        AlignmentViewPanel
+        AlignmentViewPanel, ViewportListenerI
 {
 
   public AlignViewport av;
@@ -131,7 +133,26 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       @Override
       public void componentResized(ComponentEvent evt)
       {
-        setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
+        // reset the viewport ranges when the alignment panel is resized
+        // in particular, this initialises the end residue value when Jalview
+        // is initialised
+        if (av.getWrapAlignment())
+        {
+          int widthInRes = seqPanel.seqCanvas
+                  .getWrappedCanvasWidth(seqPanel.seqCanvas.getWidth());
+          vpRanges.setViewportWidth(widthInRes);
+        }
+        else
+        {
+          int widthInRes = seqPanel.seqCanvas.getWidth()
+                  / av.getCharWidth();
+          int heightInSeq = seqPanel.seqCanvas.getHeight()
+                  / av.getCharHeight();
+
+          vpRanges.setViewportWidth(widthInRes);
+          vpRanges.setViewportHeight(heightInSeq);
+        }
+        // setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
         if (getSize().height > 0
                 && annotationPanelHolder.getSize().height > 0)
         {
@@ -164,6 +185,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
         }
       }
     });
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   @Override
@@ -230,11 +252,6 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     annotationPanel.repaint();
     validate();
     repaint();
-
-    if (overviewPanel != null)
-    {
-      overviewPanel.updateOverviewImage();
-    }
   }
 
   public void setIdWidth(int w, int h)
@@ -390,7 +407,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       {
         int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2 - 1;
         start = Math.max(start - offset, 0);
-        end = Math.min(end + offset, seq.getEnd() - 1);
+        end = end + offset - 1;
+        // end = Math.min(end + offset, seq.getEnd() - 1);
       }
 
       if (start < 0)
@@ -509,28 +527,13 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     }
     else
     {
-      scrollToWrappedVisible(start);
-    }
-    if (redrawOverview && overviewPanel != null)
-    {
-      overviewPanel.setBoxPosition();
+      vpRanges.scrollToWrappedVisible(start);
     }
+
     paintAlignment(redrawOverview);
     return true;
   }
 
-  void scrollToWrappedVisible(int res)
-  {
-    int cwidth = seqPanel.seqCanvas
-            .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
-    if (res <= vpRanges.getStartRes()
-            || res >= (vpRanges.getStartRes() + cwidth))
-    {
-      vscroll.setValue(res / cwidth);
-      vpRanges.setStartRes(vscroll.getValue() * cwidth);
-    }
-  }
-
   public OverviewPanel getOverviewPanel()
   {
     return overviewPanel;
@@ -672,213 +675,175 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
   int vextent = 0;
 
-  // return value is true if the scroll is valid
-  public boolean scrollUp(boolean up)
+  public void setScrollValues(int xpos, int ypos)
   {
-    if (up)
+    int x = xpos;
+    int y = ypos;
+
+    if (av.getWrapAlignment())
     {
-      if (vscroll.getValue() < 1)
-      {
-        return false;
-      }
-      setScrollValues(hscroll.getValue(), vscroll.getValue() - 1);
+      setScrollingForWrappedPanel(x);
     }
     else
     {
-      if (vextent + vscroll.getValue() >= av.getAlignment().getHeight())
-      {
-        return false;
-      }
-      setScrollValues(hscroll.getValue(), vscroll.getValue() + 1);
-    }
-
-    repaint();
-    return true;
-  }
+      int width = av.getAlignment().getWidth();
+      int height = av.getAlignment().getHeight();
 
-  public boolean scrollRight(boolean right)
-  {
-    if (!right)
-    {
-      if (hscroll.getValue() < 1)
+      if (av.hasHiddenColumns())
       {
-        return false;
+        width = av.getAlignment().getHiddenColumns()
+                .findColumnPosition(width);
       }
-      setScrollValues(hscroll.getValue() - 1, vscroll.getValue());
-    }
-    else
-    {
-      if (hextent + hscroll.getValue() >= av.getAlignment().getWidth())
+      if (x < 0)
       {
-        return false;
+        x = 0;
       }
-      setScrollValues(hscroll.getValue() + 1, vscroll.getValue());
-    }
 
-    repaint();
-    return true;
-  }
-
-  public void setScrollValues(int x, int y)
-  {
-    int width = av.getAlignment().getWidth();
-    int height = av.getAlignment().getHeight();
-
-    if (av.hasHiddenColumns())
-    {
-      width = av.getAlignment().getHiddenColumns()
-              .findColumnPosition(width);
-    }
-    if (x < 0)
-    {
-      x = 0;
-    }
+      hextent = seqPanel.seqCanvas.getSize().width / av.getCharWidth();
+      vextent = seqPanel.seqCanvas.getSize().height / av.getCharHeight();
 
+      if (hextent > width)
+      {
+        hextent = width;
+      }
 
-    hextent = seqPanel.seqCanvas.getSize().width / av.getCharWidth();
-    vextent = seqPanel.seqCanvas.getSize().height / av.getCharHeight();
-
-    if (hextent > width)
-    {
-      hextent = width;
-    }
+      if (vextent > height)
+      {
+        vextent = height;
+      }
 
-    if (vextent > height)
-    {
-      vextent = height;
-    }
+      if ((hextent + x) > width)
+      {
+        System.err.println("hextent was " + hextent + " and x was " + x);
 
-    if ((hextent + x) > width)
-    {
-      // System.err.println("hextent was " + hextent + " and x was " + x);
-      //
-      x = width - hextent;
-    }
+        x = width - hextent;
+      }
 
-    if ((vextent + y) > height)
-    {
-      y = height - vextent;
-    }
+      if ((vextent + y) > height)
+      {
+        y = height - vextent;
+      }
 
-    if (y < 0)
-    {
-      y = 0;
-    }
+      if (y < 0)
+      {
+        y = 0;
+      }
 
-    if (x < 0)
-    {
-      System.err.println("x was " + x);
-      x = 0;
-    }
+      if (x < 0)
+      {
+        System.err.println("x was " + x);
+        x = 0;
+      }
 
-    vpRanges.setStartSeq(y);
-    vpRanges.setEndSeq(y + vextent);
-    vpRanges.setStartRes(x);
-    vpRanges.setEndRes((x + (seqPanel.seqCanvas.getSize().width / av
-            .getCharWidth())) - 1);
+      hscroll.setValues(x, hextent, 0, width);
+      vscroll.setValues(y, vextent, 0, height);
 
-    hscroll.setValues(x, hextent, 0, width);
-    vscroll.setValues(y, vextent, 0, height);
+      // AWT scrollbar does not fire adjustmentValueChanged for setValues
+      // so also call adjustment code!
+      adjustHorizontal(x);
+      adjustVertical(y);
 
-    if (overviewPanel != null)
-    {
-      overviewPanel.setBoxPosition();
+      sendViewPosition();
     }
-    sendViewPosition();
-
   }
 
+  /**
+   * Respond to adjustment event when horizontal or vertical scrollbar is
+   * changed
+   * 
+   * @param evt
+   *          adjustment event encoding whether apvscroll, hscroll or vscroll
+   *          changed
+   */
   @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
-    int oldX = vpRanges.getStartRes();
-    int oldY = vpRanges.getStartSeq();
-
+    // Note that this event is NOT fired by the AWT scrollbar when setValues is
+    // called. Instead manually call adjustHorizontal and adjustVertical
+    // directly.
     if (evt == null || evt.getSource() == apvscroll)
     {
       annotationPanel.setScrollOffset(apvscroll.getValue(), false);
       alabels.setScrollOffset(apvscroll.getValue(), false);
-      // annotationPanel.image=null;
-      // alabels.image=null;
-      // alabels.repaint();
-      // annotationPanel.repaint();
     }
     if (evt == null || evt.getSource() == hscroll)
     {
       int x = hscroll.getValue();
-      vpRanges.setStartRes(x);
-      vpRanges.setEndRes(x + seqPanel.seqCanvas.getSize().width
-              / av.getCharWidth() - 1);
+      adjustHorizontal(x);
     }
 
     if (evt == null || evt.getSource() == vscroll)
     {
       int offy = vscroll.getValue();
-      if (av.getWrapAlignment())
-      {
-        int rowSize = seqPanel.seqCanvas
-                .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
-        vpRanges.setStartRes(vscroll.getValue() * rowSize);
-        vpRanges.setEndRes((vscroll.getValue() + 1) * rowSize);
-      }
-      else
-      {
-        vpRanges.setStartSeq(offy);
-        vpRanges.setEndSeq(offy + seqPanel.seqCanvas.getSize().height
-                / av.getCharHeight() - 1);
-      }
+      adjustVertical(offy);
     }
 
-    if (overviewPanel != null)
+  }
+
+  private void adjustHorizontal(int x)
+  {
+    int oldX = vpRanges.getStartRes();
+    int oldwidth = vpRanges.getViewportWidth();
+    int width = seqPanel.seqCanvas.getWidth() / av.getCharWidth();
+
+    // if we're scrolling to the position we're already at, stop
+    // this prevents infinite recursion of events when the scroll/viewport
+    // ranges values are the same
+    if ((x == oldX) && (width == oldwidth))
     {
-      overviewPanel.setBoxPosition();
+      return;
     }
+    vpRanges.setViewportStartAndWidth(x, width);
 
-    int scrollX = vpRanges.getStartRes() - oldX;
-    int scrollY = vpRanges.getStartSeq() - oldY;
-
-    if (av.getWrapAlignment() || !fastPaint || av.MAC)
+    if (av.getWrapAlignment() || !fastPaint)
     {
       repaint();
     }
-    else
+    sendViewPosition();
+  }
+
+  private void adjustVertical(int offy)
+  {
+    int oldX = vpRanges.getStartRes();
+    int oldwidth = vpRanges.getViewportWidth();
+    int oldY = vpRanges.getStartSeq();
+    int oldheight = vpRanges.getViewportHeight();
+
+    if (av.getWrapAlignment())
     {
-      // Make sure we're not trying to draw a panel
-      // larger than the visible window
-      if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
+      int rowSize = seqPanel.seqCanvas
+              .getWrappedCanvasWidth(seqPanel.seqCanvas.getWidth());
+
+      // if we're scrolling to the position we're already at, stop
+      // this prevents infinite recursion of events when the scroll/viewport
+      // ranges values are the same
+      if ((offy * rowSize == oldX) && (oldwidth == rowSize))
       {
-        scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
+        return;
       }
-      else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
+      else if (offy > -1)
       {
-        scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
+        vpRanges.setViewportStartAndWidth(offy * rowSize, rowSize);
       }
+    }
+    else
+    {
+      int height = seqPanel.seqCanvas.getHeight() / av.getCharHeight();
 
-      idPanel.idCanvas.fastPaint(scrollY);
-      seqPanel.seqCanvas.fastPaint(scrollX, scrollY);
-
-      scalePanel.repaint();
-      if (av.isShowAnnotation())
+      // if we're scrolling to the position we're already at, stop
+      // this prevents infinite recursion of events when the scroll/viewport
+      // ranges values are the same
+      if ((offy == oldY) && (height == oldheight))
       {
-        annotationPanel.fastPaint(vpRanges.getStartRes() - oldX);
+        return;
       }
+      vpRanges.setViewportStartAndHeight(offy, height);
     }
-    sendViewPosition();
-
-    /*
-     * If there is one, scroll the (Protein/cDNA) complementary alignment to
-     * match, unless we are ourselves doing that.
-     */
-    if (isFollowingComplementScroll())
-    {
-      setFollowingComplementScroll(false);
-    }
-    else
+    if (av.getWrapAlignment() || !fastPaint)
     {
-      AlignmentPanel ap = getComplementPanel();
-      av.scrollComplementaryAlignment(ap);
+      repaint();
     }
-
+    sendViewPosition();
   }
 
   /**
@@ -929,7 +894,6 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
      * This is like AlignmentI.findIndex(seq) but here we are matching the
      * dataset sequence not the aligned sequence
      */
-    int sequenceIndex = 0;
     boolean matched = false;
     for (SequenceI seq : seqs)
     {
@@ -938,7 +902,6 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
         matched = true;
         break;
       }
-      sequenceIndex++;
     }
     if (!matched)
     {
@@ -949,8 +912,6 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
      * Scroll to position but centring the target residue. Also set a state flag
      * to prevent adjustmentValueChanged performing this recursively.
      */
-    setFollowingComplementScroll(true);
-    // this should be scrollToPosition(sr,verticalOffset,
     scrollToPosition(sr, seqOffset, true, true);
   }
 
@@ -1005,31 +966,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       idPanel.idCanvas.setSize(d.width, canvasHeight);
     }
 
-    if (av.getWrapAlignment())
-    {
-      int maxwidth = av.getAlignment().getWidth();
-
-      if (av.hasHiddenColumns())
-      {
-        maxwidth = av.getAlignment().getHiddenColumns()
-                .findColumnPosition(maxwidth) - 1;
-      }
-
-      int canvasWidth = seqPanel.seqCanvas
-              .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
-
-      if (canvasWidth > 0)
-      {
-        int max = maxwidth / canvasWidth;
-        vscroll.setMaximum(1 + max);
-        vscroll.setUnitIncrement(1);
-        vscroll.setVisibleAmount(1);
-      }
-    }
-    else
-    {
-      setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
-    }
+    setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
 
     seqPanel.seqCanvas.repaint();
     idPanel.idCanvas.repaint();
@@ -1045,6 +982,37 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
   }
 
+  /*
+   * Set vertical scroll bar parameters for wrapped panel
+   * @param res 
+   *    the residue to scroll to
+   */
+  private void setScrollingForWrappedPanel(int res)
+  {
+    // get the width of the alignment in residues
+    int maxwidth = av.getAlignment().getWidth();
+    if (av.hasHiddenColumns())
+    {
+      maxwidth = av.getAlignment().getHiddenColumns()
+              .findColumnPosition(maxwidth) - 1;
+    }
+
+    // get the width of the canvas in residues
+    int canvasWidth = seqPanel.seqCanvas
+            .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
+    if (canvasWidth > 0)
+    {
+      // position we want to scroll to is number of canvasWidth's to get there
+      int current = res / canvasWidth;
+
+      // max scroll position: add one because extent is 1 and scrollbar value
+      // can only be set to at most max - extent
+      int max = maxwidth / canvasWidth + 1;
+      vscroll.setUnitIncrement(1);
+      vscroll.setValues(current, 1, 0, max);
+    }
+  }
+
   protected Panel sequenceHolderPanel = new Panel();
 
   protected Scrollbar vscroll = new Scrollbar();
@@ -1069,9 +1037,9 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
   /*
    * Flag set while scrolling to follow complementary cDNA/protein scroll. When
-   * true, suppresses invoking the same method recursively.
+   * false, suppresses invoking the same method recursively.
    */
-  private boolean followingComplementScroll;
+  private boolean scrollComplementaryPanel = true;
 
   private void jbInit() throws Exception
   {
@@ -1180,14 +1148,42 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
    * 
    * @param b
    */
-  protected void setFollowingComplementScroll(boolean b)
+  protected void setToScrollComplementPanel(boolean b)
+  {
+    this.scrollComplementaryPanel = b;
+  }
+
+  /**
+   * Get whether to scroll complement panel
+   * 
+   * @return true if cDNA/protein complement panels should be scrolled
+   */
+  protected boolean isSetToScrollComplementPanel()
   {
-    this.followingComplementScroll = b;
+    return this.scrollComplementaryPanel;
   }
 
-  protected boolean isFollowingComplementScroll()
+  @Override
+  /**
+   * Property change event fired when a change is made to the viewport ranges 
+   * object associated with this alignment panel's viewport
+   */
+  public void propertyChange(PropertyChangeEvent evt)
   {
-    return this.followingComplementScroll;
+    // update this panel's scroll values based on the new viewport ranges values
+    int x = vpRanges.getStartRes();
+    int y = vpRanges.getStartSeq();
+    setScrollValues(x, y);
+
+    // now update any complementary alignment (its viewport ranges object
+    // is different so does not get automatically updated)
+    if (isSetToScrollComplementPanel())
+    {
+      setToScrollComplementPanel(false);
+      av.scrollComplementaryAlignment(getComplementPanel());
+      setToScrollComplementPanel(true);
+    }
+
   }
 
 }
index 5026ee4..c658811 100755 (executable)
@@ -29,6 +29,7 @@ import jalview.schemes.ResidueProperties;
 import jalview.util.Comparison;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.viewmodel.ViewportListenerI;
 
 import java.awt.Color;
 import java.awt.Dimension;
@@ -47,10 +48,11 @@ import java.awt.event.InputEvent;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
 
 public class AnnotationPanel extends Panel implements AwtRenderPanelI,
         AdjustmentListener, ActionListener, MouseListener,
-        MouseMotionListener
+        MouseMotionListener, ViewportListenerI
 {
   AlignViewport av;
 
@@ -122,6 +124,7 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
   {
     this.av = av;
     renderer = new AnnotationRenderer();
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   @Override
@@ -750,4 +753,15 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
       return null;
     }
   }
+
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    // Respond to viewport range changes (e.g. alignment panel was scrolled)
+    if (evt.getPropertyName().equals("startres")
+            || evt.getPropertyName().equals("endres"))
+    {
+      fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
+    }
+  }
 }
index 38ecf76..3c2715f 100644 (file)
@@ -53,6 +53,7 @@ import java.awt.event.MouseEvent;
 import java.awt.event.TextEvent;
 import java.awt.event.TextListener;
 import java.util.Hashtable;
+import java.util.List;
 
 /**
  * DOCUMENT ME!
@@ -182,8 +183,8 @@ public class FeatureRenderer extends
    * @param ap
    * @return
    */
-  boolean amendFeatures(final SequenceI[] sequences,
-          final SequenceFeature[] features, boolean create,
+  boolean amendFeatures(final List<SequenceI> sequences,
+          final List<SequenceFeature> features, boolean create,
           final AlignmentPanel ap)
   {
     final Panel bigPanel = new Panel(new BorderLayout());
@@ -223,22 +224,20 @@ public class FeatureRenderer extends
 
     // /////////////////////////////////////
     // /MULTIPLE FEATURES AT SELECTED RESIDUE
-    if (!create && features.length > 1)
+    if (!create && features.size() > 1)
     {
       panel = new Panel(new GridLayout(4, 1));
       tmp = new Panel();
       tmp.add(new Label("Select Feature: "));
       overlaps = new Choice();
-      for (int i = 0; i < features.length; i++)
+      for (SequenceFeature sf : features)
       {
-        String item = features[i].getType() + "/" + features[i].getBegin()
-                + "-" + features[i].getEnd();
-
-        if (features[i].getFeatureGroup() != null)
+        String item = sf.getType() + "/" + sf.getBegin() + "-"
+                + sf.getEnd();
+        if (sf.getFeatureGroup() != null)
         {
-          item += " (" + features[i].getFeatureGroup() + ")";
+          item += " (" + sf.getFeatureGroup() + ")";
         }
-
         overlaps.addItem(item);
       }
 
@@ -253,15 +252,16 @@ public class FeatureRenderer extends
           if (index != -1)
           {
             featureIndex = index;
-            name.setText(features[index].getType());
-            description.setText(features[index].getDescription());
-            group.setText(features[index].getFeatureGroup());
-            start.setText(features[index].getBegin() + "");
-            end.setText(features[index].getEnd() + "");
+            SequenceFeature sf = features.get(index);
+            name.setText(sf.getType());
+            description.setText(sf.getDescription());
+            group.setText(sf.getFeatureGroup());
+            start.setText(sf.getBegin() + "");
+            end.setText(sf.getEnd() + "");
 
             SearchResultsI highlight = new SearchResults();
-            highlight.addResult(sequences[0], features[index].getBegin(),
-                    features[index].getEnd());
+            highlight.addResult(sequences.get(0), sf.getBegin(),
+                    sf.getEnd());
 
             ap.seqPanel.seqCanvas.highlightSearchResults(highlight);
 
@@ -269,8 +269,8 @@ public class FeatureRenderer extends
           FeatureColourI col = getFeatureStyle(name.getText());
           if (col == null)
           {
-            Color generatedColour = ColorUtils
-                    .createColourFromName(name.getText());
+            Color generatedColour = ColorUtils.createColourFromName(name
+                    .getText());
             col = new FeatureColour(generatedColour);
           }
 
@@ -328,16 +328,17 @@ public class FeatureRenderer extends
      * if feature type has not been supplied by the caller
      * (e.g. for Amend, or create features from Find) 
      */
-    boolean useLastDefaults = features[0].getType() == null;
-    String featureType = useLastDefaults ? lastFeatureAdded : features[0]
+    SequenceFeature firstFeature = features.get(0);
+    boolean useLastDefaults = firstFeature.getType() == null;
+    String featureType = useLastDefaults ? lastFeatureAdded : firstFeature
             .getType();
     String featureGroup = useLastDefaults ? lastFeatureGroupAdded
-            : features[0].getFeatureGroup();
+            : firstFeature.getFeatureGroup();
 
     String title = create ? MessageManager
             .getString("label.create_new_sequence_features")
             : MessageManager.formatMessage("label.amend_delete_features",
-                    new String[] { sequences[0].getName() });
+                    new String[] { sequences.get(0).getName() });
 
     final JVDialog dialog = new JVDialog(ap.alignFrame, title, true, 385,
             240);
@@ -362,9 +363,9 @@ public class FeatureRenderer extends
       });
     }
 
-    start.setText(features[0].getBegin() + "");
-    end.setText(features[0].getEnd() + "");
-    description.setText(features[0].getDescription());
+    start.setText(firstFeature.getBegin() + "");
+    end.setText(firstFeature.getEnd() + "");
+    description.setText(firstFeature.getDescription());
     // lookup (or generate) the feature colour
     FeatureColourI fcol = getFeatureStyle(name.getText());
     // simply display the feature color in a box
@@ -403,7 +404,7 @@ public class FeatureRenderer extends
 
     if (!create)
     {
-      SequenceFeature sf = features[featureIndex];
+      SequenceFeature sf = features.get(featureIndex);
       if (dialog.accept)
       {
         sf.type = enteredType;
@@ -437,7 +438,7 @@ public class FeatureRenderer extends
       }
       if (deleteFeature)
       {
-        sequences[0].deleteFeature(sf);
+        sequences.get(0).deleteFeature(sf);
         // ensure Feature Settings reflects removal of feature / group
         featuresAdded();
       }
@@ -449,14 +450,14 @@ public class FeatureRenderer extends
        */
       if (dialog.accept && name.getText().length() > 0)
       {
-        for (int i = 0; i < sequences.length; i++)
+        for (int i = 0; i < sequences.size(); i++)
         {
-          features[i].type = enteredType;
-          features[i].featureGroup = group.getText().trim();
-          features[i].description = description.getText()
+          features.get(i).type = enteredType;
+          features.get(i).featureGroup = group.getText().trim();
+          features.get(i).description = description.getText()
                   .replace('\n', ' ');
-          sequences[i].addSequenceFeature(features[i]);
-          ffile.parseDescriptionHTML(features[i], false);
+          sequences.get(i).addSequenceFeature(features.get(i));
+          ffile.parseDescriptionHTML(features.get(i), false);
         }
 
         Color newColour = colourPanel.getBackground();
index a342736..f7ebab6 100644 (file)
@@ -41,6 +41,8 @@ import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Vector;
 
 public class Finder extends Panel implements ActionListener
@@ -113,20 +115,16 @@ public class Finder extends Panel implements ActionListener
 
   public void createNewGroup_actionPerformed()
   {
-    SequenceI[] seqs = new SequenceI[searchResults.getSize()];
-    SequenceFeature[] features = new SequenceFeature[searchResults
-            .getSize()];
+    List<SequenceI> seqs = new ArrayList<SequenceI>();
+    List<SequenceFeature> features = new ArrayList<SequenceFeature>();
     String searchString = textfield.getText().trim();
 
-    int i = 0;
     for (SearchResultMatchI match : searchResults.getResults())
     {
-      seqs[i] = match.getSequence().getDatasetSequence();
-
-      features[i] = new SequenceFeature(searchString,
+      seqs.add(match.getSequence().getDatasetSequence());
+      features.add(new SequenceFeature(searchString,
               "Search Results", null, match.getStart(), match.getEnd(),
-              "Search Results");
-      i++;
+ "Search Results"));
     }
 
     if (ap.seqPanel.seqCanvas.getFeatureRenderer().amendFeatures(seqs,
index db9e661..74bbcf5 100755 (executable)
@@ -21,6 +21,7 @@
 package jalview.appletgui;
 
 import jalview.datamodel.SequenceI;
+import jalview.viewmodel.ViewportListenerI;
 import jalview.viewmodel.ViewportRanges;
 
 import java.awt.Color;
@@ -28,9 +29,10 @@ import java.awt.Font;
 import java.awt.Graphics;
 import java.awt.Image;
 import java.awt.Panel;
+import java.beans.PropertyChangeEvent;
 import java.util.List;
 
-public class IdCanvas extends Panel
+public class IdCanvas extends Panel implements ViewportListenerI
 {
   protected AlignViewport av;
 
@@ -55,6 +57,7 @@ public class IdCanvas extends Panel
     setLayout(null);
     this.av = av;
     PaintRefresher.Register(this, av.getSequenceSetId());
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   public void drawIdString(Graphics gg, boolean hiddenRows, SequenceI s,
@@ -394,4 +397,15 @@ public class IdCanvas extends Panel
     }
     return false;
   }
+
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    // Respond to viewport range changes (e.g. alignment panel was scrolled)
+    if (evt.getPropertyName().equals("startseq")
+            || evt.getPropertyName().equals("endseq"))
+    {
+      fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
+    }
+  }
 }
index 4cc4a3a..66eb053 100755 (executable)
@@ -413,7 +413,7 @@ public class IdPanel extends Panel implements MouseListener,
     if (av.getRanges().getStartSeq() > index
             || av.getRanges().getEndSeq() < index)
     {
-      alignPanel.setScrollValues(av.getRanges().getStartRes(), index);
+      av.getRanges().setStartSeq(index);
     }
   }
 
@@ -441,7 +441,7 @@ public class IdPanel extends Panel implements MouseListener,
       running = true;
       while (running)
       {
-        if (alignPanel.scrollUp(up))
+        if (av.getRanges().scrollUp(up))
         {
           // scroll was ok, so add new sequence to selection
           int seq = av.getRanges().getStartSeq();
index b933d30..b3c4a37 100755 (executable)
@@ -25,6 +25,7 @@ import jalview.util.Platform;
 import jalview.viewmodel.OverviewDimensions;
 import jalview.viewmodel.OverviewDimensionsHideHidden;
 import jalview.viewmodel.OverviewDimensionsShowHidden;
+import jalview.viewmodel.ViewportListenerI;
 
 import java.awt.BorderLayout;
 import java.awt.CheckboxMenuItem;
@@ -39,9 +40,10 @@ import java.awt.event.ItemListener;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
 
 public class OverviewPanel extends Panel implements Runnable,
-        MouseMotionListener, MouseListener
+        MouseMotionListener, MouseListener, ViewportListenerI
 {
   private OverviewDimensions od;
 
@@ -69,6 +71,9 @@ public class OverviewPanel extends Panel implements Runnable,
     add(oviewCanvas, BorderLayout.CENTER);
 
     setSize(new Dimension(od.getWidth(), od.getHeight()));
+
+    av.getRanges().addPropertyChangeListener(this);
+
     addComponentListener(new ComponentAdapter()
     {
 
@@ -146,7 +151,6 @@ public class OverviewPanel extends Panel implements Runnable,
     {
       od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment()
               .getHiddenSequences(), av.getAlignment().getHiddenColumns());
-      ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
       ap.paintAlignment(false);
     }
   }
@@ -194,7 +198,7 @@ public class OverviewPanel extends Panel implements Runnable,
    * changed
    * 
    */
-  public void setBoxPosition()
+  private void setBoxPosition()
   {
     od.setBoxPosition(av.getAlignment()
 .getHiddenSequences(), av
@@ -225,6 +229,12 @@ public class OverviewPanel extends Panel implements Runnable,
     popup.show(this, e.getX(), e.getY());
   }
 
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    setBoxPosition();
+  }
+
   /*
    * Toggle overview display between showing hidden columns and hiding hidden columns
    */
index 22b4e3a..ec3e246 100755 (executable)
@@ -26,6 +26,7 @@ import jalview.datamodel.SequenceGroup;
 import jalview.renderer.ScaleRenderer;
 import jalview.renderer.ScaleRenderer.ScaleMark;
 import jalview.util.MessageManager;
+import jalview.viewmodel.ViewportListenerI;
 
 import java.awt.Color;
 import java.awt.FontMetrics;
@@ -39,10 +40,11 @@ import java.awt.event.InputEvent;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
 import java.util.List;
 
 public class ScalePanel extends Panel implements MouseMotionListener,
-        MouseListener
+        MouseListener, ViewportListenerI
 {
 
   protected int offy = 4;
@@ -72,6 +74,7 @@ public class ScalePanel extends Panel implements MouseMotionListener,
     addMouseListener(this);
     addMouseMotionListener(this);
 
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   @Override
@@ -466,4 +469,11 @@ public class ScalePanel extends Panel implements MouseMotionListener,
     }
   }
 
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    // Respond to viewport change events (e.g. alignment panel was scrolled)
+    repaint();
+  }
+
 }
index 39382c5..46a908e 100755 (executable)
@@ -28,6 +28,7 @@ import jalview.datamodel.SequenceI;
 import jalview.renderer.ScaleRenderer;
 import jalview.renderer.ScaleRenderer.ScaleMark;
 import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportListenerI;
 import jalview.viewmodel.ViewportRanges;
 
 import java.awt.Color;
@@ -35,8 +36,9 @@ import java.awt.FontMetrics;
 import java.awt.Graphics;
 import java.awt.Image;
 import java.awt.Panel;
+import java.beans.PropertyChangeEvent;
 
-public class SeqCanvas extends Panel
+public class SeqCanvas extends Panel implements ViewportListenerI
 {
   FeatureRenderer fr;
 
@@ -65,6 +67,8 @@ public class SeqCanvas extends Panel
     sr = new SequenceRenderer(av);
     PaintRefresher.Register(this, av.getSequenceSetId());
     updateViewport();
+
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   int avcharHeight = 0, avcharWidth = 0;
@@ -436,7 +440,7 @@ public class SeqCanvas extends Panel
 
     av.setWrappedWidth(cWidth);
 
-    av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth);
+    av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth - 1);
 
     int endx;
     int ypos = hgap;
@@ -866,4 +870,35 @@ public class SeqCanvas extends Panel
     repaint();
   }
 
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    if (!av.getWrapAlignment())
+    {
+      if (evt.getPropertyName().equals("startres")
+              || evt.getPropertyName().equals("endres"))
+      {
+        // Make sure we're not trying to draw a panel
+        // larger than the visible window
+        ViewportRanges vpRanges = av.getRanges();
+        int scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
+        if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
+        {
+          scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
+        }
+        else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
+        {
+          scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
+        }
+        fastPaint(scrollX, 0);
+      }
+      else if (evt.getPropertyName().equals("startseq")
+              || evt.getPropertyName().equals("endseq"))
+      {
+        fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
+      }
+    }
+
+  }
+
 }
index d46cc34..4aa205e 100644 (file)
@@ -39,6 +39,7 @@ import jalview.structure.SelectionSource;
 import jalview.structure.SequenceListener;
 import jalview.structure.StructureSelectionManager;
 import jalview.structure.VamsasSource;
+import jalview.util.Comparison;
 import jalview.util.MappingUtils;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
@@ -53,6 +54,10 @@ import java.awt.event.InputEvent;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
 import java.util.Vector;
 
 public class SeqPanel extends Panel implements MouseMotionListener,
@@ -227,7 +232,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     endEditing();
     if (av.getWrapAlignment())
     {
-      ap.scrollToWrappedVisible(seqCanvas.cursorX);
+      av.getRanges().scrollToWrappedVisible(seqCanvas.cursorX);
     }
     else
     {
@@ -235,17 +240,17 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       HiddenColumns hidden = av.getAlignment().getHiddenColumns();
       while (seqCanvas.cursorY < ranges.getStartSeq())
       {
-        ap.scrollUp(true);
+        ranges.scrollUp(true);
       }
       while (seqCanvas.cursorY > ranges.getEndSeq())
       {
-        ap.scrollUp(false);
+        ranges.scrollUp(false);
       }
       while (seqCanvas.cursorX < hidden.adjustForHiddenColumns(ranges
               .getStartRes()))
       {
 
-        if (!ap.scrollRight(false))
+        if (!ranges.scrollRight(false))
         {
           break;
         }
@@ -253,7 +258,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       while (seqCanvas.cursorX > hidden.adjustForHiddenColumns(ranges
               .getEndRes()))
       {
-        if (!ap.scrollRight(true))
+        if (!ranges.scrollRight(true))
         {
           break;
         }
@@ -412,13 +417,13 @@ public class SeqPanel extends Panel implements MouseMotionListener,
    * 
    * @param sequence
    *          aligned sequence object
-   * @param res
+   * @param column
    *          alignment column
    * @param seq
    *          index of sequence in alignment
-   * @return position of res in sequence
+   * @return position of column in sequence or -1 if at gap
    */
-  void setStatusMessage(SequenceI sequence, int res, int seq)
+  void setStatusMessage(SequenceI sequence, int column, int seq)
   {
     // TODO remove duplication of identical gui method
     StringBuilder text = new StringBuilder(32);
@@ -429,7 +434,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     /*
      * Try to translate the display character to residue name (null for gap).
      */
-    final String displayChar = String.valueOf(sequence.getCharAt(res));
+    final String displayChar = String.valueOf(sequence.getCharAt(column));
     if (av.getAlignment().isNucleotide())
     {
       residue = ResidueProperties.nucleotideName.get(displayChar);
@@ -452,7 +457,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     int pos = -1;
     if (residue != null)
     {
-      pos = sequence.findPosition(res);
+      pos = sequence.findPosition(column);
       text.append(" (").append(Integer.toString(pos)).append(")");
     }
 
@@ -562,20 +567,23 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         av.setSelectionGroup(null);
       }
 
-      SequenceFeature[] features = findFeaturesAtRes(sequence,
-              sequence.findPosition(findRes(evt)));
+      int column = findRes(evt);
+      boolean isGapped = Comparison.isGap(sequence.getCharAt(column));
+      List<SequenceFeature> features = findFeaturesAtRes(sequence,
+              sequence.findPosition(column));
+      if (isGapped)
+      {
+        removeAdjacentFeatures(features, column + 1, sequence);
+      }
 
-      if (features != null && features.length > 0)
+      if (!features.isEmpty())
       {
         SearchResultsI highlight = new SearchResults();
-        highlight.addResult(sequence, features[0].getBegin(),
-                features[0].getEnd());
+        highlight.addResult(sequence, features.get(0).getBegin(), features
+                .get(0).getEnd());
         seqCanvas.highlightSearchResults(highlight);
-      }
-      if (features != null && features.length > 0)
-      {
         seqCanvas.getFeatureRenderer().amendFeatures(
-                new SequenceI[] { sequence }, features, false, ap);
+                Collections.singletonList(sequence), features, false, ap);
 
         seqCanvas.highlightSearchResults(null);
       }
@@ -585,13 +593,13 @@ public class SeqPanel extends Panel implements MouseMotionListener,
   @Override
   public void mouseReleased(MouseEvent evt)
   {
+    boolean didDrag = mouseDragging; // did we come here after a drag
     mouseDragging = false;
     mouseWheelPressed = false;
-    ap.paintAlignment(true);
 
     if (!editingSeqs)
     {
-      doMouseReleasedDefineMode(evt);
+      doMouseReleasedDefineMode(evt, didDrag);
       return;
     }
 
@@ -746,10 +754,16 @@ public class SeqPanel extends Panel implements MouseMotionListener,
   {
     if (av.isFollowHighlight())
     {
+      // don't allow highlight of protein/cDNA to also scroll a complementary
+      // panel,as this sets up a feedback loop (scrolling panel 1 causes moused
+      // over residue to change abruptly, causing highlighted residue in panel 2
+      // to change, causing a scroll in panel 1 etc)
+      ap.setToScrollComplementPanel(false);
       if (ap.scrollToPosition(results, true))
       {
         ap.alignFrame.repaint();
       }
+      ap.setToScrollComplementPanel(true);
     }
     setStatusMessage(results);
     seqCanvas.highlightSearchResults(results);
@@ -772,10 +786,10 @@ public class SeqPanel extends Panel implements MouseMotionListener,
   @Override
   public void mouseMoved(MouseEvent evt)
   {
-    int res = findRes(evt);
+    final int column = findRes(evt);
     int seq = findSeq(evt);
 
-    if (seq >= av.getAlignment().getHeight() || seq < 0 || res < 0)
+    if (seq >= av.getAlignment().getHeight() || seq < 0 || column < 0)
     {
       if (tooltip != null)
       {
@@ -785,7 +799,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     }
 
     SequenceI sequence = av.getAlignment().getSequenceAt(seq);
-    if (res > sequence.getLength())
+    if (column > sequence.getLength())
     {
       if (tooltip != null)
       {
@@ -794,38 +808,34 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       return;
     }
 
-    int respos = sequence.findPosition(res);
-    if (ssm != null)
+    final char ch = sequence.getCharAt(column);
+    boolean isGapped = Comparison.isGap(ch);
+    // find residue at column (or nearest if at a gap)
+    int respos = sequence.findPosition(column);
+
+    if (ssm != null && !isGapped)
     {
-      mouseOverSequence(sequence, res, respos);
+      mouseOverSequence(sequence, column, respos);
     }
 
     StringBuilder text = new StringBuilder();
     text.append("Sequence ").append(Integer.toString(seq + 1))
             .append(" ID: ").append(sequence.getName());
 
-    String obj = null;
-    final String ch = String.valueOf(sequence.getCharAt(res));
-    if (av.getAlignment().isNucleotide())
+    if (!isGapped)
     {
-      obj = ResidueProperties.nucleotideName.get(ch);
-      if (obj != null)
+      if (av.getAlignment().isNucleotide())
       {
-        text.append(" Nucleotide: ").append(obj);
+        String base = ResidueProperties.nucleotideName.get(ch);
+        text.append(" Nucleotide: ").append(base == null ? ch : base);
       }
-    }
-    else
-    {
-      obj = "X".equalsIgnoreCase(ch) ? "X" : ResidueProperties.aa2Triplet
-              .get(ch);
-      if (obj != null)
+      else
       {
-        text.append(" Residue: ").append(obj);
+        String residue = (ch == 'x' || ch == 'X') ? "X"
+                : ResidueProperties.aa2Triplet
+                .get(String.valueOf(ch));
+        text.append(" Residue: ").append(residue == null ? ch : residue);
       }
-    }
-
-    if (obj != null)
-    {
       text.append(" (").append(Integer.toString(respos)).append(")");
     }
 
@@ -837,7 +847,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     {
       for (int g = 0; g < groups.length; g++)
       {
-        if (groups[g].getStartRes() <= res && groups[g].getEndRes() >= res)
+        if (groups[g].getStartRes() <= column && groups[g].getEndRes() >= column)
         {
           if (!groups[g].getName().startsWith("JTreeGroup")
                   && !groups[g].getName().startsWith("JGroup"))
@@ -853,33 +863,37 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       }
     }
 
-    // use aa to see if the mouse pointer is on a
-    SequenceFeature[] allFeatures = findFeaturesAtRes(sequence,
-            sequence.findPosition(res));
-
-    int index = 0;
-    while (index < allFeatures.length)
+    /*
+     * add feature details to tooltip, including any that straddle
+     * a gapped position
+     */
+    if (av.isShowSequenceFeatures())
     {
-      SequenceFeature sf = allFeatures[index];
-
-      tooltipText.append(sf.getType() + " " + sf.begin + ":" + sf.end);
-
-      if (sf.getDescription() != null)
+      List<SequenceFeature> allFeatures = findFeaturesAtRes(sequence,
+              sequence.findPosition(column));
+      if (isGapped)
       {
-        tooltipText.append(" " + sf.getDescription());
+        removeAdjacentFeatures(allFeatures, column + 1, sequence);
       }
-
-      if (sf.getValue("status") != null)
+      for (SequenceFeature sf : allFeatures)
       {
-        String status = sf.getValue("status").toString();
-        if (status.length() > 0)
+        tooltipText.append(sf.getType() + " " + sf.begin + ":" + sf.end);
+
+        if (sf.getDescription() != null)
         {
-          tooltipText.append(" (" + sf.getValue("status") + ")");
+          tooltipText.append(" " + sf.getDescription());
         }
-      }
-      tooltipText.append("\n");
 
-      index++;
+        if (sf.getValue("status") != null)
+        {
+          String status = sf.getValue("status").toString();
+          if (status.length() > 0)
+          {
+            tooltipText.append(" (" + sf.getValue("status") + ")");
+          }
+        }
+        tooltipText.append("\n");
+      }
     }
 
     if (tooltip == null)
@@ -892,9 +906,38 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     }
   }
 
-  SequenceFeature[] findFeaturesAtRes(SequenceI sequence, int res)
+  /**
+   * Removes from the list of features any that start after, or end before, the
+   * given column position. This allows us to retain only those features
+   * adjacent to a gapped position that straddle the position. Contact features
+   * that 'straddle' the position are also removed, since they are not 'at' the
+   * position.
+   * 
+   * @param features
+   * @param column
+   *          alignment column (1..)
+   * @param sequence
+   */
+  protected void removeAdjacentFeatures(List<SequenceFeature> features,
+          int column, SequenceI sequence)
   {
-    Vector tmp = new Vector();
+    // TODO should this be an AlignViewController method (shared by gui)?
+    ListIterator<SequenceFeature> it = features.listIterator();
+    while (it.hasNext())
+    {
+      SequenceFeature sf = it.next();
+      if (sf.isContactFeature()
+              || sequence.findIndex(sf.getBegin()) > column
+              || sequence.findIndex(sf.getEnd()) < column)
+      {
+        it.remove();
+      }
+    }
+  }
+
+  List<SequenceFeature> findFeaturesAtRes(SequenceI sequence, int res)
+  {
+    List<SequenceFeature> result = new ArrayList<SequenceFeature>();
     SequenceFeature[] features = sequence.getSequenceFeatures();
     if (features != null)
     {
@@ -917,15 +960,12 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         if ((features[i].getBegin() <= res)
                 && (features[i].getEnd() >= res))
         {
-          tmp.addElement(features[i]);
+          result.add(features[i]);
         }
       }
     }
 
-    features = new SequenceFeature[tmp.size()];
-    tmp.copyInto(features);
-
-    return features;
+    return result;
   }
 
   Tooltip tooltip;
@@ -1451,24 +1491,21 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     // DETECT RIGHT MOUSE BUTTON IN AWT
     if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
     {
-      SequenceFeature[] allFeatures = findFeaturesAtRes(sequence,
+      List<SequenceFeature> allFeatures = findFeaturesAtRes(sequence,
               sequence.findPosition(res));
 
       Vector<String> links = null;
-      if (allFeatures != null)
+      for (SequenceFeature sf : allFeatures)
       {
-        for (int i = 0; i < allFeatures.length; i++)
+        if (sf.links != null)
         {
-          if (allFeatures[i].links != null)
+          if (links == null)
           {
-            if (links == null)
-            {
-              links = new Vector<String>();
-            }
-            for (int j = 0; j < allFeatures[i].links.size(); j++)
-            {
-              links.addElement(allFeatures[i].links.elementAt(j));
-            }
+            links = new Vector<String>();
+          }
+          for (int j = 0; j < sf.links.size(); j++)
+          {
+            links.addElement(sf.links.elementAt(j));
           }
         }
       }
@@ -1512,7 +1549,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     }
   }
 
-  public void doMouseReleasedDefineMode(MouseEvent evt)
+  public void doMouseReleasedDefineMode(MouseEvent evt, boolean afterDrag)
   {
     if (stretchGroup == null)
     {
@@ -1522,7 +1559,8 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     // but defer colourscheme update until hidden sequences are passed in
     boolean vischange = stretchGroup.recalcConservation(true);
     // here we rely on stretchGroup == av.getSelection()
-    needOverviewUpdate |= vischange && av.isSelectionDefinedGroup();
+    needOverviewUpdate |= vischange && av.isSelectionDefinedGroup()
+            && afterDrag;
     if (stretchGroup.cs != null)
     {
       stretchGroup.cs.alignmentChanged(stretchGroup,
@@ -1761,24 +1799,24 @@ public class SeqPanel extends Panel implements MouseMotionListener,
           if (mouseDragging && evt.getY() < 0
                   && av.getRanges().getStartSeq() > 0)
           {
-            running = ap.scrollUp(true);
+            running = av.getRanges().scrollUp(true);
           }
 
           if (mouseDragging && evt.getY() >= getSize().height
                   && av.getAlignment().getHeight() > av.getRanges()
                           .getEndSeq())
           {
-            running = ap.scrollUp(false);
+            running = av.getRanges().scrollUp(false);
           }
 
           if (mouseDragging && evt.getX() < 0)
           {
-            running = ap.scrollRight(false);
+            running = av.getRanges().scrollRight(false);
           }
 
           else if (mouseDragging && evt.getX() >= getSize().width)
           {
-            running = ap.scrollRight(true);
+            running = av.getRanges().scrollRight(true);
           }
         }
 
index 95e36b5..845110e 100644 (file)
  */
 package jalview.appletgui;
 
+import jalview.analysis.AAFrequency;
 import jalview.api.FeatureColourI;
 import jalview.datamodel.SequenceGroup;
 import jalview.renderer.ResidueShader;
+import jalview.schemes.Blosum62ColourScheme;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.FeatureColour;
+import jalview.schemes.PIDColourScheme;
 import jalview.schemes.ResidueProperties;
 import jalview.schemes.UserColourScheme;
 import jalview.util.MessageManager;
@@ -579,35 +582,25 @@ public class UserDefinedColours extends Panel implements ActionListener,
       return;
     }
 
-    Color[] newColours = new Color[24];
-    for (int i = 0; i < 24; i++)
-    {
-      newColours[i] = oldColours.elementAt(i);
-      buttonPanel.getComponent(i).setBackground(newColours[i]);
-    }
-
-    UserColourScheme ucs = new UserColourScheme(newColours);
-
     if (ap != null)
     {
       if (seqGroup != null)
       {
-        seqGroup.cs = new ResidueShader(ucs);
+        seqGroup.cs = new ResidueShader(oldColourScheme);
+        if (oldColourScheme instanceof PIDColourScheme
+                || oldColourScheme instanceof Blosum62ColourScheme)
+        {
+          seqGroup.cs.setConsensus(AAFrequency.calculate(
+                  seqGroup.getSequences(ap.av.getHiddenRepSequences()), 0,
+                  ap.av.getAlignment().getWidth()));
+        }
       }
       else
       {
-        ap.av.setGlobalColourScheme(ucs);
+        ap.av.setGlobalColourScheme(oldColourScheme);
       }
       ap.paintAlignment(true);
     }
-    else if (jmol != null)
-    {
-      jmol.setJalviewColourScheme(ucs);
-    }
-    else if (pdbcanvas != null)
-    {
-      pdbcanvas.pdb.setColours(ucs);
-    }
 
     frame.setVisible(false);
   }
index fcb6109..5d91b36 100755 (executable)
@@ -73,7 +73,7 @@ public class Alignment implements AlignmentI
     groups = Collections.synchronizedList(new ArrayList<SequenceGroup>());
     hiddenSequences = new HiddenSequences(this);
     hiddenCols = new HiddenColumns();
-    codonFrameList = new ArrayList<AlignedCodonFrame>();
+    codonFrameList = new ArrayList<>();
 
     nucleotide = Comparison.isNucleotide(seqs);
 
@@ -405,7 +405,7 @@ public class Alignment implements AlignmentI
   @Override
   public SequenceGroup[] findAllGroups(SequenceI s)
   {
-    ArrayList<SequenceGroup> temp = new ArrayList<SequenceGroup>();
+    ArrayList<SequenceGroup> temp = new ArrayList<>();
 
     synchronized (groups)
     {
@@ -456,7 +456,7 @@ public class Alignment implements AlignmentI
             return;
           }
         }
-        sg.setContext(this);
+        sg.setContext(this, true);
         groups.add(sg);
       }
     }
@@ -533,7 +533,7 @@ public class Alignment implements AlignmentI
       }
       for (SequenceGroup sg : groups)
       {
-        sg.setContext(null);
+        sg.setContext(null, false);
       }
       groups.clear();
     }
@@ -549,7 +549,7 @@ public class Alignment implements AlignmentI
       {
         removeAnnotationForGroup(g);
         groups.remove(g);
-        g.setContext(null);
+        g.setContext(null, false);
       }
     }
   }
@@ -1071,7 +1071,7 @@ public class Alignment implements AlignmentI
     {
       return;
     }
-    List<SequenceI> toProcess = new ArrayList<SequenceI>();
+    List<SequenceI> toProcess = new ArrayList<>();
     toProcess.add(currentSeq);
     while (toProcess.size() > 0)
     {
@@ -1124,7 +1124,7 @@ public class Alignment implements AlignmentI
       return;
     }
     // try to avoid using SequenceI.equals at this stage, it will be expensive
-    Set<SequenceI> seqs = new LinkedIdentityHashSet<SequenceI>();
+    Set<SequenceI> seqs = new LinkedIdentityHashSet<>();
 
     for (int i = 0; i < getHeight(); i++)
     {
@@ -1409,7 +1409,7 @@ public class Alignment implements AlignmentI
     {
       return null;
     }
-    List<AlignedCodonFrame> cframes = new ArrayList<AlignedCodonFrame>();
+    List<AlignedCodonFrame> cframes = new ArrayList<>();
     for (AlignedCodonFrame acf : getCodonFrames())
     {
       if (acf.involvesSequence(seq))
@@ -1486,7 +1486,7 @@ public class Alignment implements AlignmentI
     if (sqs != null)
     {
       // avoid self append deadlock by
-      List<SequenceI> toappendsq = new ArrayList<SequenceI>();
+      List<SequenceI> toappendsq = new ArrayList<>();
       synchronized (sqs)
       {
         for (SequenceI addedsq : sqs)
@@ -1627,7 +1627,7 @@ public class Alignment implements AlignmentI
   @Override
   public Iterable<AlignmentAnnotation> findAnnotation(String calcId)
   {
-    List<AlignmentAnnotation> aa = new ArrayList<AlignmentAnnotation>();
+    List<AlignmentAnnotation> aa = new ArrayList<>();
     AlignmentAnnotation[] alignmentAnnotation = getAlignmentAnnotation();
     if (alignmentAnnotation != null)
     {
@@ -1648,7 +1648,7 @@ public class Alignment implements AlignmentI
   public Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq,
           String calcId, String label)
   {
-    ArrayList<AlignmentAnnotation> aa = new ArrayList<AlignmentAnnotation>();
+    ArrayList<AlignmentAnnotation> aa = new ArrayList<>();
     for (AlignmentAnnotation ann : getAlignmentAnnotation())
     {
       if ((calcId == null || (ann.getCalcId() != null && ann.getCalcId()
@@ -1853,7 +1853,7 @@ public class Alignment implements AlignmentI
   @Override
   public Set<String> getSequenceNames()
   {
-    Set<String> names = new HashSet<String>();
+    Set<String> names = new HashSet<>();
     for (SequenceI seq : getSequences())
     {
       names.add(seq.getName());
index 1daaf43..a98b10e 100755 (executable)
@@ -170,7 +170,13 @@ public class HiddenSequences
   public List<SequenceI> showAll(
           Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
   {
-    List<SequenceI> revealedSeqs = new ArrayList<SequenceI>();
+    List<SequenceI> revealedSeqs = new ArrayList<>();
+
+    if (hiddenSequences == null)
+    {
+      return revealedSeqs;
+    }
+
     for (int i = 0; i < hiddenSequences.length; i++)
     {
       if (hiddenSequences[i] != null)
@@ -199,7 +205,7 @@ public class HiddenSequences
   public List<SequenceI> showSequence(int alignmentIndex,
           Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
   {
-    List<SequenceI> revealedSeqs = new ArrayList<SequenceI>();
+    List<SequenceI> revealedSeqs = new ArrayList<>();
     SequenceI repSequence = alignment.getSequenceAt(alignmentIndex);
     if (repSequence != null && hiddenRepSequences != null
             && hiddenRepSequences.containsKey(repSequence))
index 76ad093..463b909 100755 (executable)
@@ -52,6 +52,12 @@ public class SequenceGroup implements AnnotatedCollectionI
   boolean colourText = false;
 
   /**
+   * True if the group is defined as a group on the alignment, false if it is
+   * just a selection.
+   */
+  boolean isDefined = false;
+
+  /**
    * after Olivier's non-conserved only character display
    */
   boolean showNonconserved = false;
@@ -59,7 +65,7 @@ public class SequenceGroup implements AnnotatedCollectionI
   /**
    * group members
    */
-  private List<SequenceI> sequences = new ArrayList<SequenceI>();
+  private List<SequenceI> sequences = new ArrayList<>();
 
   /**
    * representative sequence for this group (if any)
@@ -104,13 +110,23 @@ public class SequenceGroup implements AnnotatedCollectionI
    */
   private boolean normaliseSequenceLogo;
 
-  /**
-   * @return the includeAllConsSymbols
+  /*
+   * visibility of rows or represented rows covered by group
    */
-  public boolean isShowSequenceLogo()
-  {
-    return showSequenceLogo;
-  }
+  private boolean hidereps = false;
+
+  /*
+   * visibility of columns intersecting this group
+   */
+  private boolean hidecols = false;
+
+  AlignmentAnnotation consensus = null;
+
+  AlignmentAnnotation conservation = null;
+
+  private boolean showConsensusHistogram;
+
+  private AnnotatedCollectionI context;
 
   /**
    * Creates a new SequenceGroup object.
@@ -161,7 +177,7 @@ public class SequenceGroup implements AnnotatedCollectionI
     this();
     if (seqsel != null)
     {
-      sequences = new ArrayList<SequenceI>();
+      sequences = new ArrayList<>();
       sequences.addAll(seqsel.sequences);
       if (seqsel.groupName != null)
       {
@@ -172,13 +188,17 @@ public class SequenceGroup implements AnnotatedCollectionI
       colourText = seqsel.colourText;
       startRes = seqsel.startRes;
       endRes = seqsel.endRes;
-      cs = seqsel.cs;
+      cs = new ResidueShader(seqsel.getColourScheme());
       if (seqsel.description != null)
       {
         description = new String(seqsel.description);
       }
       hidecols = seqsel.hidecols;
       hidereps = seqsel.hidereps;
+      showNonconserved = seqsel.showNonconserved;
+      showSequenceLogo = seqsel.showSequenceLogo;
+      normaliseSequenceLogo = seqsel.normaliseSequenceLogo;
+      showConsensusHistogram = seqsel.showConsensusHistogram;
       idColour = seqsel.idColour;
       outlineColour = seqsel.outlineColour;
       seqrep = seqsel.seqrep;
@@ -195,6 +215,11 @@ public class SequenceGroup implements AnnotatedCollectionI
     }
   }
 
+  public boolean isShowSequenceLogo()
+  {
+    return showSequenceLogo;
+  }
+
   public SequenceI[] getSelectionAsNewSequences(AlignmentI align)
   {
     int iSize = sequences.size();
@@ -311,7 +336,7 @@ public class SequenceGroup implements AnnotatedCollectionI
     }
     else
     {
-      List<SequenceI> allSequences = new ArrayList<SequenceI>();
+      List<SequenceI> allSequences = new ArrayList<>();
       for (SequenceI seq : sequences)
       {
         allSequences.add(seq);
@@ -951,11 +976,6 @@ public class SequenceGroup implements AnnotatedCollectionI
   }
 
   /**
-   * visibility of rows or represented rows covered by group
-   */
-  private boolean hidereps = false;
-
-  /**
    * set visibility of sequences covered by (if no sequence representative is
    * defined) or represented by this group.
    * 
@@ -977,11 +997,6 @@ public class SequenceGroup implements AnnotatedCollectionI
   }
 
   /**
-   * visibility of columns intersecting this group
-   */
-  private boolean hidecols = false;
-
-  /**
    * set intended visibility of columns covered by this group
    * 
    * @param visibility
@@ -1015,7 +1030,7 @@ public class SequenceGroup implements AnnotatedCollectionI
   {
     SequenceGroup sgroup = new SequenceGroup(this);
     SequenceI[] insect = getSequencesInOrder(alignment);
-    sgroup.sequences = new ArrayList<SequenceI>();
+    sgroup.sequences = new ArrayList<>();
     for (int s = 0; insect != null && s < insect.length; s++)
     {
       if (map == null || map.containsKey(insect[s]))
@@ -1043,13 +1058,6 @@ public class SequenceGroup implements AnnotatedCollectionI
     this.showNonconserved = displayNonconserved;
   }
 
-  AlignmentAnnotation consensus = null, conservation = null;
-
-  /**
-   * flag indicating if consensus histogram should be rendered
-   */
-  private boolean showConsensusHistogram;
-
   /**
    * set this alignmentAnnotation object as the one used to render consensus
    * annotation
@@ -1242,7 +1250,7 @@ public class SequenceGroup implements AnnotatedCollectionI
   {
     // TODO add in other methods like 'getAlignmentAnnotation(String label),
     // etc'
-    ArrayList<AlignmentAnnotation> annot = new ArrayList<AlignmentAnnotation>();
+    ArrayList<AlignmentAnnotation> annot = new ArrayList<>();
     synchronized (sequences)
     {
       for (SequenceI seq : sequences)
@@ -1274,7 +1282,7 @@ public class SequenceGroup implements AnnotatedCollectionI
   @Override
   public Iterable<AlignmentAnnotation> findAnnotation(String calcId)
   {
-    List<AlignmentAnnotation> aa = new ArrayList<AlignmentAnnotation>();
+    List<AlignmentAnnotation> aa = new ArrayList<>();
     if (calcId == null)
     {
       return aa;
@@ -1293,7 +1301,7 @@ public class SequenceGroup implements AnnotatedCollectionI
   public Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq,
           String calcId, String label)
   {
-    ArrayList<AlignmentAnnotation> aa = new ArrayList<AlignmentAnnotation>();
+    ArrayList<AlignmentAnnotation> aa = new ArrayList<>();
     for (AlignmentAnnotation ann : getAlignmentAnnotation())
     {
       if ((calcId == null || (ann.getCalcId() != null && ann.getCalcId()
@@ -1340,12 +1348,29 @@ public class SequenceGroup implements AnnotatedCollectionI
     }
   }
 
-  private AnnotatedCollectionI context;
+  /**
+   * Sets the alignment or group context for this group, and whether it is
+   * defined as a group
+   * 
+   * @param ctx
+   *          the context for the group
+   * @param defined
+   *          whether the group is defined on the alignment or is just a
+   *          selection
+   * @throws IllegalArgumentException
+   *           if setting the context would result in a circular reference chain
+   */
+  public void setContext(AnnotatedCollectionI ctx, boolean defined)
+  {
+    setContext(ctx);
+    this.isDefined = defined;
+  }
 
   /**
    * Sets the alignment or group context for this group
    * 
    * @param ctx
+   *          the context for the group
    * @throws IllegalArgumentException
    *           if setting the context would result in a circular reference chain
    */
@@ -1375,6 +1400,11 @@ public class SequenceGroup implements AnnotatedCollectionI
     return context;
   }
 
+  public boolean isDefined()
+  {
+    return isDefined;
+  }
+
   public void setColourScheme(ColourSchemeI scheme)
   {
     if (cs == null)
index 92f797f..e81553b 100755 (executable)
@@ -189,12 +189,13 @@ public interface SequenceI extends ASequenceI
   public int findIndex(int pos);
 
   /**
-   * Returns the sequence position for an alignment position
+   * Returns the sequence position for an alignment position.
    * 
    * @param i
    *          column index in alignment (from 0..<length)
    * 
-   * @return residue number for residue (left of and) nearest ith column
+   * @return TODO: JAL-2562 - residue number for residue (left of and) nearest
+   *         ith column
    */
   public int findPosition(int i);
 
index 00fd679..5de554b 100644 (file)
@@ -164,7 +164,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
   public void closeViewer()
   {
     // remove listeners for all structures in viewer
-    getSsm().removeStructureViewerListener(this, this.getPdbFile());
+    getSsm().removeStructureViewerListener(this, this.getStructureFiles());
     viewer.dispose();
     lastCommand = null;
     viewer = null;
@@ -250,7 +250,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
      * get the distinct structure files modelled
      * (a file with multiple chains may map to multiple sequences)
      */
-    String[] files = getPdbFile();
+    String[] files = getStructureFiles();
     if (!waitForFileLoad(files))
     {
       return null;
@@ -577,7 +577,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
   private int getModelNum(String modelFileName)
   {
-    String[] mfn = getPdbFile();
+    String[] mfn = getStructureFiles();
     if (mfn == null)
     {
       return -1;
@@ -601,8 +601,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
   // ////////////////////////////////
   // /StructureListener
-  @Override
-  public synchronized String[] getPdbFile()
+  // @Override
+  public synchronized String[] getPdbFilex()
   {
     if (viewer == null)
     {
@@ -667,6 +667,32 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     return modelFileNames;
   }
 
+  @Override
+  public synchronized String[] getStructureFiles()
+  {
+    List<String> mset = new ArrayList<String>();
+    if (viewer == null)
+    {
+      return new String[0];
+    }
+
+    if (modelFileNames == null)
+    {
+      int modelCount = viewer.ms.mc;
+      String filePath = null;
+      for (int i = 0; i < modelCount; ++i)
+      {
+        filePath = viewer.ms.getModelFileName(i);
+        if (!mset.contains(filePath))
+        {
+          mset.add(filePath);
+        }
+      }
+      modelFileNames = mset.toArray(new String[mset.size()]);
+    }
+
+    return modelFileNames;
+  }
   /**
    * map from string to applet
    */
@@ -1035,7 +1061,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     chainNames = new ArrayList<String>();
     chainFile = new Hashtable<String, String>();
     boolean notifyLoaded = false;
-    String[] modelfilenames = getPdbFile();
+    String[] modelfilenames = getStructureFiles();
     // first check if we've lost any structures
     if (oldmodels != null && oldmodels.length > 0)
     {
index 870c4fe..b954677 100644 (file)
@@ -289,7 +289,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
    */
   public void closeViewer(boolean closeChimera)
   {
-    getSsm().removeStructureViewerListener(this, this.getPdbFile());
+    getSsm().removeStructureViewerListener(this, this.getStructureFiles());
     if (closeChimera)
     {
       viewer.exitChimera();
@@ -340,7 +340,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
           int[] _refStructure, HiddenColumns[] _hiddenCols)
   {
     StringBuilder allComs = new StringBuilder(128);
-    String[] files = getPdbFile();
+    String[] files = getStructureFiles();
 
     if (!waitForFileLoad(files))
     {
@@ -577,7 +577,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
      * to the Chimera command 'list models type molecule', see
      * ChimeraManager.getModelList().
      */
-    List<ChimeraModel> maps = chimeraMaps.get(getPdbFile()[pdbfnum]);
+    List<ChimeraModel> maps = chimeraMaps.get(getStructureFiles()[pdbfnum]);
     boolean hasSubModels = maps != null && maps.size() > 1;
     return "#" + String.valueOf(pdbfnum) + (hasSubModels ? ".1" : "");
   }
@@ -745,7 +745,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   // ////////////////////////////////
   // /StructureListener
   @Override
-  public synchronized String[] getPdbFile()
+  public synchronized String[] getStructureFiles()
   {
     if (viewer == null)
     {
@@ -1100,7 +1100,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     // TODO refactor as required to pull up to an interface
     AlignmentI alignment = avp.getAlignment();
 
-    String[] files = getPdbFile();
+    String[] files = getStructureFiles();
     if (files == null)
     {
       return 0;
index 4073e3e..a9a970f 100644 (file)
@@ -691,23 +691,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         case KeyEvent.VK_PAGE_UP:
           if (viewport.getWrapAlignment())
           {
-            alignPanel.scrollUp(true);
+            vpRanges.scrollUp(true);
           }
           else
           {
-            alignPanel.setScrollValues(vpRanges.getStartRes(),
-                    2 * vpRanges.getStartSeq() - vpRanges.getEndSeq());
+            vpRanges.pageUp();
           }
           break;
         case KeyEvent.VK_PAGE_DOWN:
           if (viewport.getWrapAlignment())
           {
-            alignPanel.scrollUp(false);
+            vpRanges.scrollUp(false);
           }
           else
           {
-            alignPanel.setScrollValues(vpRanges.getStartRes(),
-                    vpRanges.getEndSeq());
+            vpRanges.pageDown();
           }
           break;
         }
@@ -3280,7 +3278,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     frame.setContentPane(overview);
     Desktop.addInternalFrame(frame, MessageManager.formatMessage(
             "label.overview_params", new Object[] { this.getTitle() }),
-            frame.getWidth(), frame.getHeight());
+            true, frame.getWidth(), frame.getHeight(), true, true);
     frame.pack();
     frame.setLayer(JLayeredPane.PALETTE_LAYER);
     frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
index 6409b56..86e1144 100644 (file)
@@ -1049,8 +1049,9 @@ public class AlignViewport extends AlignmentViewport implements
       // TODO would like next line without cast but needs more refactoring...
       final AlignmentPanel complementPanel = ((AlignViewport) getCodingComplement())
               .getAlignPanel();
-      complementPanel.setDontScrollComplement(true);
+      complementPanel.setToScrollComplementPanel(false);
       complementPanel.scrollToCentre(sr, verticalOffset);
+      complementPanel.setToScrollComplementPanel(true);
     }
   }
 
index 885d79d..395f6b3 100644 (file)
@@ -36,6 +36,7 @@ import jalview.schemes.ResidueProperties;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.viewmodel.ViewportListenerI;
 import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BorderLayout;
@@ -48,6 +49,8 @@ import java.awt.Graphics;
 import java.awt.Insets;
 import java.awt.event.AdjustmentEvent;
 import java.awt.event.AdjustmentListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
 import java.awt.print.PageFormat;
 import java.awt.print.Printable;
 import java.awt.print.PrinterException;
@@ -67,7 +70,8 @@ import javax.swing.SwingUtilities;
  * @version $Revision: 1.161 $
  */
 public class AlignmentPanel extends GAlignmentPanel implements
-        AdjustmentListener, Printable, AlignmentViewPanel
+        AdjustmentListener, Printable, AlignmentViewPanel,
+        ViewportListenerI
 {
   public AlignViewport av;
 
@@ -101,9 +105,9 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
   /*
    * Flag set while scrolling to follow complementary cDNA/protein scroll. When
-   * true, suppresses invoking the same method recursively.
+   * false, suppresses invoking the same method recursively.
    */
-  private boolean dontScrollComplement;
+  private boolean scrollComplementaryPanel = true;
 
   private PropertyChangeListener propertyChangeListener;
 
@@ -143,6 +147,34 @@ public class AlignmentPanel extends GAlignmentPanel implements
     hscroll.addAdjustmentListener(this);
     vscroll.addAdjustmentListener(this);
 
+    addComponentListener(new ComponentAdapter()
+    {
+      @Override
+      public void componentResized(ComponentEvent evt)
+      {
+        // reset the viewport ranges when the alignment panel is resized
+        // in particular, this initialises the end residue value when Jalview
+        // is initialised
+        if (av.getWrapAlignment())
+        {
+          int widthInRes = getSeqPanel().seqCanvas
+                  .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
+          vpRanges.setViewportWidth(widthInRes);
+        }
+        else
+        {
+          int widthInRes = getSeqPanel().seqCanvas.getWidth()
+                  / av.getCharWidth();
+          int heightInSeq = getSeqPanel().seqCanvas.getHeight()
+                  / av.getCharHeight();
+          
+          vpRanges.setViewportWidth(widthInRes);
+          vpRanges.setViewportHeight(heightInSeq);
+        }
+      }
+
+    });
+
     final AlignmentPanel ap = this;
     propertyChangeListener = new PropertyChangeListener()
     {
@@ -157,6 +189,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
       }
     };
     av.addPropertyChangeListener(propertyChangeListener);
+
+    av.getRanges().addPropertyChangeListener(this);
     fontChanged();
     adjustAnnotationHeight();
     updateLayout();
@@ -207,10 +241,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
     getIdPanel().getIdCanvas().setPreferredSize(d);
     hscrollFillerPanel.setPreferredSize(d);
 
-    if (overviewPanel != null)
-    {
-      overviewPanel.setBoxPosition();
-    }
     if (this.alignFrame.getSplitViewContainer() != null)
     {
       ((SplitFrame) this.alignFrame.getSplitViewContainer()).adjustLayout();
@@ -379,9 +409,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
       }
       int start = r[0];
       int end = r[1];
-      // DEBUG
-      // System.err.println(this.av.viewName + " Seq : " + seqIndex
-      // + " Scroll to " + start + "," + end);
 
       /*
        * To centre results, scroll to positions half the visible width
@@ -389,7 +416,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
        */
       if (centre)
       {
-        int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2 - 1;
+        int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2
+                - 1;
         start = Math.max(start - offset, 0);
         end = end + offset - 1;
       }
@@ -421,9 +449,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
        */
       seqIndex = Math.max(0, seqIndex - verticalOffset);
 
-      // System.out.println("start=" + start + ", end=" + end + ", startv="
-      // + av.getStartRes() + ", endv=" + av.getEndRes() + ", starts="
-      // + av.getStartSeq() + ", ends=" + av.getEndSeq());
       if (!av.getWrapAlignment())
       {
         if ((startv = vpRanges.getStartRes()) >= start)
@@ -431,7 +456,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
           /*
            * Scroll left to make start of search results visible
            */
-          // setScrollValues(start - 1, seqIndex); // plus one residue
           setScrollValues(start, seqIndex);
         }
         else if ((endv = vpRanges.getEndRes()) <= end)
@@ -439,7 +463,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
           /*
            * Scroll right to make end of search results visible
            */
-          // setScrollValues(startv + 1 + end - endv, seqIndex); // plus one
           setScrollValues(startv + end - endv, seqIndex);
         }
         else if ((starts = vpRanges.getStartSeq()) > seqIndex)
@@ -463,30 +486,14 @@ public class AlignmentPanel extends GAlignmentPanel implements
       }
       else
       {
-        scrollToWrappedVisible(start);
+        vpRanges.scrollToWrappedVisible(start);
       }
     }
-    if (redrawOverview && overviewPanel != null)
-    {
-      overviewPanel.setBoxPosition();
-    }
+
     paintAlignment(redrawOverview);
     return true;
   }
 
-  void scrollToWrappedVisible(int res)
-  {
-    int cwidth = getSeqPanel().seqCanvas
-            .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
-    if (res < vpRanges.getStartRes()
-            || res >= (vpRanges.getStartRes() + cwidth))
-    {
-      vscroll.setValue((res / cwidth));
-      vpRanges.setStartRes(vscroll.getValue() * cwidth);
-    }
-
-  }
-
   /**
    * DOCUMENT ME!
    * 
@@ -622,75 +629,28 @@ public class AlignmentPanel extends GAlignmentPanel implements
       annotationSpaceFillerHolder.setVisible(true);
     }
 
-    idSpaceFillerPanel1.setVisible(!wrap);
-
-    repaint();
-  }
-
-  // return value is true if the scroll is valid
-  public boolean scrollUp(boolean up)
-  {
-    if (up)
+    if (wrap)
     {
-      if (vscroll.getValue() < 1)
-      {
-        return false;
-      }
-
-      fastPaint = false;
-      vscroll.setValue(vscroll.getValue() - 1);
+      int widthInRes = getSeqPanel().seqCanvas
+              .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
+      vpRanges.setViewportWidth(widthInRes);
     }
     else
     {
-      if ((vextent + vscroll.getValue()) >= av.getAlignment().getHeight())
-      {
-        return false;
-      }
+      int widthInRes = (getSeqPanel().seqCanvas.getWidth() / av
+              .getCharWidth()) - 1;
+      int heightInSeq = (getSeqPanel().seqCanvas.getHeight() / av
+              .getCharHeight()) - 1;
 
-      fastPaint = false;
-      vscroll.setValue(vscroll.getValue() + 1);
+      vpRanges.setViewportWidth(widthInRes);
+      vpRanges.setViewportHeight(heightInSeq);
     }
 
-    fastPaint = true;
+    idSpaceFillerPanel1.setVisible(!wrap);
 
-    return true;
+    repaint();
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param right
-   *          DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
-  public boolean scrollRight(boolean right)
-  {
-    if (!right)
-    {
-      if (hscroll.getValue() < 1)
-      {
-        return false;
-      }
-
-      fastPaint = false;
-      hscroll.setValue(hscroll.getValue() - 1);
-    }
-    else
-    {
-      if ((hextent + hscroll.getValue()) >= av.getAlignment().getWidth())
-      {
-        return false;
-      }
-
-      fastPaint = false;
-      hscroll.setValue(hscroll.getValue() + 1);
-    }
-
-    fastPaint = true;
-
-    return true;
-  }
 
   /**
    * Adjust row/column scrollers to show a visible position in the alignment.
@@ -701,176 +661,170 @@ public class AlignmentPanel extends GAlignmentPanel implements
    *          visible row to scroll to
    * 
    */
-  public void setScrollValues(int x, int y)
+  public void setScrollValues(int xpos, int ypos)
   {
+    int x = xpos;
+    int y = ypos;
+
     if (av == null || av.getAlignment() == null)
     {
       return;
     }
-    int width = av.getAlignment().getWidth();
-    int height = av.getAlignment().getHeight();
 
-    if (av.hasHiddenColumns())
+    if (av.getWrapAlignment())
     {
-      // reset the width to exclude hidden columns
-      width = av.getAlignment().getHiddenColumns()
-              .findColumnPosition(width);
+      setScrollingForWrappedPanel(x);
     }
+    else
+    {
+      int width = av.getAlignment().getWidth();
+      int height = av.getAlignment().getHeight();
 
-    hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
-    vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight();
+      if (av.hasHiddenColumns())
+      {
+        // reset the width to exclude hidden columns
+        width = av.getAlignment().getHiddenColumns().findColumnPosition(width);
+      }
 
-    if (hextent > width)
-    {
-      hextent = width;
-    }
+      hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
+      vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight();
 
-    if (vextent > height)
-    {
-      vextent = height;
-    }
+      if (hextent > width)
+      {
+        hextent = width;
+      }
 
-    if ((hextent + x) > width)
-    {
-      x = width - hextent;
-    }
+      if (vextent > height)
+      {
+        vextent = height;
+      }
 
-    if ((vextent + y) > height)
-    {
-      y = height - vextent;
-    }
+      if ((hextent + x) > width)
+      {
+        x = width - hextent;
+      }
 
-    if (y < 0)
-    {
-      y = 0;
-    }
+      if ((vextent + y) > height)
+      {
+        y = height - vextent;
+      }
 
-    if (x < 0)
-    {
-      x = 0;
-    }
+      if (y < 0)
+      {
+        y = 0;
+      }
 
-    // update endRes after x has (possibly) been adjusted
-    vpRanges.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
-            .getCharWidth())) - 1);
+      if (x < 0)
+      {
+        x = 0;
+      }
 
-    /*
-     * each scroll adjustment triggers adjustmentValueChanged, which resets the
-     * 'do not scroll complement' flag; ensure it is the same for both
-     * operations
-     */
-    boolean flag = isDontScrollComplement();
-    hscroll.setValues(x, hextent, 0, width);
-    setDontScrollComplement(flag);
-    vscroll.setValues(y, vextent, 0, height);
+      // update the scroll values
+      hscroll.setValues(x, hextent, 0, width);
+      vscroll.setValues(y, vextent, 0, height);
+    }
   }
 
   /**
-   * DOCUMENT ME!
+   * Respond to adjustment event when horizontal or vertical scrollbar is
+   * changed
    * 
    * @param evt
-   *          DOCUMENT ME!
+   *          adjustment event encoding whether hscroll or vscroll changed
    */
   @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
     int oldX = vpRanges.getStartRes();
+    int oldwidth = vpRanges.getViewportWidth();
     int oldY = vpRanges.getStartSeq();
+    int oldheight = vpRanges.getViewportHeight();
 
-    if (evt.getSource() == hscroll)
-    {
-      int x = hscroll.getValue();
-      vpRanges.setStartRes(x);
-      vpRanges.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
-              .getCharWidth())) - 1);
-    }
-
-    if (evt.getSource() == vscroll)
+    if (av.getWrapAlignment())
     {
-      int offy = vscroll.getValue();
-
-      if (av.getWrapAlignment())
+      if (evt.getSource() == hscroll)
       {
-        if (offy > -1)
+        return; // no horizontal scroll when wrapped
+      }
+      else if (evt.getSource() == vscroll)
+      {
+        int offy = vscroll.getValue();
+        int rowSize = getSeqPanel().seqCanvas
+                .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
+
+        // if we're scrolling to the position we're already at, stop
+        // this prevents infinite recursion of events when the scroll/viewport
+        // ranges values are the same
+        if ((offy * rowSize == oldX) && (oldwidth == rowSize))
         {
-          int rowSize = getSeqPanel().seqCanvas
-                  .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
-          vpRanges.setStartRes(offy * rowSize);
-          vpRanges.setEndRes((offy + 1) * rowSize);
+          return;
         }
-        else
+        else if (offy > -1)
         {
-          // This is only called if file loaded is a jar file that
-          // was wrapped when saved and user has wrap alignment true
-          // as preference setting
-          SwingUtilities.invokeLater(new Runnable()
-          {
-            @Override
-            public void run()
-            {
-              setScrollValues(vpRanges.getStartRes(),
-                      vpRanges.getStartSeq());
-            }
-          });
+          vpRanges.setViewportStartAndWidth(offy * rowSize, rowSize);
         }
       }
       else
       {
-        vpRanges.setStartSeq(offy);
-        vpRanges.setEndSeq(offy
-                + (getSeqPanel().seqCanvas.getHeight() / av.getCharHeight())
-                - 1);
+        // This is only called if file loaded is a jar file that
+        // was wrapped when saved and user has wrap alignment true
+        // as preference setting
+        SwingUtilities.invokeLater(new Runnable()
+        {
+          @Override
+          public void run()
+        {
+            // When updating scrolling to use ViewportChange events, this code
+            // could not be validated and it is not clear if it is now being
+            // called. Log warning here in case it is called and unforeseen
+            // problems occur
+            Cache.log
+                    .warn("Unexpected path through code: Wrapped jar file opened with wrap alignment set in preferences");
+
+            // scroll to start of panel
+            vpRanges.setStartRes(0);
+            vpRanges.setStartSeq(0);
+          }
+        });
       }
-    }
-
-    if (overviewPanel != null)
-    {
-      overviewPanel.setBoxPosition();
-    }
-
-    int scrollX = vpRanges.getStartRes() - oldX;
-    int scrollY = vpRanges.getStartSeq() - oldY;
-
-    if (av.getWrapAlignment() || !fastPaint)
-    {
       repaint();
     }
     else
     {
-      // Make sure we're not trying to draw a panel
-      // larger than the visible window
-      if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
+      // horizontal scroll
+      if (evt.getSource() == hscroll)
       {
-        scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
-      }
-      else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
-      {
-        scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
-      }
+        int x = hscroll.getValue();
+        int width = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
 
-      if (scrollX != 0 || scrollY != 0)
+        // if we're scrolling to the position we're already at, stop
+        // this prevents infinite recursion of events when the scroll/viewport
+        // ranges values are the same
+        if ((x == oldX) && (width == oldwidth))
+        {
+          return;
+        }
+        vpRanges.setViewportStartAndWidth(x, width);
+      }
+      else if (evt.getSource() == vscroll)
       {
-        getIdPanel().getIdCanvas().fastPaint(scrollY);
-        getSeqPanel().seqCanvas.fastPaint(scrollX, scrollY);
-        getScalePanel().repaint();
-
-        if (av.isShowAnnotation() && scrollX != 0)
+        int y = vscroll.getValue();
+        int height = getSeqPanel().seqCanvas.getHeight()
+                / av.getCharHeight();
+
+        // if we're scrolling to the position we're already at, stop
+        // this prevents infinite recursion of events when the scroll/viewport
+        // ranges values are the same
+        if ((y == oldY) && (height == oldheight))
         {
-          getAnnotationPanel().fastPaint(scrollX);
+          return;
         }
+        vpRanges.setViewportStartAndHeight(y, height);
+      }
+      if (!fastPaint)
+      {
+        repaint();
       }
-    }
-    /*
-     * If there is one, scroll the (Protein/cDNA) complementary alignment to
-     * match, unless we are ourselves doing that.
-     */
-    if (isDontScrollComplement())
-    {
-      setDontScrollComplement(false);
-    }
-    else
-    {
-      av.scrollComplementaryAlignment();
     }
   }
 
@@ -916,37 +870,39 @@ public class AlignmentPanel extends GAlignmentPanel implements
     validate();
 
     /*
-     * set scroll bar positions; first suppress this being 'followed' in any
-     * complementary split pane
+     * set scroll bar positions
      */
-    setDontScrollComplement(true);
+    setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
+  }
 
-    if (av.getWrapAlignment())
+  /*
+   * Set vertical scroll bar parameters for wrapped panel
+   * @param res 
+   *    the residue to scroll to
+   */
+  private void setScrollingForWrappedPanel(int res)
+  {
+    // get the width of the alignment in residues
+    int maxwidth = av.getAlignment().getWidth();
+    if (av.hasHiddenColumns())
     {
-      int maxwidth = av.getAlignment().getWidth();
-
-      if (av.hasHiddenColumns())
-      {
         maxwidth = av.getAlignment().getHiddenColumns()
                 .findColumnPosition(maxwidth) - 1;
-      }
-
-      int canvasWidth = getSeqPanel().seqCanvas
-              .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
-      if (canvasWidth > 0)
-      {
-        int max = maxwidth
-                / getSeqPanel().seqCanvas
-                        .getWrappedCanvasWidth(getSeqPanel().seqCanvas
-                                .getWidth()) + 1;
-        vscroll.setMaximum(max);
-        vscroll.setUnitIncrement(1);
-        vscroll.setVisibleAmount(1);
-      }
     }
-    else
+
+    // get the width of the canvas in residues
+    int canvasWidth = getSeqPanel().seqCanvas
+            .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
+    if (canvasWidth > 0)
     {
-      setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
+      // position we want to scroll to is number of canvasWidth's to get there
+      int current = res / canvasWidth;
+
+      // max scroll position: add one because extent is 1 and scrollbar value
+      // can only be set to at most max - extent
+      int max = maxwidth / canvasWidth + 1;
+      vscroll.setUnitIncrement(1);
+      vscroll.setValues(current, 1, 0, max);
     }
   }
 
@@ -1902,14 +1858,19 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * 
    * @param b
    */
-  protected void setDontScrollComplement(boolean b)
+  protected void setToScrollComplementPanel(boolean b)
   {
-    this.dontScrollComplement = b;
+    this.scrollComplementaryPanel = b;
   }
 
-  protected boolean isDontScrollComplement()
+  /**
+   * Get whether to scroll complement panel
+   * 
+   * @return true if cDNA/protein complement panels should be scrolled
+   */
+  protected boolean isSetToScrollComplementPanel()
   {
-    return this.dontScrollComplement;
+    return this.scrollComplementaryPanel;
   }
 
   /**
@@ -1934,6 +1895,28 @@ public class AlignmentPanel extends GAlignmentPanel implements
     }
   }
 
+  @Override
+  /**
+   * Property change event fired when a change is made to the viewport ranges 
+   * object associated with this alignment panel's viewport
+   */
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    // update this panel's scroll values based on the new viewport ranges values
+    int x = vpRanges.getStartRes();
+    int y = vpRanges.getStartSeq();
+    setScrollValues(x, y);
+
+    // now update any complementary alignment (its viewport ranges object
+    // is different so does not get automatically updated)
+    if (isSetToScrollComplementPanel())
+    {
+      setToScrollComplementPanel(false);
+      av.scrollComplementaryAlignment();
+      setToScrollComplementPanel(true);
+    }
+  }
+
   /**
    * Set the reference to the PCA/Tree chooser dialog for this panel. This
    * reference should be nulled when the dialog is closed.
index 919356f..452f002 100755 (executable)
@@ -30,6 +30,7 @@ import jalview.renderer.AwtRenderPanelI;
 import jalview.schemes.ResidueProperties;
 import jalview.util.Comparison;
 import jalview.util.MessageManager;
+import jalview.viewmodel.ViewportListenerI;
 
 import java.awt.AlphaComposite;
 import java.awt.Color;
@@ -50,6 +51,7 @@ import java.awt.event.MouseMotionListener;
 import java.awt.event.MouseWheelEvent;
 import java.awt.event.MouseWheelListener;
 import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeEvent;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -70,7 +72,7 @@ import javax.swing.ToolTipManager;
  */
 public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         MouseListener, MouseWheelListener, MouseMotionListener,
-        ActionListener, AdjustmentListener, Scrollable
+        ActionListener, AdjustmentListener, Scrollable, ViewportListenerI
 {
   String HELIX = MessageManager.getString("label.helix");
 
@@ -156,6 +158,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     // and then set our own listener to consume all mousewheel events
     ap.annotationScroller.addMouseWheelListener(this);
     renderer = new AnnotationRenderer();
+
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   public AnnotationPanel(AlignViewport av)
@@ -172,11 +176,11 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       e.consume();
       if (e.getWheelRotation() > 0)
       {
-        ap.scrollRight(true);
+        av.getRanges().scrollRight(true);
       }
       else
       {
-        ap.scrollRight(false);
+        av.getRanges().scrollRight(false);
       }
     }
     else
@@ -1159,4 +1163,15 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       renderer.dispose();
     }
   }
+
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    // Respond to viewport range changes (e.g. alignment panel was scrolled)
+    if (evt.getPropertyName().equals("startres")
+            || evt.getPropertyName().equals("endres"))
+    {
+      fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
+    }
+  }
 }
index 5d23f49..68a847e 100644 (file)
@@ -410,8 +410,8 @@ public class AppJmol extends StructureViewerBase
     int waitFor = 35;
     int waitTotal = 0;
     while (addingStructures ? lastnotify >= jmb.getLoadNotifiesHandled()
-            : !(jmb.isFinishedInit() && jmb.getPdbFile() != null && jmb
-                    .getPdbFile().length == files.size()))
+            : !(jmb.isFinishedInit() && jmb.getStructureFiles() != null && jmb
+                    .getStructureFiles().length == files.size()))
     {
       try
       {
@@ -429,7 +429,7 @@ public class AppJmol extends StructureViewerBase
 //        System.err.println("finished: " + jmb.isFinishedInit()
 //                + "; loaded: " + Arrays.toString(jmb.getPdbFile())
 //                + "; files: " + files.toString());
-        jmb.getPdbFile();
+        jmb.getStructureFiles();
         break;
       }
     }
@@ -494,7 +494,7 @@ public class AppJmol extends StructureViewerBase
     String pdbid = "";
     try
     {
-      String[] filesInViewer = jmb.getPdbFile();
+      String[] filesInViewer = jmb.getStructureFiles();
       // TODO: replace with reference fetching/transfer code (validate PDBentry
       // as a DBRef?)
       Pdb pdbclient = new Pdb();
index 8ab1e61..829fc3e 100644 (file)
@@ -384,7 +384,7 @@ public class AppVarnaBinding extends JalviewVarnaBinding
   }
 
   @Override
-  public String[] getPdbFile()
+  public String[] getStructureFiles()
   {
     return null;
   }
index ab6f6c8..eadc2ad 100644 (file)
@@ -490,7 +490,7 @@ public class ChimeraViewFrame extends StructureViewerBase
     StructureFile pdb = null;
     try
     {
-      String[] curfiles = jmb.getPdbFile(); // files currently in viewer
+      String[] curfiles = jmb.getStructureFiles(); // files currently in viewer
       // TODO: replace with reference fetching/transfer code (validate PDBentry
       // as a DBRef?)
       for (int pi = 0; pi < jmb.getPdbCount(); pi++)
index 4877d7f..63d88a0 100644 (file)
@@ -749,7 +749,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
   public static synchronized void addInternalFrame(
           final JInternalFrame frame, String title, int w, int h)
   {
-    addInternalFrame(frame, title, true, w, h, true);
+    addInternalFrame(frame, title, true, w, h, true, false);
   }
 
   /**
@@ -771,7 +771,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
           final JInternalFrame frame, String title, boolean makeVisible,
           int w, int h)
   {
-    addInternalFrame(frame, title, makeVisible, w, h, true);
+    addInternalFrame(frame, title, makeVisible, w, h, true, false);
   }
 
   /**
@@ -792,7 +792,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
           final JInternalFrame frame, String title, int w, int h,
           boolean resizable)
   {
-    addInternalFrame(frame, title, true, w, h, resizable);
+    addInternalFrame(frame, title, true, w, h, resizable, false);
   }
 
   /**
@@ -811,10 +811,12 @@ public class Desktop extends jalview.jbgui.GDesktop implements
    *          height
    * @param resizable
    *          Allow resize
+   * @param ignoreMinSize
+   *          Do not set the default minimum size for frame
    */
   public static synchronized void addInternalFrame(
           final JInternalFrame frame, String title, boolean makeVisible,
-          int w, int h, boolean resizable)
+          int w, int h, boolean resizable, boolean ignoreMinSize)
   {
 
     // TODO: allow callers to determine X and Y position of frame (eg. via
@@ -840,8 +842,11 @@ public class Desktop extends jalview.jbgui.GDesktop implements
 
     openFrameCount++;
 
-    frame.setMinimumSize(new Dimension(DEFAULT_MIN_WIDTH,
-            DEFAULT_MIN_HEIGHT));
+    if (!ignoreMinSize)
+    {
+      frame.setMinimumSize(new Dimension(DEFAULT_MIN_WIDTH,
+              DEFAULT_MIN_HEIGHT));
+    }
     frame.setVisible(makeVisible);
     frame.setClosable(true);
     frame.setResizable(resizable);
index 1b79f54..5ce36cb 100755 (executable)
@@ -21,6 +21,7 @@
 package jalview.gui;
 
 import jalview.datamodel.SequenceI;
+import jalview.viewmodel.ViewportListenerI;
 import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BorderLayout;
@@ -31,6 +32,7 @@ import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.RenderingHints;
 import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeEvent;
 import java.util.List;
 
 import javax.swing.JPanel;
@@ -41,7 +43,7 @@ import javax.swing.JPanel;
  * @author $author$
  * @version $Revision$
  */
-public class IdCanvas extends JPanel
+public class IdCanvas extends JPanel implements ViewportListenerI
 {
   protected AlignViewport av;
 
@@ -80,6 +82,7 @@ public class IdCanvas extends JPanel
     setLayout(new BorderLayout());
     this.av = av;
     PaintRefresher.Register(this, av.getSequenceSetId());
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   /**
@@ -516,4 +519,15 @@ public class IdCanvas extends JPanel
   {
     this.idfont = idfont;
   }
+
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    // Respond to viewport range changes (e.g. alignment panel was scrolled)
+    if (evt.getPropertyName().equals("startseq")
+            || evt.getPropertyName().equals("endseq"))
+    {
+      fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
+    }
+  }
 }
index 2074900..6097089 100755 (executable)
@@ -152,22 +152,22 @@ public class IdPanel extends JPanel implements MouseListener,
     {
       if (e.isShiftDown())
       {
-        alignPanel.scrollRight(true);
+        av.getRanges().scrollRight(true);
       }
       else
       {
-        alignPanel.scrollUp(false);
+        av.getRanges().scrollUp(false);
       }
     }
     else
     {
       if (e.isShiftDown())
       {
-        alignPanel.scrollRight(false);
+        av.getRanges().scrollRight(false);
       }
       else
       {
-        alignPanel.scrollUp(true);
+        av.getRanges().scrollUp(true);
       }
     }
   }
@@ -446,7 +446,7 @@ public class IdPanel extends JPanel implements MouseListener,
     if ((av.getRanges().getStartSeq() > index)
             || (av.getRanges().getEndSeq() < index))
     {
-      alignPanel.setScrollValues(av.getRanges().getStartRes(), index);
+      av.getRanges().setStartSeq(index);
     }
   }
 
@@ -485,7 +485,7 @@ public class IdPanel extends JPanel implements MouseListener,
 
       while (running)
       {
-        if (alignPanel.scrollUp(up))
+        if (av.getRanges().scrollUp(up))
         {
           // scroll was ok, so add new sequence to selection
           int seq = av.getRanges().getStartSeq();
index 6361caf..dee921e 100644 (file)
@@ -4464,7 +4464,7 @@ public class Jalview2XML
     af.viewport.setShowUnconserved(view.hasShowUnconserved() ? view
             .isShowUnconserved() : false);
     af.viewport.getRanges().setStartRes(view.getStartRes());
-    af.viewport.getRanges().setStartSeq(view.getStartSeq());
+    // startSeq set in af.alignPanel.updateLayout below
     af.alignPanel.updateLayout();
     ColourSchemeI cs = null;
     // apply colourschemes
index cc2f636..8d71ccf 100755 (executable)
@@ -368,7 +368,7 @@ public class Jalview2XML_V1
     af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
             view.getHeight());
     af.viewport.getRanges().setStartRes(view.getStartRes());
-    af.viewport.getRanges().setStartSeq(view.getStartSeq());
+    // startSeq set in af.alignPanel.updateLayout below
     af.viewport.setShowAnnotation(view.getShowAnnotation());
     af.viewport.setAbovePIDThreshold(view.getPidSelected());
     af.viewport.setColourText(view.getShowColourText());
index a6c3960..3fa674e 100755 (executable)
@@ -25,6 +25,7 @@ import jalview.util.Platform;
 import jalview.viewmodel.OverviewDimensions;
 import jalview.viewmodel.OverviewDimensionsHideHidden;
 import jalview.viewmodel.OverviewDimensionsShowHidden;
+import jalview.viewmodel.ViewportListenerI;
 
 import java.awt.BorderLayout;
 import java.awt.Dimension;
@@ -35,6 +36,7 @@ import java.awt.event.ComponentEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseMotionAdapter;
+import java.beans.PropertyChangeEvent;
 
 import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JPanel;
@@ -48,7 +50,8 @@ import javax.swing.SwingUtilities;
  * @author $author$
  * @version $Revision$
  */
-public class OverviewPanel extends JPanel implements Runnable
+public class OverviewPanel extends JPanel implements Runnable,
+        ViewportListenerI
 {
   private OverviewDimensions od;
 
@@ -77,10 +80,14 @@ public class OverviewPanel extends JPanel implements Runnable
             (av.isShowAnnotation() && av
                     .getAlignmentConservationAnnotation() != null));
 
+    setSize(od.getWidth(), od.getHeight());
+
     oviewCanvas = new OverviewCanvas(od, av);
     setLayout(new BorderLayout());
     add(oviewCanvas, BorderLayout.CENTER);
 
+    av.getRanges().addPropertyChangeListener(this);
+
     addComponentListener(new ComponentAdapter()
     {
       @Override
@@ -90,6 +97,7 @@ public class OverviewPanel extends JPanel implements Runnable
                 || (getHeight() != (od.getHeight())))
         {
           updateOverviewImage();
+          setBoxPosition();
         }
       }
     });
@@ -105,7 +113,7 @@ public class OverviewPanel extends JPanel implements Runnable
           od.updateViewportFromMouse(evt.getX(), evt.getY(), av
                   .getAlignment().getHiddenSequences(), av.getAlignment()
                   .getHiddenColumns());
-          ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
+
         }
       }
     });
@@ -127,7 +135,6 @@ public class OverviewPanel extends JPanel implements Runnable
           od.updateViewportFromMouse(evt.getX(), evt.getY(), av
                   .getAlignment().getHiddenSequences(), av.getAlignment()
                   .getHiddenColumns());
-          ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
         }
       }
 
@@ -191,6 +198,7 @@ public class OverviewPanel extends JPanel implements Runnable
     }
     oviewCanvas.resetOviewDims(od);
     updateOverviewImage();
+    setBoxPosition();
   }
 
   /**
@@ -232,10 +240,16 @@ public class OverviewPanel extends JPanel implements Runnable
    * changed
    * 
    */
-  public void setBoxPosition()
+  private void setBoxPosition()
   {
     od.setBoxPosition(av.getAlignment().getHiddenSequences(), av
             .getAlignment().getHiddenColumns());
     repaint();
   }
+
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    setBoxPosition();
+  }
 }
index 90f7cd2..cb19539 100755 (executable)
@@ -28,6 +28,7 @@ import jalview.renderer.ScaleRenderer;
 import jalview.renderer.ScaleRenderer.ScaleMark;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.viewmodel.ViewportListenerI;
 
 import java.awt.Color;
 import java.awt.FontMetrics;
@@ -39,6 +40,7 @@ import java.awt.event.ActionListener;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
 import java.util.List;
 
 import javax.swing.JMenuItem;
@@ -52,7 +54,7 @@ import javax.swing.ToolTipManager;
  * supports a range of mouse operations to select, hide or reveal columns.
  */
 public class ScalePanel extends JPanel implements MouseMotionListener,
-        MouseListener
+        MouseListener, ViewportListenerI
 {
   protected int offy = 4;
 
@@ -91,6 +93,8 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
 
     addMouseListener(this);
     addMouseMotionListener(this);
+
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   /**
@@ -548,4 +552,11 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
     }
   }
 
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    // Respond to viewport change events (e.g. alignment panel was scrolled)
+    repaint();
+  }
+
 }
index c2a2ccb..0e5e1b8 100755 (executable)
@@ -27,6 +27,7 @@ import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.ScaleRenderer;
 import jalview.renderer.ScaleRenderer.ScaleMark;
+import jalview.viewmodel.ViewportListenerI;
 import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BasicStroke;
@@ -38,6 +39,7 @@ import java.awt.Graphics2D;
 import java.awt.RenderingHints;
 import java.awt.Shape;
 import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeEvent;
 import java.util.List;
 
 import javax.swing.JComponent;
@@ -48,7 +50,7 @@ import javax.swing.JComponent;
  * @author $author$
  * @version $Revision$
  */
-public class SeqCanvas extends JComponent
+public class SeqCanvas extends JComponent implements ViewportListenerI
 {
   final FeatureRenderer fr;
 
@@ -89,6 +91,8 @@ public class SeqCanvas extends JComponent
     setLayout(new BorderLayout());
     PaintRefresher.Register(this, av.getSequenceSetId());
     setBackground(Color.white);
+
+    av.getRanges().addPropertyChangeListener(this);
   }
 
   public SequenceRenderer getSequenceRenderer()
@@ -295,13 +299,12 @@ public class SeqCanvas extends JComponent
 
     if (horizontal > 0) // scrollbar pulled right, image to the left
     {
-      er++;
       transX = (er - sr - horizontal) * charWidth;
       sr = er - horizontal;
     }
     else if (horizontal < 0)
     {
-      er = sr - horizontal - 1;
+      er = sr - horizontal;
     }
     else if (vertical > 0) // scroll down
     {
@@ -512,7 +515,7 @@ public class SeqCanvas extends JComponent
 
     av.setWrappedWidth(cWidth);
 
-    av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth);
+    av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth - 1);
 
     int endx;
     int ypos = hgap;
@@ -981,4 +984,34 @@ public class SeqCanvas extends JComponent
 
     repaint();
   }
+
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    if (!av.getWrapAlignment())
+    {
+      if (evt.getPropertyName().equals("startres")
+              || evt.getPropertyName().equals("endres"))
+      {
+        // Make sure we're not trying to draw a panel
+        // larger than the visible window
+        ViewportRanges vpRanges = av.getRanges();
+        int scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
+        if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
+        {
+          scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
+        }
+        else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
+        {
+          scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
+        }
+        fastPaint(scrollX, 0);
+      }
+      else if (evt.getPropertyName().equals("startseq")
+              || evt.getPropertyName().equals("endseq"))
+      {
+        fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
+      }
+    }
+  }
 }
index 7dfac5e..c6c2deb 100644 (file)
@@ -62,6 +62,7 @@ import java.awt.event.MouseWheelListener;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.ListIterator;
 
 import javax.swing.JPanel;
 import javax.swing.SwingUtilities;
@@ -389,38 +390,11 @@ public class SeqPanel extends JPanel implements MouseListener,
     endEditing();
     if (av.getWrapAlignment())
     {
-      ap.scrollToWrappedVisible(seqCanvas.cursorX);
+      av.getRanges().scrollToWrappedVisible(seqCanvas.cursorX);
     }
     else
     {
-      while (seqCanvas.cursorY < av.getRanges().getStartSeq())
-      {
-        ap.scrollUp(true);
-      }
-      while (seqCanvas.cursorY > av.getRanges().getEndSeq())
-      {
-        ap.scrollUp(false);
-      }
-      if (!av.getWrapAlignment())
-      {
-        HiddenColumns hidden = av.getAlignment().getHiddenColumns();
-        while (seqCanvas.cursorX < hidden.adjustForHiddenColumns(av
-                .getRanges().getStartRes()))
-        {
-          if (!ap.scrollRight(false))
-          {
-            break;
-          }
-        }
-        while (seqCanvas.cursorX > hidden.adjustForHiddenColumns(av
-                .getRanges().getEndRes()))
-        {
-          if (!ap.scrollRight(true))
-          {
-            break;
-          }
-        }
-      }
+      av.getRanges().scrollToVisible(seqCanvas.cursorX, seqCanvas.cursorY);
     }
     setStatusMessage(av.getAlignment().getSequenceAt(seqCanvas.cursorY),
             seqCanvas.cursorX, seqCanvas.cursorY);
@@ -590,6 +564,7 @@ public class SeqPanel extends JPanel implements MouseListener,
   @Override
   public void mouseReleased(MouseEvent evt)
   {
+    boolean didDrag = mouseDragging; // did we come here after a drag
     mouseDragging = false;
     mouseWheelPressed = false;
 
@@ -602,7 +577,7 @@ public class SeqPanel extends JPanel implements MouseListener,
 
     if (!editingSeqs)
     {
-      doMouseReleasedDefineMode(evt);
+      doMouseReleasedDefineMode(evt, didDrag);
       return;
     }
 
@@ -696,17 +671,16 @@ public class SeqPanel extends JPanel implements MouseListener,
 
     if (av.isFollowHighlight())
     {
-      /*
-       * if scrollToPosition requires a scroll adjustment, this flag prevents
-       * another scroll event being propagated back to the originator
-       * 
-       * @see AlignmentPanel#adjustmentValueChanged
-       */
-      ap.setDontScrollComplement(true);
+      // don't allow highlight of protein/cDNA to also scroll a complementary
+      // panel,as this sets up a feedback loop (scrolling panel 1 causes moused
+      // over residue to change abruptly, causing highlighted residue in panel 2
+      // to change, causing a scroll in panel 1 etc)
+      ap.setToScrollComplementPanel(false);
       if (ap.scrollToPosition(results, false))
       {
         seqCanvas.revalidate();
       }
+      ap.setToScrollComplementPanel(true);
     }
     setStatusMessage(results);
     seqCanvas.highlightSearchResults(results);
@@ -758,8 +732,9 @@ public class SeqPanel extends JPanel implements MouseListener,
     /*
      * set status bar message, returning residue position in sequence
      */
+    boolean isGapped = Comparison.isGap(sequence.getCharAt(column));
     final int pos = setStatusMessage(sequence, column, seq);
-    if (ssm != null && pos > -1)
+    if (ssm != null && !isGapped)
     {
       mouseOverSequence(sequence, column, pos);
     }
@@ -788,10 +763,19 @@ public class SeqPanel extends JPanel implements MouseListener,
       }
     }
 
+    /*
+     * add any features at the position to the tooltip; if over a gap, only
+     * add features that straddle the gap (pos may be the residue before or
+     * after the gap)
+     */
     if (av.isShowSequenceFeatures())
     {
       List<SequenceFeature> features = ap.getFeatureRenderer()
               .findFeaturesAtRes(sequence.getDatasetSequence(), pos);
+      if (isGapped)
+      {
+        removeAdjacentFeatures(features, column + 1, sequence);
+      }
       seqARep.appendFeatures(tooltipText, pos, features,
               this.ap.getSeqPanel().seqCanvas.fr.getMinMax());
     }
@@ -816,6 +800,35 @@ public class SeqPanel extends JPanel implements MouseListener,
 
   }
 
+  /**
+   * Removes from the list of features any that start after, or end before, the
+   * given column position. This allows us to retain only those features
+   * adjacent to a gapped position that straddle the position. Contact features
+   * that 'straddle' the position are also removed, since they are not 'at' the
+   * position.
+   * 
+   * @param features
+   * @param column
+   *          alignment column (1..)
+   * @param sequence
+   */
+  protected void removeAdjacentFeatures(List<SequenceFeature> features,
+          final int column, SequenceI sequence)
+  {
+    // TODO should this be an AlignViewController method (and reused by applet)?
+    ListIterator<SequenceFeature> it = features.listIterator();
+    while (it.hasNext())
+    {
+      SequenceFeature sf = it.next();
+      if (sf.isContactFeature()
+              || sequence.findIndex(sf.getBegin()) > column
+              || sequence.findIndex(sf.getEnd()) < column)
+      {
+        it.remove();
+      }
+    }
+  }
+
   private Point lastp = null;
 
   /*
@@ -860,8 +873,10 @@ public class SeqPanel extends JPanel implements MouseListener,
 
   /**
    * Sets the status message in alignment panel, showing the sequence number
-   * (index) and id, residue and residue position for the given sequence and
-   * column position. Returns the calculated residue position in the sequence.
+   * (index) and id, and residue and residue position if not at a gap, for the
+   * given sequence and column position. Returns the residue position returned
+   * by Sequence.findPosition. Note this may be for the nearest adjacent residue
+   * if at a gapped position.
    * 
    * @param sequence
    *          aligned sequence object
@@ -869,7 +884,8 @@ public class SeqPanel extends JPanel implements MouseListener,
    *          alignment column
    * @param seq
    *          index of sequence in alignment
-   * @return position of res in sequence
+   * @return sequence position of residue at column, or adjacent residue if at a
+   *         gap
    */
   int setStatusMessage(SequenceI sequence, final int column, int seq)
   {
@@ -883,36 +899,34 @@ public class SeqPanel extends JPanel implements MouseListener,
             .append(sequence.getName());
 
     String residue = null;
+
     /*
      * Try to translate the display character to residue name (null for gap).
      */
     final String displayChar = String.valueOf(sequence.getCharAt(column));
-    if (av.getAlignment().isNucleotide())
+    boolean isGapped = Comparison.isGap(sequence.getCharAt(column));
+    int pos = sequence.findPosition(column);
+
+    if (!isGapped)
     {
-      residue = ResidueProperties.nucleotideName.get(displayChar);
-      if (residue != null)
+      boolean nucleotide = av.getAlignment().isNucleotide();
+      if (nucleotide)
       {
-        text.append(" Nucleotide: ").append(residue);
+        residue = ResidueProperties.nucleotideName.get(displayChar);
       }
-    }
-    else
-    {
-      residue = "X".equalsIgnoreCase(displayChar) ? "X" : ("*"
-              .equals(displayChar) ? "STOP" : ResidueProperties.aa2Triplet
-              .get(displayChar));
-      if (residue != null)
+      else
       {
-        text.append(" Residue: ").append(residue);
+        residue = "X".equalsIgnoreCase(displayChar) ? "X" : ("*"
+                .equals(displayChar) ? "STOP"
+                : ResidueProperties.aa2Triplet.get(displayChar));
       }
-    }
+      text.append(" ").append(nucleotide ? "Nucleotide" : "Residue")
+              .append(": ").append(residue == null ? displayChar : residue);
 
-    int pos = -1;
-    pos = sequence.findPosition(column);
-    if (residue != null)
-    {
       text.append(" (").append(Integer.toString(pos)).append(")");
     }
     ap.alignFrame.statusBar.setText(text.toString());
+
     return pos;
   }
 
@@ -1552,9 +1566,20 @@ public class SeqPanel extends JPanel implements MouseListener,
         av.setSelectionGroup(null);
       }
 
+      int column = findColumn(evt);
+      boolean isGapped = Comparison.isGap(sequence.getCharAt(column));
+
+      /*
+       * find features at the position (if not gapped), or straddling
+       * the position (if at a gap)
+       */
       List<SequenceFeature> features = seqCanvas.getFeatureRenderer()
               .findFeaturesAtRes(sequence.getDatasetSequence(),
-                      sequence.findPosition(findColumn(evt)));
+                      sequence.findPosition(column));
+      if (isGapped)
+      {
+        removeAdjacentFeatures(features, column, sequence);
+      }
 
       if (!features.isEmpty())
       {
@@ -1586,23 +1611,23 @@ public class SeqPanel extends JPanel implements MouseListener,
     {
       if (e.isShiftDown())
       {
-        ap.scrollRight(true);
+        av.getRanges().scrollRight(true);
 
       }
       else
       {
-        ap.scrollUp(false);
+        av.getRanges().scrollUp(false);
       }
     }
     else
     {
       if (e.isShiftDown())
       {
-        ap.scrollRight(false);
+        av.getRanges().scrollRight(false);
       }
       else
       {
-        ap.scrollUp(true);
+        av.getRanges().scrollUp(true);
       }
     }
     // TODO Update tooltip for new position.
@@ -1737,7 +1762,7 @@ public class SeqPanel extends JPanel implements MouseListener,
     List<SequenceFeature> allFeatures = ap.getFeatureRenderer()
             .findFeaturesAtRes(sequence.getDatasetSequence(),
                     sequence.findPosition(res));
-    List<String> links = new ArrayList<String>();
+    List<String> links = new ArrayList<>();
     for (SequenceFeature sf : allFeatures)
     {
       if (sf.links != null)
@@ -1754,12 +1779,15 @@ public class SeqPanel extends JPanel implements MouseListener,
   }
 
   /**
-   * DOCUMENT ME!
+   * Update the display after mouse up on a selection or group
    * 
    * @param evt
-   *          DOCUMENT ME!
+   *          mouse released event details
+   * @param afterDrag
+   *          true if this event is happening after a mouse drag (rather than a
+   *          mouse down)
    */
-  public void doMouseReleasedDefineMode(MouseEvent evt)
+  public void doMouseReleasedDefineMode(MouseEvent evt, boolean afterDrag)
   {
     if (stretchGroup == null)
     {
@@ -1768,7 +1796,8 @@ public class SeqPanel extends JPanel implements MouseListener,
     // always do this - annotation has own state
     // but defer colourscheme update until hidden sequences are passed in
     boolean vischange = stretchGroup.recalcConservation(true);
-    needOverviewUpdate |= vischange && av.isSelectionDefinedGroup();
+    needOverviewUpdate |= vischange && av.isSelectionDefinedGroup()
+            && afterDrag;
     if (stretchGroup.cs != null)
     {
       stretchGroup.cs.alignmentChanged(stretchGroup,
@@ -1970,23 +1999,23 @@ public class SeqPanel extends JPanel implements MouseListener,
           if (mouseDragging && (evt.getY() < 0)
                   && (av.getRanges().getStartSeq() > 0))
           {
-            running = ap.scrollUp(true);
+            running = av.getRanges().scrollUp(true);
           }
 
           if (mouseDragging && (evt.getY() >= getHeight())
                   && (av.getAlignment().getHeight() > av.getRanges()
                           .getEndSeq()))
           {
-            running = ap.scrollUp(false);
+            running = av.getRanges().scrollUp(false);
           }
 
           if (mouseDragging && (evt.getX() < 0))
           {
-            running = ap.scrollRight(false);
+            running = av.getRanges().scrollRight(false);
           }
           else if (mouseDragging && (evt.getX() >= getWidth()))
           {
-            running = ap.scrollRight(true);
+            running = av.getRanges().scrollRight(true);
           }
         }
 
@@ -2022,11 +2051,13 @@ public class SeqPanel extends JPanel implements MouseListener,
         ap.getCalculationDialog().validateCalcTypes();
       }
 
-      // process further ?
-      if (!av.followSelection)
-      {
-        return;
-      }
+      return;
+    }
+
+    // process further ?
+    if (!av.followSelection)
+    {
+      return;
     }
 
     /*
index e37627d..e73ce07 100644 (file)
@@ -919,7 +919,7 @@ public abstract class StructureViewerBase extends GStructureViewer
       {
         // TODO: cope with multiple PDB files in view
         in = new BufferedReader(
-                new FileReader(getBinding().getPdbFile()[0]));
+                new FileReader(getBinding().getStructureFiles()[0]));
         File outFile = chooser.getSelectedFile();
   
         PrintWriter out = new PrintWriter(new FileOutputStream(outFile));
@@ -991,7 +991,7 @@ public abstract class StructureViewerBase extends GStructureViewer
      * enable 'Superpose with' if more than one mapped structure
      */
     viewSelectionMenu.setEnabled(false);
-    if (getBinding().getPdbFile().length > 1
+    if (getBinding().getStructureFiles().length > 1
             && getBinding().getSequence().length > 1)
     {
       viewSelectionMenu.setEnabled(true);
index c5a80e3..907ff46 100755 (executable)
@@ -407,15 +407,26 @@ public class AppletFormatAdapter
     return null;
   }
 
-  public static DataSourceType checkProtocol(String file)
+  /**
+   * Determines the protocol (i.e DataSourceType.{FILE|PASTE|URL}) for the input
+   * data
+   *
+   * @param data
+   * @return the protocol for the input data
+   */
+  public static DataSourceType checkProtocol(String data)
   {
-    DataSourceType protocol = DataSourceType.FILE;
-    String ft = file.toLowerCase().trim();
+    DataSourceType protocol = DataSourceType.PASTE;
+    String ft = data.toLowerCase().trim();
     if (ft.indexOf("http:") == 0 || ft.indexOf("https:") == 0
             || ft.indexOf("file:") == 0)
     {
       protocol = DataSourceType.URL;
     }
+    else if (new File(data).exists())
+    {
+      protocol = DataSourceType.FILE;
+    }
     return protocol;
   }
 
index 7c6d181..9d5fd93 100755 (executable)
@@ -39,7 +39,10 @@ import jalview.json.binding.biojson.v1.ColourSchemeMapper;
 import jalview.schemes.ColourSchemeI;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
+import jalview.ws.utils.UrlDownloadClient;
 
+import java.io.File;
+import java.io.IOException;
 import java.util.StringTokenizer;
 import java.util.Vector;
 
@@ -205,6 +208,12 @@ public class FileLoader implements Runnable
       // refer to it as.
       return;
     }
+    if (file != null
+            && file.indexOf(System.getProperty("java.io.tmpdir")) > -1)
+    {
+      // ignore files loaded from the system's temporary directory
+      return;
+    }
     String type = protocol == DataSourceType.FILE ? "RECENT_FILE"
             : "RECENT_URL";
 
@@ -325,9 +334,27 @@ public class FileLoader implements Runnable
 
             // open a new source and read from it
             FormatAdapter fa = new FormatAdapter();
-            al = fa.readFile(file, protocol, format);
-            source = fa.getAlignFile(); // keep reference for later if
-                                        // necessary.
+            boolean downloadStructureFile = format.isStructureFile()
+                    && protocol.equals(DataSourceType.URL);
+            if (downloadStructureFile)
+            {
+              String structExt = format.getExtensions().split(",")[0];
+              String urlLeafName = file.substring(file.lastIndexOf(System
+                      .getProperty("file.separator")), file
+                      .lastIndexOf("."));
+              String tempStructureFileStr = createNamedJvTempFile(
+                      urlLeafName, structExt);
+              UrlDownloadClient.download(file, tempStructureFileStr);
+              al = fa.readFile(tempStructureFileStr, DataSourceType.FILE,
+                      format);
+              source = fa.getAlignFile();
+            }
+            else
+            {
+              al = fa.readFile(file, protocol, format);
+              source = fa.getAlignFile(); // keep reference for later if
+                                          // necessary.
+            }
           }
         } catch (java.io.IOException ex)
         {
@@ -556,6 +583,29 @@ public class FileLoader implements Runnable
 
   }
 
+  /**
+   * This method creates the file -
+   * {tmpdir}/jalview/{current_timestamp}/fileName.exetnsion using the supplied
+   * file name and extension
+   * 
+   * @param fileName
+   *          the name of the temp file to be created
+   * @param extension
+   *          the extension of the temp file to be created
+   * @return
+   */
+  private static String createNamedJvTempFile(String fileName,
+          String extension) throws IOException
+  {
+    String seprator = System.getProperty("file.separator");
+    String jvTempDir = System.getProperty("java.io.tmpdir") + "jalview"
+            + seprator + System.currentTimeMillis();
+    File tempStructFile = new File(jvTempDir + seprator + fileName + "."
+            + extension);
+    tempStructFile.mkdirs();
+    return tempStructFile.toString();
+  }
+
   /*
    * (non-Javadoc)
    * 
index 7fe17c8..ab220f0 100644 (file)
@@ -406,7 +406,8 @@ public abstract class StructureFile extends AlignFile
    * make a friendly ID string.
    * 
    * @param dataName
-   * @return truncated dataName to after last '/'
+   * @return truncated dataName to after last '/' and pruned .extension if
+   *         present
    */
   protected String safeName(String dataName)
   {
@@ -415,6 +416,9 @@ public abstract class StructureFile extends AlignFile
     {
       dataName = dataName.substring(p + 1);
     }
+    if(dataName.indexOf(".") > -1){
+      dataName = dataName.substring(0, dataName.lastIndexOf("."));
+    }
     return dataName;
   }
 
index 7580222..c390b17 100644 (file)
@@ -126,7 +126,7 @@ public class MouseOverStructureListener extends JSFunctionExec implements
   }
 
   @Override
-  public String[] getPdbFile()
+  public String[] getStructureFiles()
   {
     return modelSet;
   }
index e5c5d04..9fde3f1 100644 (file)
@@ -31,7 +31,7 @@ public interface StructureListener
    * handles messages for, or null if generic listener (only used by
    * removeListener method)
    */
-  public String[] getPdbFile();
+  public String[] getStructureFiles();
 
   /**
    * Called by StructureSelectionManager to inform viewer to highlight given
index 72da7ae..db0b47e 100644 (file)
@@ -36,6 +36,7 @@ import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceI;
 import jalview.ext.jmol.JmolParser;
 import jalview.gui.IProgressIndicator;
+import jalview.io.AppletFormatAdapter;
 import jalview.io.DataSourceType;
 import jalview.io.StructureFile;
 import jalview.util.MappingUtils;
@@ -385,6 +386,7 @@ public class StructureSelectionManager
     boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
     try
     {
+      sourceType = AppletFormatAdapter.checkProtocol(pdbFile);
       pdb = new JmolParser(pdbFile, sourceType);
 
       if (pdb.getId() != null && pdb.getId().trim().length() > 0
@@ -740,7 +742,7 @@ public class StructureSelectionManager
       if (listeners.elementAt(i) instanceof StructureListener)
       {
         sl = (StructureListener) listeners.elementAt(i);
-        for (String pdbfile : sl.getPdbFile())
+        for (String pdbfile : sl.getStructureFiles())
         {
           pdbs.remove(pdbfile);
         }
index b336e45..1637631 100644 (file)
@@ -532,7 +532,7 @@ public abstract class AAStructureBindingModel extends
           BitSet matched, SuperposeData[] structures)
   {
     int refStructure = -1;
-    String[] files = getPdbFile();
+    String[] files = getStructureFiles();
     if (files == null)
     {
       return -1;
@@ -756,7 +756,7 @@ public abstract class AAStructureBindingModel extends
     {
       return;
     }
-    String[] files = getPdbFile();
+    String[] files = getStructureFiles();
   
     SequenceRenderer sr = getSequenceRenderer(alignmentv);
   
index cdf0758..60cee46 100644 (file)
@@ -92,9 +92,9 @@ public abstract class AlignmentViewport implements AlignViewportI,
 
   FeaturesDisplayedI featuresDisplayed = null;
 
-  protected Deque<CommandI> historyList = new ArrayDeque<CommandI>();
+  protected Deque<CommandI> historyList = new ArrayDeque<>();
 
-  protected Deque<CommandI> redoList = new ArrayDeque<CommandI>();
+  protected Deque<CommandI> redoList = new ArrayDeque<>();
 
   /**
    * alignment displayed in the viewport. Please use get/setter
@@ -1113,7 +1113,6 @@ public abstract class AlignmentViewport implements AlignViewportI,
   public void setHiddenColumns(HiddenColumns hidden)
   {
     this.alignment.setHiddenColumns(hidden);
-    // this.colSel = colsel;
   }
 
   @Override
@@ -1298,7 +1297,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
 
   protected boolean showOccupancy = true;
 
-  private Map<SequenceI, Color> sequenceColours = new HashMap<SequenceI, Color>();
+  private Map<SequenceI, Color> sequenceColours = new HashMap<>();
 
   protected SequenceAnnotationOrder sortAnnotationsBy = null;
 
@@ -1528,7 +1527,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
 
     if (hiddenRepSequences == null)
     {
-      hiddenRepSequences = new Hashtable<SequenceI, SequenceCollectionI>();
+      hiddenRepSequences = new Hashtable<>();
     }
 
     hiddenRepSequences.put(repSequence, sg);
@@ -1736,7 +1735,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
   @Override
   public List<int[]> getVisibleRegionBoundaries(int min, int max)
   {
-    ArrayList<int[]> regions = new ArrayList<int[]>();
+    ArrayList<int[]> regions = new ArrayList<>();
     int start = min;
     int end = max;
 
@@ -1779,7 +1778,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
   public List<AlignmentAnnotation> getVisibleAlignmentAnnotation(
           boolean selectedOnly)
   {
-    ArrayList<AlignmentAnnotation> ala = new ArrayList<AlignmentAnnotation>();
+    ArrayList<AlignmentAnnotation> ala = new ArrayList<>();
     AlignmentAnnotation[] aa;
     if ((aa = alignment.getAlignmentAnnotation()) != null)
     {
@@ -2133,7 +2132,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
     // intersect alignment annotation with alignment groups
 
     AlignmentAnnotation[] aan = alignment.getAlignmentAnnotation();
-    List<SequenceGroup> oldrfs = new ArrayList<SequenceGroup>();
+    List<SequenceGroup> oldrfs = new ArrayList<>();
     if (aan != null)
     {
       for (int an = 0; an < aan.length; an++)
@@ -2846,8 +2845,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
         selectionIsDefinedGroup = gps.contains(selectionGroup);
       }
     }
-    return selectionGroup.getContext() == alignment
-            || selectionIsDefinedGroup;
+    return selectionGroup.isDefined() || selectionIsDefinedGroup;
   }
 
   /**
index a837d53..d2912d8 100644 (file)
@@ -31,24 +31,41 @@ import java.awt.Graphics;
 public abstract class OverviewDimensions
 {
   protected static final int MAX_WIDTH = 400;
+
   protected static final int MIN_WIDTH = 120;
+
   protected static final int MIN_SEQ_HEIGHT = 40;
+
   protected static final int MAX_SEQ_HEIGHT = 300;
 
   private static final int DEFAULT_GRAPH_HEIGHT = 20;
 
   protected int width;
+
   protected int sequencesHeight;
+
   protected int graphHeight = DEFAULT_GRAPH_HEIGHT;
+
   protected int boxX = -1;
+
   protected int boxY = -1;
+
   protected int boxWidth = -1;
+
   protected int boxHeight = -1;
-  protected int scrollCol = -1;
-  protected int scrollRow = -1;
+
   protected int alwidth;
+
   protected int alheight;
 
+  /**
+   * Create an OverviewDimensions object
+   * 
+   * @param ranges
+   *          positional properties of the viewport
+   * @param showAnnotationPanel
+   *          true if the annotation panel is to be shown, false otherwise
+   */
   public OverviewDimensions(ViewportRanges ranges,
           boolean showAnnotationPanel)
   {
@@ -97,16 +114,6 @@ public abstract class OverviewDimensions
     g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);
   }
 
-  public int getScrollCol()
-  {
-    return scrollCol;
-  }
-
-  public int getScrollRow()
-  {
-    return scrollRow;
-  }
-
   public int getBoxX()
   {
     return boxX;
@@ -218,8 +225,8 @@ public abstract class OverviewDimensions
    */
   protected abstract void resetAlignmentDims();
 
-  protected void setBoxPosition(int startRes, int endRes, int startSeq,
-          int endSeq)
+  protected void setBoxPosition(int startRes, int startSeq, int vpwidth,
+          int vpheight)
   {
     resetAlignmentDims();
 
@@ -228,12 +235,9 @@ public abstract class OverviewDimensions
     boxY = Math.round((float) startSeq * sequencesHeight / alheight);
 
     // boxWidth is the width in residues translated to pixels
-    // since the box includes both the start and end residues, add 1 to the
-    // difference
-    boxWidth = Math
-            .round((float) (endRes - startRes + 1) * width / alwidth);
+    boxWidth = Math.round((float) vpwidth * width / alwidth);
+
     // boxHeight is the height in sequences translated to pixels
-    boxHeight = Math.round((float) (endSeq - startSeq + 1)
-            * sequencesHeight / alheight);
+    boxHeight = Math.round((float) vpheight * sequencesHeight / alheight);
   }
 }
\ No newline at end of file
index b03f9ac..4bf7694 100644 (file)
@@ -51,20 +51,20 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions
     int xAsRes = Math.round((float) x * alwidth / width);
 
     // get viewport width in residues
-    int vpwidth = ranges.getEndRes() - ranges.getStartRes() + 1;
+    int vpwidth = ranges.getViewportWidth();
 
     if (xAsRes + vpwidth > alwidth)
     {
       // went past the end of the alignment, adjust backwards
 
       // if last position was before the end of the alignment, need to update
-      if ((scrollCol + vpwidth - 1) < alwidth)
+      if (ranges.getStartRes() < alwidth)
       {
         xAsRes = alwidth - vpwidth;
       }
       else
       {
-        xAsRes = scrollCol;
+        xAsRes = ranges.getStartRes();
       }
     }
 
@@ -78,24 +78,24 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions
 
     // get viewport height in sequences
     // add 1 because height includes both endSeq and startSeq
-    int vpheight = ranges.getEndSeq() - ranges.getStartSeq() + 1;
+    int vpheight = ranges.getViewportHeight();
 
     if (yAsSeq + vpheight > alheight)
     {
       // went past the end of the alignment, adjust backwards
-      if ((scrollRow + vpheight - 1) < alheight)
+      if (ranges.getEndSeq() < alheight)
       {
         yAsSeq = alheight - vpheight;
       }
       else
       {
-        yAsSeq = scrollRow;
+        yAsSeq = ranges.getStartSeq();
       }
     }
 
-    // update scroll values
-    scrollCol = xAsRes;
-    scrollRow = yAsSeq;
+    // update viewport
+    ranges.setStartRes(xAsRes);
+    ranges.setStartSeq(yAsSeq);
 
   }
 
@@ -103,15 +103,8 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions
   public void setBoxPosition(HiddenSequences hiddenSeqs,
           HiddenColumns hiddenCols)
   {
-    // work with visible values of startRes and endRes
-    int startRes = ranges.getStartRes();
-    int endRes = ranges.getEndRes();
-
-    // work with visible values of startSeq and endSeq
-    int startSeq = ranges.getStartSeq();
-    int endSeq = ranges.getEndSeq();
-
-    setBoxPosition(startRes, endRes, startSeq, endSeq);
+    setBoxPosition(ranges.getStartRes(), ranges.getStartSeq(),
+            ranges.getViewportWidth(), ranges.getViewportHeight());
   }
 
   @Override
index b897189..4b396a6 100644 (file)
@@ -93,7 +93,7 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions
     int xAsRes = Math.round((float) x * alwidth / width);
 
     // get viewport width in residues
-    int vpwidth = ranges.getEndRes() - ranges.getStartRes() + 1;
+    int vpwidth = ranges.getViewportWidth();
 
     // get where x should be when accounting for hidden cols
     // if x is in a hidden col region, shift to left - but we still need
@@ -108,14 +108,14 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions
       // went past the end of the alignment, adjust backwards
 
       // if last position was before the end of the alignment, need to update
-      if ((scrollCol + vpwidth - 1) < visAlignWidth)
+      if (ranges.getEndRes() < visAlignWidth)
       {
         visXAsRes = hiddenCols.findColumnPosition(hiddenCols
                 .subtractVisibleColumns(vpwidth - 1, alwidth - 1));
       }
       else
       {
-        visXAsRes = scrollCol;
+        visXAsRes = ranges.getStartRes();
       }
     }
 
@@ -127,8 +127,7 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions
     int yAsSeq = Math.round((float) y * alheight / sequencesHeight);
 
     // get viewport height in sequences
-    // add 1 because height includes both endSeq and startSeq
-    int vpheight = ranges.getEndSeq() - ranges.getStartSeq() + 1;
+    int vpheight = ranges.getViewportHeight();
 
     // get where y should be when accounting for hidden rows
     // if y is in a hidden row region, shift up - but we still need absolute
@@ -143,20 +142,20 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions
     if (visYAsSeq + vpheight - 1 > visAlignHeight)
     {
       // went past the end of the alignment, adjust backwards
-      if ((scrollRow + vpheight - 1) < visAlignHeight)
+      if (ranges.getEndSeq() < visAlignHeight)
       {
         visYAsSeq = hiddenSeqs.findIndexWithoutHiddenSeqs(hiddenSeqs
                 .subtractVisibleRows(vpheight - 1, alheight - 1));
       }
       else
       {
-        visYAsSeq = scrollRow;
+        visYAsSeq = ranges.getStartSeq();
       }
     }
 
-    // update scroll values
-    scrollCol = visXAsRes;
-    scrollRow = visYAsSeq;
+    // update viewport
+    ranges.setStartRes(visXAsRes);
+    ranges.setStartSeq(visYAsSeq);
 
   }
 
@@ -176,15 +175,15 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions
           HiddenColumns hiddenCols)
   {
     // work with absolute values of startRes and endRes
-    int startRes = hiddenCols
-            .adjustForHiddenColumns(ranges.getStartRes());
+    int startRes = hiddenCols.adjustForHiddenColumns(ranges.getStartRes());
     int endRes = hiddenCols.adjustForHiddenColumns(ranges.getEndRes());
 
     // work with absolute values of startSeq and endSeq
     int startSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getStartSeq());
     int endSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getEndSeq());
 
-    setBoxPosition(startRes, endRes, startSeq, endSeq);
+    setBoxPosition(startRes, startSeq, endRes - startRes + 1, endSeq
+            - startSeq + 1);
   }
 
   @Override
diff --git a/src/jalview/viewmodel/ViewportListenerI.java b/src/jalview/viewmodel/ViewportListenerI.java
new file mode 100644 (file)
index 0000000..555089e
--- /dev/null
@@ -0,0 +1,8 @@
+package jalview.viewmodel;
+
+import java.beans.PropertyChangeListener;
+
+public interface ViewportListenerI extends PropertyChangeListener
+{
+
+}
index 246806e..a78a1c0 100644 (file)
  */
 package jalview.viewmodel;
 
+import java.beans.PropertyChangeSupport;
+
 public abstract class ViewportProperties
 {
+  protected PropertyChangeSupport changeSupport = new PropertyChangeSupport(
+          this);
+
+  public void addPropertyChangeListener(ViewportListenerI listener)
+  {
+    changeSupport.addPropertyChangeListener(listener);
+  }
+
+  public void removePropertyChangeListener(ViewportListenerI listener)
+  {
+    changeSupport.removePropertyChangeListener(listener);
+  }
 
 }
index fc163e0..743d212 100644 (file)
 package jalview.viewmodel;
 
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
 
 /**
- * Embryonic class which: Supplies and updates viewport properties relating to
- * position such as: start and end residues and sequences; ideally will serve
- * hidden columns/rows too. Intention also to support calculations for
- * positioning, scrolling etc. such as finding the middle of the viewport,
+ * Slightly less embryonic class which: Supplies and updates viewport properties
+ * relating to position such as: start and end residues and sequences; ideally
+ * will serve hidden columns/rows too. Intention also to support calculations
+ * for positioning, scrolling etc. such as finding the middle of the viewport,
  * checking for scrolls off screen
  */
 public class ViewportRanges extends ViewportProperties
@@ -95,79 +96,163 @@ public class ViewportRanges extends ViewportProperties
   }
 
   /**
-   * Set first residue visible in the viewport
+   * Set first residue visible in the viewport, and retain the current width.
+   * Fires a property change event.
    * 
    * @param res
    *          residue position
    */
   public void setStartRes(int res)
   {
-    if (res > al.getWidth() - 1)
+    int width = getViewportWidth();
+    setStartEndRes(res, res + width - 1);
+  }
+
+  /**
+   * Set start and end residues at the same time. This method only fires one
+   * event for the two changes, and should be used in preference to separate
+   * calls to setStartRes and setEndRes.
+   * 
+   * @param start
+   *          the start residue
+   * @param end
+   *          the end residue
+   */
+  public void setStartEndRes(int start, int end)
+  {
+    int oldstartres = this.startRes;
+    if (start > getVisibleAlignmentWidth() - 1)
+    {
+      startRes = getVisibleAlignmentWidth() - 1;
+    }
+    else if (start < 0)
     {
-      res = al.getWidth() - 1;
+      startRes = 0;
     }
-    else if (res < 0)
+    else
     {
-      res = 0;
+      startRes = start;
+    }
+
+    int oldendres = this.endRes;
+    if (end < 0)
+    {
+      endRes = 0;
+    }
+    else if (end > getVisibleAlignmentWidth() - 1)
+    {
+      endRes = getVisibleAlignmentWidth() - 1;
+    }
+    else
+    {
+      endRes = end;
+    }
+
+    changeSupport.firePropertyChange("startres", oldstartres, startRes);
+    if (oldstartres == startRes)
+    {
+      // event won't be fired if start positions are same
+      // fire an event for the end positions in case they changed
+      changeSupport.firePropertyChange("endres", oldendres, endRes);
     }
-    this.startRes = res;
   }
 
   /**
-   * Set last residue visible in the viewport
+   * Set last residue visible in the viewport. Fires a property change event.
    * 
    * @param res
    *          residue position
    */
   public void setEndRes(int res)
   {
-    if (res >= al.getWidth())
+    int startres = res;
+    int width = getViewportWidth();
+    if (startres + width - 1 > getVisibleAlignmentWidth() - 1)
     {
-      res = al.getWidth() - 1;
+      startres = getVisibleAlignmentWidth() - width;
     }
-    else if (res < 0)
-    {
-      res = 0;
-    }
-    this.endRes = res;
+    setStartEndRes(startres - width + 1, startres);
   }
 
   /**
-   * Set the first sequence visible in the viewport
+   * Set the first sequence visible in the viewport, maintaining the height. If
+   * the viewport would extend past the last sequence, sets the viewport so it
+   * sits at the bottom of the alignment. Fires a property change event.
    * 
    * @param seq
    *          sequence position
    */
   public void setStartSeq(int seq)
   {
-    if (seq > al.getHeight() - 1)
+    int startseq = seq;
+    int height = getViewportHeight();
+    if (startseq + height - 1 > getVisibleAlignmentHeight() - 1)
+    {
+      startseq = getVisibleAlignmentHeight() - height;
+    }
+    setStartEndSeq(startseq, startseq + height - 1);
+  }
+
+  /**
+   * Set start and end sequences at the same time. The viewport height may
+   * change. This method only fires one event for the two changes, and should be
+   * used in preference to separate calls to setStartSeq and setEndSeq.
+   * 
+   * @param start
+   *          the start sequence
+   * @param end
+   *          the end sequence
+   */
+  public void setStartEndSeq(int start, int end)
+  {
+    int oldstartseq = this.startSeq;
+    if (start > getVisibleAlignmentHeight() - 1)
+    {
+      startSeq = getVisibleAlignmentHeight() - 1;
+    }
+    else if (start < 0)
+    {
+      startSeq = 0;
+    }
+    else
+    {
+      startSeq = start;
+    }
+
+    int oldendseq = this.endSeq;
+    if (end >= getVisibleAlignmentHeight())
+    {
+      endSeq = getVisibleAlignmentHeight() - 1;
+    }
+    else if (end < 0)
     {
-      seq = al.getHeight() - 1;
+      endSeq = 0;
     }
-    else if (seq < 0)
+    else
     {
-      seq = 0;
+      endSeq = end;
+    }
+
+    changeSupport.firePropertyChange("startseq", oldstartseq, startSeq);
+    if (oldstartseq == startSeq)
+    {
+      // event won't be fired if start positions are the same
+      // fire in case the end positions changed
+      changeSupport.firePropertyChange("endseq", oldendseq, endSeq);
     }
-    this.startSeq = seq;
   }
 
   /**
-   * Set the last sequence visible in the viewport
+   * Set the last sequence visible in the viewport. Fires a property change
+   * event.
    * 
    * @param seq
    *          sequence position
    */
   public void setEndSeq(int seq)
   {
-    if (seq >= al.getHeight())
-    {
-      seq = al.getHeight() - 1;
-    }
-    else if (seq < 0)
-    {
-      seq = 0;
-    }
-    this.endSeq = seq;
+    int height = getViewportHeight();
+    setStartEndSeq(seq - height + 1, seq);
   }
 
   /**
@@ -201,4 +286,234 @@ public class ViewportRanges extends ViewportProperties
   {
     return endSeq;
   }
+
+  /**
+   * Set viewport width in residues, without changing startRes. Use in
+   * preference to calculating endRes from the width, to avoid out by one
+   * errors! Fires a property change event.
+   * 
+   * @param w
+   *          width in residues
+   */
+  public void setViewportWidth(int w)
+  {
+    setStartEndRes(startRes, startRes + w - 1);
+  }
+
+  /**
+   * Set viewport height in residues, without changing startSeq. Use in
+   * preference to calculating endSeq from the height, to avoid out by one
+   * errors! Fires a property change event.
+   * 
+   * @param h
+   *          height in sequences
+   */
+  public void setViewportHeight(int h)
+  {
+    setStartEndSeq(startSeq, startSeq + h - 1);
+  }
+
+  /**
+   * Set viewport horizontal start position and width. Use in preference to
+   * calculating endRes from the width, to avoid out by one errors! Fires a
+   * property change event.
+   * 
+   * @param start
+   *          start residue
+   * @param w
+   *          width in residues
+   */
+  public void setViewportStartAndWidth(int start, int w)
+  {
+    int vpstart = start;
+    if (vpstart < 0)
+    {
+      vpstart = 0;
+    }
+    else if ((w <= getVisibleAlignmentWidth())
+            && (vpstart + w - 1 > getVisibleAlignmentWidth() - 1))
+    // viewport width is less than the full alignment and we are running off the
+    // RHS edge
+    {
+      vpstart = getVisibleAlignmentWidth() - w;
+    }
+    setStartEndRes(vpstart, vpstart + w - 1);
+  }
+
+  /**
+   * Set viewport vertical start position and height. Use in preference to
+   * calculating endSeq from the height, to avoid out by one errors! Fires a
+   * property change event.
+   * 
+   * @param start
+   *          start sequence
+   * @param h
+   *          height in sequences
+   */
+  public void setViewportStartAndHeight(int start, int h)
+  {
+    int vpstart = start;
+    if (vpstart < 0)
+    {
+      vpstart = 0;
+    }
+    else if ((h <= getVisibleAlignmentHeight())
+            && (vpstart + h - 1 > getVisibleAlignmentHeight() - 1))
+    // viewport height is less than the full alignment and we are running off
+    // the bottom
+    {
+      vpstart = getVisibleAlignmentHeight() - h;
+    }
+    setStartEndSeq(vpstart, vpstart + h - 1);
+  }
+
+  /**
+   * Get width of viewport in residues
+   * 
+   * @return width of viewport
+   */
+  public int getViewportWidth()
+  {
+    return (endRes - startRes + 1);
+  }
+
+  /**
+   * Get height of viewport in residues
+   * 
+   * @return height of viewport
+   */
+  public int getViewportHeight()
+  {
+    return (endSeq - startSeq + 1);
+  }
+
+  /**
+   * Scroll the viewport range vertically. Fires a property change event.
+   * 
+   * @param up
+   *          true if scrolling up, false if down
+   * 
+   * @return true if the scroll is valid
+   */
+  public boolean scrollUp(boolean up)
+  {
+    if (up)
+    {
+      if (startSeq < 1)
+      {
+        return false;
+      }
+
+      setStartSeq(startSeq - 1);
+    }
+    else
+    {
+      if (endSeq >= getVisibleAlignmentHeight() - 1)
+      {
+        return false;
+      }
+
+      setStartSeq(startSeq + 1);
+    }
+    return true;
+  }
+
+  /**
+   * Scroll the viewport range horizontally. Fires a property change event.
+   * 
+   * @param right
+   *          true if scrolling right, false if left
+   * 
+   * @return true if the scroll is valid
+   */
+  public boolean scrollRight(boolean right)
+  {
+    if (!right)
+    {
+      if (startRes < 1)
+      {
+        return false;
+      }
+
+      setStartRes(startRes - 1);
+    }
+    else
+    {
+      if (endRes >= getVisibleAlignmentWidth() - 1)
+      {
+        return false;
+      }
+
+      setStartRes(startRes + 1);
+    }
+
+    return true;
+  }
+
+  /**
+   * Scroll a wrapped alignment so that the specified residue is visible. Fires
+   * a property change event.
+   * 
+   * @param res
+   *          residue position to scroll to
+   */
+  public void scrollToWrappedVisible(int res)
+  {
+    // get the start residue of the wrapped row which res is in
+    // and set that as our start residue
+    int width = getViewportWidth();
+    setStartRes((res / width) * width);
+  }
+
+  /**
+   * Scroll so that (x,y) is visible. Fires a property change event.
+   * 
+   * @param x
+   *          x position in alignment
+   * @param y
+   *          y position in alignment
+   */
+  public void scrollToVisible(int x, int y)
+  {
+    while (y < startSeq)
+    {
+      scrollUp(true);
+    }
+    while (y > endSeq)
+    {
+      scrollUp(false);
+    }
+
+    HiddenColumns hidden = al.getHiddenColumns();
+    while (x < hidden.adjustForHiddenColumns(startRes))
+    {
+      if (!scrollRight(false))
+      {
+        break;
+      }
+    }
+    while (x > hidden.adjustForHiddenColumns(endRes))
+    {
+      if (!scrollRight(true))
+      {
+        break;
+      }
+    }
+  }
+  
+  /**
+   * Adjust sequence position for page up. Fires a property change event.
+   */
+  public void pageUp()
+  {
+    setViewportStartAndHeight(2 * startSeq - endSeq, getViewportHeight());
+  }
+  
+  /**
+   * Adjust sequence position for page down. Fires a property change event.
+   */
+  public void pageDown()
+  {
+    setViewportStartAndHeight(endSeq, getViewportHeight());
+  }
 }
diff --git a/src/jalview/ws/jws2/JPred301Client.java b/src/jalview/ws/jws2/JPred301Client.java
deleted file mode 100644 (file)
index c15f256..0000000
+++ /dev/null
@@ -1,299 +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.
- */
-package jalview.ws.jws2;
-
-import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.Annotation;
-import jalview.gui.AlignFrame;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
-import jalview.ws.params.ArgumentI;
-import jalview.ws.params.OptionI;
-import jalview.ws.params.WsParamSetI;
-import jalview.ws.uimodel.AlignAnalysisUIText;
-
-import java.awt.Color;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import compbio.data.sequence.FastaSequence;
-import compbio.data.sequence.JpredAlignment;
-import compbio.metadata.Argument;
-
-public class JPred301Client extends JabawsMsaInterfaceAlignCalcWorker
-{
-  /**
-   * 
-   * @return default args for this service when run as dynamic web service
-   */
-  public List<Argument> selectDefaultArgs()
-  {
-    List<ArgumentI> rgs = new ArrayList<ArgumentI>();
-    for (ArgumentI argi : service.getParamStore().getServiceParameters())
-    {
-      if (argi instanceof OptionI)
-      {
-        List<String> o = ((OptionI) argi).getPossibleValues();
-        if (o.contains("-pred-nohits"))
-        {
-          OptionI cpy = ((OptionI) argi).copy();
-          cpy.setValue("-pred-nohits");
-          rgs.add(cpy);
-        }
-      }
-    }
-    return JabaParamStore.getJabafromJwsArgs(rgs);
-  }
-
-  public JPred301Client(Jws2Instance service, AlignFrame alignFrame,
-          WsParamSetI preset, List<Argument> paramset)
-  {
-    super(service, alignFrame, preset, paramset);
-    submitGaps = true;
-    alignedSeqs = true;
-    nucleotidesAllowed = false;
-    proteinAllowed = true;
-    gapMap = new boolean[0];
-    updateParameters(null, selectDefaultArgs());
-  }
-
-  @Override
-  boolean checkValidInputSeqs(boolean dynamic, List<FastaSequence> seqs)
-  {
-    return (seqs.size() > 1);
-  }
-
-  @Override
-  public String getServiceActionText()
-  {
-    return "calculating consensus secondary structure prediction using JPred service";
-  }
-
-  private static Map<String, String[]> jpredRowLabels = new HashMap<String, String[]>();
-
-  private static final Set<String> jpredRes_graph;
-
-  private static final Set<String> jpredRes_ssonly;
-  static
-  {
-    jpredRes_ssonly = new HashSet<String>();
-    jpredRes_ssonly.add("jnetpred".toLowerCase());
-    jpredRes_ssonly.add("jnetpssm".toLowerCase());
-    jpredRes_ssonly.add("jnethmm".toLowerCase());
-    jpredRes_graph = new HashSet<String>();
-    jpredRes_graph.add("jnetconf".toLowerCase());
-    jpredRes_graph.add("jnet burial".toLowerCase());
-  }
-
-  /**
-   * update the consensus annotation from the sequence profile data using
-   * current visualization settings.
-   */
-  @Override
-  public void updateResultAnnotation(boolean immediate)
-  {
-    if (immediate || !calcMan.isWorking(this) && msascoreset != null)
-    {
-      if (msascoreset instanceof compbio.data.sequence.JpredAlignment)
-      {
-        JpredAlignment jpres = (JpredAlignment) msascoreset;
-        int alWidth = alignViewport.getAlignment().getWidth();
-        ArrayList<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
-        char[] sol = new char[jpres.getJpredSequences().get(0).getLength()];
-        boolean firstsol = true;
-        for (FastaSequence fsq : jpres.getJpredSequences())
-        {
-          String[] k = jpredRowLabels.get(fsq.getId());
-          if (k == null)
-          {
-            k = new String[] { fsq.getId(), "JNet Output" };
-          }
-          if (fsq.getId().startsWith("JNETSOL"))
-          {
-            char amnt = (fsq.getId().endsWith("25") ? "3" : fsq.getId()
-                    .endsWith("5") ? "6" : "9").charAt(0);
-            char[] vseq = fsq.getSequence().toCharArray();
-            for (int spos = 0, sposL = fsq.getLength(); spos < sposL; spos++)
-            {
-              if (firstsol)
-              {
-                sol[spos] = '0';
-              }
-              if (vseq[spos] == 'B'
-                      && (sol[spos] == '0' || sol[spos] < amnt))
-              {
-                sol[spos] = amnt;
-              }
-            }
-            firstsol = false;
-          }
-          else
-          {
-            createAnnotationRowFromString(
-                    ourAnnot,
-                    getCalcId(),
-                    alWidth,
-                    k[0],
-                    k[1],
-                    jpredRes_graph.contains(fsq.getId()) ? AlignmentAnnotation.BAR_GRAPH
-                            : AlignmentAnnotation.NO_GRAPH, 0f, 9f,
-                    fsq.getSequence());
-          }
-
-        }
-        createAnnotationRowFromString(
-                ourAnnot,
-                getCalcId(),
-                alWidth,
-                "Jnet Burial",
-                "<html>Prediction of Solvent Accessibility<br/>levels are<ul><li>0 - Exposed</li><li>3 - 25% or more S.A. accessible</li><li>6 - 5% or more S.A. accessible</li><li>9 - Buried (<5% exposed)</li></ul>",
-                AlignmentAnnotation.BAR_GRAPH, 0f, 9f, new String(sol));
-        for (FastaSequence fsq : jpres.getSequences())
-        {
-          if (fsq.getId().equalsIgnoreCase("QUERY"))
-          {
-            createAnnotationRowFromString(ourAnnot, getCalcId(), alWidth,
-                    "Query", "JPred Reference Sequence",
-                    AlignmentAnnotation.NO_GRAPH, 0f, 0f, fsq.getSequence());
-          }
-        }
-        if (ourAnnot.size() > 0)
-        {
-          updateOurAnnots(ourAnnot);
-        }
-      }
-    }
-  }
-
-  private void createAnnotationRowFromString(
-          ArrayList<AlignmentAnnotation> ourAnnot, String calcId,
-          int alWidth, String label, String descr, int rowType, float min,
-          float max, String jpredPrediction)
-  {
-    // simple annotation row
-    AlignmentAnnotation annotation = alignViewport.getAlignment()
-            .findOrCreateAnnotation(label, calcId, true, null, null);
-    if (alWidth == gapMap.length) // scr.getScores().size())
-    {
-      annotation.label = new String(label);
-      annotation.description = new String(descr);
-      annotation.graph = rowType;
-      annotation.graphMin = min;
-      annotation.graphMax = max;
-      if (constructAnnotationFromString(annotation, jpredPrediction,
-              alWidth, rowType))
-      {
-        // created a valid annotation from the data
-        ourAnnot.add(annotation);
-        // annotation.validateRangeAndDisplay();
-      }
-    }
-  }
-
-  private boolean constructAnnotationFromString(
-          AlignmentAnnotation annotation, String sourceData, int alWidth,
-          int rowType)
-  {
-    if (sourceData.length() == 0 && alWidth > 0)
-    {
-      return false;
-    }
-    Annotation[] elm = new Annotation[alWidth];
-    boolean ssOnly = jpredRes_ssonly.contains(annotation.label
-            .toLowerCase());
-    boolean graphOnly = rowType != AlignmentAnnotation.NO_GRAPH;
-    if (!ssOnly && !graphOnly)
-    {
-      // for burial 'B'
-      annotation.showAllColLabels = true;
-    }
-
-    for (int i = 0, iSize = sourceData.length(); i < iSize; i++)
-    {
-      char annot = sourceData.charAt(i);
-      // if we're at a gapped column then skip to next ungapped position
-      if (gapMap != null && gapMap.length > 0)
-      {
-        while (!gapMap[i])
-        {
-          elm[i++] = new Annotation("", "", ' ', Float.NaN);
-        }
-      }
-      switch (rowType)
-      {
-      case AlignmentAnnotation.NO_GRAPH:
-        elm[i] = ssOnly ? new Annotation("", "", annot, Float.NaN,
-                colourSS(annot)) : new Annotation("" + annot, "" + annot,
-                '\0', Float.NaN);
-        break;
-      default:
-        try
-        {
-          elm[i] = new Annotation("" + annot, "" + annot, annot,
-                  Integer.valueOf("" + annot));
-        } catch (Exception x)
-        {
-          System.err.println("Expected numeric value in character '"
-                  + annot + "'");
-        }
-      }
-    }
-
-    annotation.annotations = elm;
-    annotation.belowAlignment = true;
-    annotation.validateRangeAndDisplay();
-    return true;
-  }
-
-  private Color colourSS(char annot)
-  {
-    switch (annot)
-    {
-    case 'H':
-      return jalview.renderer.AnnotationRenderer.HELIX_COLOUR;
-    case 'E':
-      return jalview.renderer.AnnotationRenderer.SHEET_COLOUR;
-    }
-    return jalview.renderer.AnnotationRenderer.GLYPHLINE_COLOR;
-  }
-
-  @Override
-  public String getCalcId()
-  {
-    return CALC_ID;
-  }
-
-  private static String CALC_ID = "jabaws21.JPred3Cons";
-
-  public static AlignAnalysisUIText getAlignAnalysisUITest()
-  {
-    return new AlignAnalysisUIText(
-            compbio.ws.client.Services.JpredWS.toString(),
-            jalview.ws.jws2.JPred301Client.class, CALC_ID, false, true,
-            true, "JPred Consensus",
-            "When checked, JPred consensus is updated automatically.",
-            "Change JPred Settings...",
-            "Modify settings for JPred calculations.");
-  }
-}
index 7c8395f..671b5f1 100644 (file)
@@ -21,7 +21,6 @@
 package jalview.ws.jws2.jabaws2;
 
 import jalview.ws.jws2.AAConClient;
-import jalview.ws.jws2.JPred301Client;
 import jalview.ws.jws2.RNAalifoldClient;
 import jalview.ws.uimodel.AlignAnalysisUIText;
 
@@ -51,11 +50,8 @@ public class Jws2InstanceFactory
               AAConClient.getAlignAnalysisUITest());
       aaConGUI.put(compbio.ws.client.Services.RNAalifoldWS.toString(),
               RNAalifoldClient.getAlignAnalysisUITest());
-      // disable the JPred301 client in jalview ...
+      // ignore list for JABAWS services not supported in jalview ...
       ignoreGUI = new HashSet<String>();
-      ignoreGUI.add(compbio.ws.client.Services.JpredWS.toString());
-      aaConGUI.put(compbio.ws.client.Services.JpredWS.toString(),
-              JPred301Client.getAlignAnalysisUITest());
     }
   }
 
index 86e3f76..dcd861a 100644 (file)
@@ -47,7 +47,8 @@ public class UrlDownloadClient
    *          the name of file to save the URLs to
    * @throws IOException
    */
-  public void download(String urlstring, String outfile) throws IOException
+  public static void download(String urlstring, String outfile)
+          throws IOException
   {
     FileOutputStream fos = null;
     ReadableByteChannel rbc = null;
index 6e1c2db..f6d4028 100644 (file)
@@ -3,12 +3,16 @@ package jalview.datamodel;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNotSame;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertSame;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
 import jalview.schemes.NucleotideColourScheme;
+import jalview.schemes.PIDColourScheme;
+
+import java.awt.Color;
 
 import junit.extensions.PA;
 
@@ -121,13 +125,32 @@ public class SequenceGroupTest
     PA.setValue(sg2, "context", sg2);
     try
     {
-      sg3.setContext(sg2); // circular reference in sg2
+      sg3.setContext(sg2, false); // circular reference in sg2
       fail("Expected exception");
     } catch (IllegalArgumentException e)
     {
       // expected
       assertNull(sg3.getContext());
     }
+
+    // test isDefined setting behaviour
+    sg2 = new SequenceGroup();
+    sg1.setContext(null, false);
+    assertFalse(sg1.isDefined());
+
+    sg1.setContext(sg2, false);
+    assertFalse(sg1.isDefined());
+
+    sg1.setContext(sg2, true);
+    assertTrue(sg1.isDefined());
+
+    // setContext without defined parameter does not change isDefined
+    sg1.setContext(null);
+    assertTrue(sg1.isDefined());
+
+    sg1.setContext(null, false);
+    sg1.setContext(sg2);
+    assertFalse(sg1.isDefined());
   }
 
   @Test(groups = { "Functional" })
@@ -198,6 +221,73 @@ public class SequenceGroupTest
     assertTrue(sg2.contains(seq2, 8));
     sg2.deleteSequence(seq2, false);
     assertFalse(sg2.contains(seq2));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testCopyConstructor()
+  {
+    SequenceI seq = new Sequence("seq", "ABC");
+    SequenceGroup sg = new SequenceGroup();
+    sg.addSequence(seq, false);
+    sg.setName("g1");
+    sg.setDescription("desc");
+    sg.setColourScheme(new PIDColourScheme());
+    sg.setDisplayBoxes(false);
+    sg.setDisplayText(false);
+    sg.setColourText(true);
+    sg.isDefined = true;
+    sg.setShowNonconserved(true);
+    sg.setOutlineColour(Color.red);
+    sg.setIdColour(Color.blue);
+    sg.thresholdTextColour = 1;
+    sg.textColour = Color.orange;
+    sg.textColour2 = Color.yellow;
+    sg.setIgnoreGapsConsensus(false);
+    sg.setshowSequenceLogo(true);
+    sg.setNormaliseSequenceLogo(true);
+    sg.setHidereps(true);
+    sg.setHideCols(true);
+    sg.setShowConsensusHistogram(true);
+    sg.setContext(new SequenceGroup());
+
+    SequenceGroup sg2 = new SequenceGroup(sg);
+    assertEquals(sg2.getName(), sg.getName());
+    assertEquals(sg2.getDescription(), sg.getDescription());
+    assertNotSame(sg2.getGroupColourScheme(), sg.getGroupColourScheme());
+    assertSame(sg2.getColourScheme(), sg.getColourScheme());
+    assertEquals(sg2.getDisplayBoxes(), sg.getDisplayBoxes());
+    assertEquals(sg2.getDisplayText(), sg.getDisplayText());
+    assertEquals(sg2.getColourText(), sg.getColourText());
+    assertEquals(sg2.getShowNonconserved(), sg.getShowNonconserved());
+    assertEquals(sg2.getOutlineColour(), sg.getOutlineColour());
+    assertEquals(sg2.getIdColour(), sg.getIdColour());
+    assertEquals(sg2.thresholdTextColour, sg.thresholdTextColour);
+    assertEquals(sg2.textColour, sg.textColour);
+    assertEquals(sg2.textColour2, sg.textColour2);
+    assertEquals(sg2.getIgnoreGapsConsensus(), sg.getIgnoreGapsConsensus());
+    assertEquals(sg2.isShowSequenceLogo(), sg.isShowSequenceLogo());
+    assertEquals(sg2.isNormaliseSequenceLogo(),
+            sg.isNormaliseSequenceLogo());
+    assertEquals(sg2.isHidereps(), sg.isHidereps());
+    assertEquals(sg2.isHideCols(), sg.isHideCols());
+    assertEquals(sg2.isShowConsensusHistogram(),
+            sg.isShowConsensusHistogram());
+
+    /*
+     * copy of sequences
+     */
+    assertNotSame(sg2.getSequences(), sg.getSequences());
+    assertEquals(sg2.getSequences(), sg.getSequences());
 
+    /*
+     * isDefined should only be set true when a new group is added to
+     * an alignment, not in the copy constructor
+     */
+    assertFalse(sg2.isDefined());
+
+    /*
+     * context should be set explicitly, not by copy
+     */
+    assertNull(sg2.getContext());
   }
 }
index 131ef41..36e9b20 100644 (file)
@@ -272,7 +272,7 @@ public class JmolParserTest
      * local structure files should yield a false ID based on the filename
      */
     assertNotNull(structureData.getId());
-    assertEquals(structureData.getId(), "localstruct.pdb");
+    assertEquals(structureData.getId(), "localstruct");
     assertNotNull(structureData.getSeqs());
     /*
      * the ID is also the group for features derived from structure data 
@@ -280,7 +280,7 @@ public class JmolParserTest
     assertNotNull(structureData.getSeqs().get(0).getSequenceFeatures()[0].featureGroup);
     assertEquals(
             structureData.getSeqs().get(0).getSequenceFeatures()[0].featureGroup,
-            "localstruct.pdb");
+            "localstruct");
 
   }
 }
index 995b099..792f7ad 100644 (file)
@@ -115,4 +115,6 @@ public class JmolViewerTest
       }
     }
   }
+
+
 }
index d85bb10..29fd092 100644 (file)
@@ -217,7 +217,7 @@ public class JalviewChimeraView
      * (or possibly 52-145 to 1-94 - see JAL-2319)
      */
     StructureSelectionManager ssm = binding.getSsm();
-    String pdbFile = binding.getPdbFile()[0];
+    String pdbFile = binding.getStructureFiles()[0];
     StructureMapping[] mappings = ssm.getMapping(pdbFile);
     assertTrue(mappings[0].getMappingDetailsOutput().contains("SIFTS"),
             "Failed to perform SIFTS mapping");
index e6c16b7..4660842 100644 (file)
@@ -160,7 +160,7 @@ public class AlignViewportTest
     acf2.addMap(s1, s1, new MapList(new int[] { 1, 4 }, new int[] { 4, 1 },
             1, 1));
 
-    List<AlignedCodonFrame> mappings = new ArrayList<AlignedCodonFrame>();
+    List<AlignedCodonFrame> mappings = new ArrayList<>();
     mappings.add(acf1);
     mappings.add(acf2);
     af1.getViewport().getAlignment().setCodonFrames(mappings);
@@ -217,11 +217,11 @@ public class AlignViewportTest
     acf3.addMap(cs2, cs2, new MapList(new int[] { 1, 12 }, new int[] { 1,
         12 }, 1, 1));
 
-    List<AlignedCodonFrame> mappings1 = new ArrayList<AlignedCodonFrame>();
+    List<AlignedCodonFrame> mappings1 = new ArrayList<>();
     mappings1.add(acf1);
     af1.getViewport().getAlignment().setCodonFrames(mappings1);
 
-    List<AlignedCodonFrame> mappings2 = new ArrayList<AlignedCodonFrame>();
+    List<AlignedCodonFrame> mappings2 = new ArrayList<>();
     mappings2.add(acf2);
     mappings2.add(acf3);
     af2.getViewport().getAlignment().setCodonFrames(mappings2);
@@ -280,12 +280,12 @@ public class AlignViewportTest
     acf3.addMap(cs2, cs2, new MapList(new int[] { 1, 12 }, new int[] { 1,
         12 }, 1, 1));
 
-    List<AlignedCodonFrame> mappings1 = new ArrayList<AlignedCodonFrame>();
+    List<AlignedCodonFrame> mappings1 = new ArrayList<>();
     mappings1.add(acf1);
     mappings1.add(acf2);
     af1.getViewport().getAlignment().setCodonFrames(mappings1);
 
-    List<AlignedCodonFrame> mappings2 = new ArrayList<AlignedCodonFrame>();
+    List<AlignedCodonFrame> mappings2 = new ArrayList<>();
     mappings2.add(acf2);
     mappings2.add(acf3);
     af2.getViewport().getAlignment().setCodonFrames(mappings2);
@@ -389,7 +389,8 @@ public class AlignViewportTest
 
   /**
    * Verify that setting the selection group has the side-effect of setting the
-   * context on the group, unless it already has one
+   * context on the group, unless it already has one, but does not change
+   * whether the group is defined or not.
    */
   @Test(groups = { "Functional" })
   public void testSetSelectionGroup()
@@ -399,13 +400,21 @@ public class AlignViewportTest
     AlignViewport av = af.getViewport();
     SequenceGroup sg1 = new SequenceGroup();
     SequenceGroup sg2 = new SequenceGroup();
+    SequenceGroup sg3 = new SequenceGroup();
 
     av.setSelectionGroup(sg1);
     assertSame(sg1.getContext(), av.getAlignment()); // context set
+    assertFalse(sg1.isDefined()); // group not defined
 
-    sg2.setContext(sg1);
+    sg2.setContext(sg1, false);
     av.setSelectionGroup(sg2);
+    assertFalse(sg2.isDefined()); // unchanged
     assertSame(sg2.getContext(), sg1); // unchanged
+
+    // create a defined group
+    sg3.setContext(av.getAlignment(), true);
+    av.setSelectionGroup(sg3);
+    assertTrue(sg3.isDefined()); // unchanged
   }
   /**
    * Verify that setting/clearing SHOW_OCCUPANCY preference adds or omits occupancy row from viewport
diff --git a/test/jalview/gui/SeqPanelTest.java b/test/jalview/gui/SeqPanelTest.java
new file mode 100644 (file)
index 0000000..53dff0e
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.gui;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class SeqPanelTest
+{
+  AlignFrame af;
+
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+  }
+  @Test(groups = "Functional")
+  public void testSetStatusReturnsPosOrMinusOne()
+  {
+    SequenceI seq1 = new Sequence("Seq1", "AACDE");
+    SequenceI seq2 = new Sequence("Seq2", "AA--E");
+    AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
+    AlignFrame alignFrame = new AlignFrame(al, al.getWidth(),
+            al.getHeight());
+    AlignmentI visAl = alignFrame.getViewport().getAlignment();
+    // Test either side of gap
+    // This first assert fails due to JAL-2563
+    assertEquals(
+            alignFrame.alignPanel.getSeqPanel().setStatusMessage(
+                    visAl.getSequenceAt(1), 1, 1), 2);
+    assertEquals(
+            alignFrame.alignPanel.getSeqPanel().setStatusMessage(
+                    visAl.getSequenceAt(1), 4, 1), 3);
+    // Test gaps are -1
+    assertEquals(
+            alignFrame.alignPanel.getSeqPanel().setStatusMessage(
+                    visAl.getSequenceAt(1), 2, 1), -1);
+    assertEquals(
+            alignFrame.alignPanel.getSeqPanel().setStatusMessage(
+                    visAl.getSequenceAt(1), 3, 1), -1);
+  }
+
+  @Test(groups = "Functional")
+  public void testAmbiguousAminoAcidGetsStatusMessage()
+  {
+    SequenceI seq1 = new Sequence("Seq1", "ABCDE");
+    SequenceI seq2 = new Sequence("Seq2", "AB--E");
+    AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
+    AlignFrame alignFrame = new AlignFrame(al, al.getWidth(),
+            al.getHeight());
+    AlignmentI visAl = alignFrame.getViewport().getAlignment();
+    // Test either side of gap
+    // This first assert fails due to JAL-2563
+    assertEquals(
+            alignFrame.alignPanel.getSeqPanel().setStatusMessage(
+                    visAl.getSequenceAt(1), 1, 1), 2);
+    assertTrue(alignFrame.statusBar.getText().contains("(2)"));
+  }
+}
index c04353f..4535c93 100644 (file)
@@ -121,7 +121,7 @@ public class StructureChooserTest
     StructureChooser sc = new StructureChooser(selectedSeqs, seq, null);
     sc.populateFilterComboBox(false, false);
     int optionsSize = sc.getCmbFilterOption().getItemCount();
-    assertEquals(3, optionsSize); // if structures are not discovered then don't
+    assertEquals(2, optionsSize); // if structures are not discovered then don't
                                   // populate filter options
 
     sc.populateFilterComboBox(true, false);
diff --git a/test/jalview/io/FileLoaderTest.java b/test/jalview/io/FileLoaderTest.java
new file mode 100644 (file)
index 0000000..968901f
--- /dev/null
@@ -0,0 +1,22 @@
+package jalview.io;
+
+import org.junit.Assert;
+import org.testng.annotations.Test;
+
+public class FileLoaderTest
+{
+
+  @Test(groups = { "Network" })
+  public void testDownloadStructuresIfInputFromURL()
+  {
+    String urlFile = "http://www.jalview.org/builds/develop/examples/3W5V.pdb";
+    FileLoader fileLoader = new FileLoader();
+    fileLoader.LoadFileWaitTillLoaded(urlFile, DataSourceType.URL,
+            FileFormat.PDB);
+    Assert.assertNotNull(fileLoader.file);
+    // The FileLoader's file is expected to be same as the original URL.
+    Assert.assertEquals(urlFile, fileLoader.file);
+    // Data source type expected to be DataSourceType.URL
+    Assert.assertEquals(DataSourceType.URL, fileLoader.protocol);
+  }
+}
index a7e483e..c125ef6 100644 (file)
@@ -138,7 +138,7 @@ public class AAStructureBindingModelTest
     testee = new AAStructureBindingModel(ssm, pdbFiles, seqs, null)
     {
       @Override
-      public String[] getPdbFile()
+      public String[] getStructureFiles()
       {
         return new String[] { "INLINE1YCS", "INLINE3A6S", "INLINE1OOT" };
       }
@@ -230,7 +230,7 @@ public class AAStructureBindingModelTest
     /*
      * create a data bean to hold data per structure file
      */
-    SuperposeData[] structs = new SuperposeData[testee.getPdbFile().length];
+    SuperposeData[] structs = new SuperposeData[testee.getStructureFiles().length];
     for (int i = 0; i < structs.length; i++)
     {
       structs[i] = testee.new SuperposeData(al.getWidth());
index 2bd9c47..0e931eb 100644 (file)
@@ -79,10 +79,8 @@ public class OverviewDimensionsHideHiddenTest
     hiddenCols.revealAllHiddenColumns(colsel);
     
     vpranges = new ViewportRanges(al);
-    vpranges.setStartRes(0);
-    vpranges.setEndRes(62);
-    vpranges.setStartSeq(0);
-    vpranges.setEndSeq(17);
+    vpranges.setViewportStartAndHeight(0, 18);
+    vpranges.setViewportStartAndWidth(0, 63);
 
     viewHeight = vpranges.getEndSeq() - vpranges.getStartSeq() + 1;
     viewWidth = vpranges.getEndRes() - vpranges.getStartRes() + 1;
@@ -204,26 +202,26 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // negative boxX value reset to 0
     mouseClick(od, -5, 10);
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollRow(),
+    assertEquals(vpranges.getStartSeq(),
             Math.round((float) 10 * alheight / od.getSequencesHeight()));
-    assertEquals(od.getScrollCol(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
 
     // negative boxY value reset to 0
     mouseClick(od, 6, -2);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) 6 * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // overly large boxX value reset to width-boxWidth
     mouseClick(od, 100, 6);
@@ -231,9 +229,10 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), 6);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
 
@@ -243,13 +242,14 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight());
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
 
     // here (float) od.getBoxY() * alheight / od.getSequencesHeight() = 507.5
     // and round rounds to 508; however we get 507 working with row values
     // hence the subtraction of 1
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()) - 1);
 
@@ -258,9 +258,10 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
 
@@ -274,19 +275,20 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), oldboxx + 5);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
     assertEquals(od.getBoxY(), oldboxy + 2);
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
 
     // click at top corner
     mouseClick(od, 0, 0);
     assertEquals(od.getBoxX(), 0);
-    assertEquals(od.getScrollCol(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
     assertEquals(od.getBoxY(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
   }
@@ -302,8 +304,8 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide cols at start and check updated box position is correct
     int lastHiddenCol = 30;
@@ -313,8 +315,8 @@ public class OverviewDimensionsHideHiddenTest
 
     // click to right of hidden columns, box moves to click point
     testBoxIsAtClickPoint(40, 0);
-    assertEquals(od.getScrollRow(), 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartSeq(), 0);
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) 40 * alwidth / od.getWidth()));
 
     // click to right of hidden columns such that box runs over right hand side
@@ -327,9 +329,9 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
   }
 
   /**
@@ -344,8 +346,8 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
     
     // hide columns 63-73, no change to box position or dimensions
     int firstHidden = 63;
@@ -357,8 +359,8 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so that it overlaps with hidden cols on one side
     // box width, boxX and scrollCol as for unhidden case
@@ -366,35 +368,35 @@ public class OverviewDimensionsHideHiddenTest
                               // between cols 60 and 70
     mouseClick(od, xpos, 0);
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round(xpos * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so that it completely covers hidden cols
     // box width, boxX and scrollCol as for unhidden case
     xpos = 33;
     mouseClick(od, xpos, 0);
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) xpos * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so boxX is in hidden cols, box overhangs at right
     // boxX and scrollCol at left of hidden area, box width unchanged
     xpos = 50;
     mouseClick(od, xpos, 0);
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) xpos * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so boxX is to right of hidden cols, but does not go beyond full
     // width of alignment
     // box width, boxX and scrollCol all as for non-hidden case
     xpos = 75;
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollRow(), 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartSeq(), 0);
+    assertEquals(vpranges.getStartRes(),
             Math.round(xpos * alwidth / od.getWidth()));
     
     // move box so it goes beyond full width of alignment
@@ -405,9 +407,9 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
   }
 
@@ -422,8 +424,8 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide columns 140-164, no change to box position or dimensions
     int firstHidden = 140;
@@ -433,15 +435,15 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // click to left of hidden cols, without overlapping
     // boxX, scrollCol and width as normal
     int xpos = 5;
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollRow(), 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartSeq(), 0);
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) xpos * alwidth / od.getWidth()));
 
     // click to left of hidden cols, with overlap
@@ -449,9 +451,9 @@ public class OverviewDimensionsHideHiddenTest
     xpos = Math.round((float) 145 * od.getWidth() / alwidth) - boxWidth;
     mouseClick(od, xpos, 0);
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) xpos * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // click off end of alignment
     // boxX and scrollCol adjusted backwards, width normal
@@ -461,9 +463,9 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
   }
 
   /**
@@ -750,8 +752,8 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxHeight(), boxHeight);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide rows at start and check updated box position is correct
     int lastHiddenRow = 30;
@@ -795,8 +797,8 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide rows in middle and check updated box position is correct
     // no changes
@@ -855,8 +857,8 @@ public class OverviewDimensionsHideHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide rows at end and check updated box position is correct
     // no changes
@@ -911,8 +913,7 @@ public class OverviewDimensionsHideHiddenTest
    */
   private void moveViewportH(int startRes)
   {
-    vpranges.setStartRes(startRes);
-    vpranges.setEndRes(startRes + viewWidth - 1);
+    vpranges.setViewportStartAndWidth(startRes, viewWidth);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
 
@@ -921,8 +922,7 @@ public class OverviewDimensionsHideHiddenTest
    */
   private void moveViewportV(int startSeq)
   {
-    vpranges.setStartSeq(startSeq);
-    vpranges.setEndSeq(startSeq + viewHeight - 1);
+    vpranges.setViewportStartAndHeight(startSeq, viewHeight);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
 
@@ -931,28 +931,21 @@ public class OverviewDimensionsHideHiddenTest
    */
   private void moveViewport(int startRes, int startSeq)
   {
-    vpranges.setStartRes(startRes);
-    vpranges.setEndRes(startRes + viewWidth - 1);
-    vpranges.setStartSeq(startSeq);
-    vpranges.setEndSeq(startSeq + viewHeight - 1);
+    vpranges.setViewportStartAndWidth(startRes, viewWidth);
+    vpranges.setViewportStartAndHeight(startSeq, viewHeight);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
 
   /*
    * Mouse click as position x,y in overview window
    */
-  private void mouseClick(OverviewDimensionsHideHidden od, int x, int y)
+  private void mouseClick(OverviewDimensions od, int x, int y)
   {
     od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols);
 
     // updates require an OverviewPanel to exist which it doesn't here
     // so call setBoxPosition() as it would be called by the AlignmentPanel
     // normally
-
-    vpranges.setStartRes(od.getScrollCol());
-    vpranges.setEndRes(od.getScrollCol() + viewWidth - 1);
-    vpranges.setStartSeq(od.getScrollRow());
-    vpranges.setEndSeq(od.getScrollRow() + viewHeight - 1);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
   
index 8297159..1bc3bfa 100644 (file)
@@ -78,10 +78,8 @@ public class OverviewDimensionsShowHiddenTest
     hiddenCols.revealAllHiddenColumns(colsel);
     
     vpranges = new ViewportRanges(al);
-    vpranges.setStartRes(0);
-    vpranges.setEndRes(62);
-    vpranges.setStartSeq(0);
-    vpranges.setEndSeq(17);
+    vpranges.setViewportStartAndHeight(0, 18);
+    vpranges.setViewportStartAndWidth(0, 63);
 
     viewHeight = vpranges.getEndSeq() - vpranges.getStartSeq() + 1;
     viewWidth = vpranges.getEndRes() - vpranges.getStartRes() + 1;
@@ -203,26 +201,26 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // negative boxX value reset to 0
     mouseClick(od, -5, 10);
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollRow(),
+    assertEquals(vpranges.getStartSeq(),
             Math.round((float) 10 * alheight / od.getSequencesHeight()));
-    assertEquals(od.getScrollCol(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
 
     // negative boxY value reset to 0
     mouseClick(od, 6, -2);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) 6 * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // overly large boxX value reset to width-boxWidth
     mouseClick(od, 100, 6);
@@ -230,9 +228,10 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 6);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
 
@@ -242,13 +241,14 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight());
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
 
     // here (float) od.getBoxY() * alheight / od.getSequencesHeight() = 507.5
     // and round rounds to 508; however we get 507 working with row values
     // hence the subtraction of 1
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()) - 1);
 
@@ -257,9 +257,10 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
 
@@ -273,19 +274,20 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), oldboxx + 5);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
     assertEquals(od.getBoxY(), oldboxy + 2);
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
 
     // click at top corner
     mouseClick(od, 0, 0);
     assertEquals(od.getBoxX(), 0);
-    assertEquals(od.getScrollCol(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
     assertEquals(od.getBoxY(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
   }
@@ -301,8 +303,8 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide cols at start and check updated box position is correct
     // changes boxX but not boxwidth
@@ -326,13 +328,13 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollRow(), 0);
-    assertEquals(od.getScrollCol(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
 
     // click to right of hidden columns, box moves to click point
     testBoxIsAtClickPoint(40, 0);
-    assertEquals(od.getScrollRow(), 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartSeq(), 0);
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) 40 * alwidth / od.getWidth())
                     - (lastHiddenCol + 1));
 
@@ -346,10 +348,11 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 5);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth())
                     - (lastHiddenCol + 1));
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
   }
@@ -365,8 +368,8 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
     
     // hide columns 63-73, no change to box position or dimensions
     int firstHidden = 63;
@@ -377,8 +380,8 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so that it overlaps with hidden cols on one side
     // box width changes, boxX and scrollCol as for unhidden case
@@ -392,9 +395,9 @@ public class OverviewDimensionsShowHiddenTest
             Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
                     * od.getWidth() / alwidth));
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round(xpos * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so that it completely covers hidden cols
     // box width changes, boxX and scrollCol as for hidden case
@@ -407,9 +410,9 @@ public class OverviewDimensionsShowHiddenTest
             Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
                     * od.getWidth() / alwidth));
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) xpos * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so boxX is in hidden cols, box overhangs at right
     // boxX and scrollCol at left of hidden area, box width extends across
@@ -425,16 +428,16 @@ public class OverviewDimensionsShowHiddenTest
                     + Math.round((float) (lastHidden - firstHidden + 1)
                             * od.getWidth() / alwidth));
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(), firstHidden - 1);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), firstHidden - 1);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // move box so boxX is to right of hidden cols, but does not go beyond full
     // width of alignment
     // box width, boxX and scrollCol all as for non-hidden case
     xpos = 75;
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollRow(), 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartSeq(), 0);
+    assertEquals(vpranges.getStartRes(),
             Math.round(xpos * alwidth / od.getWidth())
                     - (lastHidden - firstHidden + 1));
     
@@ -446,10 +449,12 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 5);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(
+            vpranges.getStartRes(),
             Math.round(((float) od.getBoxX() * alwidth / od.getWidth())
                     - (lastHidden - firstHidden + 1)));
-    assertEquals(od.getScrollRow(),
+    assertEquals(
+            vpranges.getStartSeq(),
             Math.round((float) od.getBoxY() * alheight
                     / od.getSequencesHeight()));
 
@@ -466,8 +471,8 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide columns 140-164, no change to box position or dimensions
     int firstHidden = 140;
@@ -477,15 +482,15 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxX(), 0);
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // click to left of hidden cols, without overlapping
     // boxX, scrollCol and width as normal
     int xpos = 5;
     testBoxIsAtClickPoint(xpos, 0);
-    assertEquals(od.getScrollRow(), 0);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartSeq(), 0);
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) xpos * alwidth / od.getWidth()));
 
     // click to left of hidden cols, with overlap
@@ -498,9 +503,9 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // click in hidden cols
     // boxX and scrollCol adjusted for hidden cols, width normal
@@ -511,9 +516,9 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // click off end of alignment
     // boxX and scrollCol adjusted for hidden cols, width normal
@@ -524,9 +529,9 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(),
+    assertEquals(vpranges.getStartRes(),
             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
   }
 
   /**
@@ -791,8 +796,8 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxHeight(), boxHeight);
     assertEquals(od.getBoxWidth(), boxWidth);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide rows at start and check updated box position is correct
     // changes boxY but not boxheight
@@ -838,8 +843,8 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide rows in middle and check updated box position is correct
     // no changes
@@ -895,8 +900,8 @@ public class OverviewDimensionsShowHiddenTest
     assertEquals(od.getBoxY(), 0);
     assertEquals(od.getBoxWidth(), boxWidth);
     assertEquals(od.getBoxHeight(), boxHeight);
-    assertEquals(od.getScrollCol(), 0);
-    assertEquals(od.getScrollRow(), 0);
+    assertEquals(vpranges.getStartRes(), 0);
+    assertEquals(vpranges.getStartSeq(), 0);
 
     // hide rows at end and check updated box position is correct
     // no changes
@@ -951,8 +956,7 @@ public class OverviewDimensionsShowHiddenTest
    */
   private void moveViewportH(int startRes)
   {
-    vpranges.setStartRes(startRes);
-    vpranges.setEndRes(startRes + viewWidth - 1);
+    vpranges.setViewportStartAndWidth(startRes, viewWidth);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
 
@@ -961,8 +965,7 @@ public class OverviewDimensionsShowHiddenTest
    */
   private void moveViewportV(int startSeq)
   {
-    vpranges.setStartSeq(startSeq);
-    vpranges.setEndSeq(startSeq + viewHeight - 1);
+    vpranges.setViewportStartAndHeight(startSeq, viewHeight);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
 
@@ -971,28 +974,21 @@ public class OverviewDimensionsShowHiddenTest
    */
   private void moveViewport(int startRes, int startSeq)
   {
-    vpranges.setStartRes(startRes);
-    vpranges.setEndRes(startRes + viewWidth - 1);
-    vpranges.setStartSeq(startSeq);
-    vpranges.setEndSeq(startSeq + viewHeight - 1);
+    vpranges.setViewportStartAndWidth(startRes, viewWidth);
+    vpranges.setViewportStartAndHeight(startSeq, viewHeight);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
 
   /*
    * Mouse click as position x,y in overview window
    */
-  private void mouseClick(OverviewDimensionsShowHidden od, int x, int y)
+  private void mouseClick(OverviewDimensions od, int x, int y)
   {
     od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols);
 
     // updates require an OverviewPanel to exist which it doesn't here
     // so call setBoxPosition() as it would be called by the AlignmentPanel
     // normally
-
-    vpranges.setStartRes(od.getScrollCol());
-    vpranges.setEndRes(od.getScrollCol() + viewWidth - 1);
-    vpranges.setStartSeq(od.getScrollRow());
-    vpranges.setEndSeq(od.getScrollRow() + viewHeight - 1);
     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
   }
   
index cfd03cd..80bd4db 100644 (file)
@@ -1,10 +1,20 @@
 package jalview.viewmodel;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
 
 import jalview.analysis.AlignmentGenerator;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.HiddenSequences;
 
+import java.beans.PropertyChangeEvent;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 public class ViewportRangesTest {
@@ -13,7 +23,17 @@ public class ViewportRangesTest {
 
   AlignmentI al = gen.generate(20, 30, 1, 5, 5);
 
-  @Test
+  AlignmentI smallAl = gen.generate(7, 2, 2, 5, 5);
+
+  @BeforeMethod
+  public void cleanUp()
+  {
+    ColumnSelection sel = new ColumnSelection();
+    al.getHiddenColumns().revealAllHiddenColumns(sel);
+    al.getHiddenSequences().showAll(null);
+  }
+
+  @Test(groups = { "Functional" })
   public void testViewportRanges() 
   {
     ViewportRanges vr = new ViewportRanges(al);
@@ -24,7 +44,7 @@ public class ViewportRangesTest {
     assertEquals(vr.getEndSeq(), al.getHeight() - 1);
   }
 
-  @Test
+  @Test(groups = { "Functional" })
   public void testGetAbsoluteAlignmentHeight()
   {
     ViewportRanges vr = new ViewportRanges(al);
@@ -35,28 +55,25 @@ public class ViewportRangesTest {
     assertEquals(vr.getAbsoluteAlignmentHeight(), al.getHeight() + 1);
   }
 
-  @Test
+  @Test(groups = { "Functional" })
   public void testGetAbsoluteAlignmentWidth()
   {
     ViewportRanges vr = new ViewportRanges(al);
     assertEquals(vr.getAbsoluteAlignmentWidth(), al.getWidth());
   }
 
-  @Test
+  @Test(groups = { "Functional" })
   public void testSetEndRes()
   {
     ViewportRanges vr = new ViewportRanges(al);
     vr.setEndRes(-1);
     assertEquals(vr.getEndRes(), 0);
 
-    vr.setEndRes(al.getWidth());
-    assertEquals(vr.getEndRes(), al.getWidth() - 1);
-
     vr.setEndRes(al.getWidth() - 1);
     assertEquals(vr.getEndRes(), al.getWidth() - 1);
   }
 
-  @Test
+  @Test(groups = { "Functional" })
   public void testSetEndSeq()
   {
     ViewportRanges vr = new ViewportRanges(al);
@@ -70,7 +87,7 @@ public class ViewportRangesTest {
     assertEquals(vr.getEndSeq(), al.getHeight() - 1);
   }
 
-  @Test
+  @Test(groups = { "Functional" })
   public void testSetStartRes()
   {
     ViewportRanges vr = new ViewportRanges(al);
@@ -84,17 +101,452 @@ public class ViewportRangesTest {
     assertEquals(vr.getStartRes(), al.getWidth() - 1);
   }
 
-  @Test
+  @Test(groups = { "Functional" })
   public void testSetStartSeq()
   {
     ViewportRanges vr = new ViewportRanges(al);
     vr.setStartSeq(-1);
     assertEquals(vr.getStartSeq(), 0);
 
-    vr.setStartSeq(al.getHeight());
-    assertEquals(vr.getStartSeq(), al.getHeight() - 1);
+    vr.setStartSeq(al.getHeight() - vr.getViewportHeight() + 1);
+    assertEquals(vr.getStartSeq(), al.getHeight() - vr.getViewportHeight());
+
+    vr.setStartSeq(al.getHeight() - vr.getViewportHeight());
+    assertEquals(vr.getStartSeq(), al.getHeight() - vr.getViewportHeight());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetStartEndRes()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setStartEndRes(-1, -1);
+    assertEquals(vr.getStartRes(), 0);
+    assertEquals(vr.getEndRes(), 0);
+
+    vr.setStartEndRes(5, 19);
+    assertEquals(vr.getStartRes(), 5);
+    assertEquals(vr.getEndRes(), 19);
+
+    vr.setStartEndRes(al.getWidth(), al.getWidth());
+    assertEquals(vr.getEndRes(), al.getWidth() - 1);
+
+    ViewportRanges vrsmall = new ViewportRanges(smallAl);
+    vrsmall.setStartEndRes(al.getWidth(), al.getWidth());
+    assertEquals(vrsmall.getEndRes(), 6);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetStartEndSeq()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setStartEndSeq(-1, -1);
+    assertEquals(vr.getStartSeq(), 0);
+    assertEquals(vr.getEndSeq(), 0);
+
+    vr.setStartEndSeq(5, 19);
+    assertEquals(vr.getStartSeq(), 5);
+    assertEquals(vr.getEndSeq(), 19);
+
+    vr.setStartEndSeq(al.getHeight(), al.getHeight());
+    assertEquals(vr.getEndSeq(), al.getHeight() - 1);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetViewportHeight()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportHeight(13);
+    assertEquals(vr.getViewportHeight(), 13);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetViewportWidth()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportWidth(13);
+    assertEquals(vr.getViewportWidth(), 13);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetViewportStartAndHeight()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportStartAndHeight(2, 6);
+    assertEquals(vr.getViewportHeight(), 6);
+    assertEquals(vr.getStartSeq(), 2);
+
+    // reset -ve values of start to 0
+    vr.setViewportStartAndHeight(-1, 7);
+    assertEquals(vr.getViewportHeight(), 7);
+    assertEquals(vr.getStartSeq(), 0);
+
+    // reset out of bounds start values to within bounds
+    vr.setViewportStartAndHeight(35, 5);
+    assertEquals(vr.getViewportHeight(), 5);
+    assertEquals(vr.getStartSeq(), 24);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetViewportStartAndWidth()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportStartAndWidth(2, 6);
+    assertEquals(vr.getViewportWidth(), 6);
+    assertEquals(vr.getStartRes(), 2);
+
+    // reset -ve values of start to 0
+    vr.setViewportStartAndWidth(-1, 7);
+    assertEquals(vr.getViewportWidth(), 7);
+    assertEquals(vr.getStartRes(), 0);
+
+    // reset out of bounds start values to within bounds
+    vr.setViewportStartAndWidth(35, 5);
+    assertEquals(vr.getViewportWidth(), 5);
+    assertEquals(vr.getStartRes(), 16);
+
+    // small alignment doesn't get bounds reset
+    ViewportRanges vrsmall = new ViewportRanges(smallAl);
+    vrsmall.setViewportStartAndWidth(0, 63);
+    assertEquals(vrsmall.getViewportWidth(), 7);
+    assertEquals(vrsmall.getStartRes(), 0);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testPageUpDown()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportStartAndHeight(8, 6);
+    vr.pageDown();
+    assertEquals(vr.getStartSeq(), 13);
+
+    vr.pageUp();
+    assertEquals(vr.getStartSeq(), 8);
+
+    vr.pageUp();
+    assertEquals(vr.getStartSeq(), 3);
+
+    vr.pageUp();
+    // pageup does not go beyond 0, viewport height stays the same
+    assertEquals(vr.getStartSeq(), 0);
+    assertEquals(vr.getViewportHeight(), 6);
+
+    vr.pageDown();
+    vr.pageDown();
+    vr.pageDown();
+    vr.pageDown();
+    vr.pageDown();
+
+    // pagedown to bottom does not go beyond end, and height stays same
+    assertEquals(vr.getStartSeq(), 24);
+    assertEquals(vr.getViewportHeight(), 6);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testScrollUp()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportStartAndHeight(1, 5);
+    vr.scrollUp(true);
+    assertEquals(vr.getStartSeq(), 0);
+    // can't scroll above top
+    vr.scrollUp(true);
+    assertEquals(vr.getStartSeq(), 0);
+
+    vr.setViewportStartAndHeight(24, 5);
+    vr.scrollUp(false);
+    assertEquals(vr.getStartSeq(), 25);
+    // can't scroll beyond bottom
+    vr.scrollUp(false);
+    assertEquals(vr.getStartSeq(), 25);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testScrollUpWithHidden()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+
+    // hide last sequence
+    HiddenSequences hidden = new HiddenSequences(al);
+    hidden.hideSequence(al.getSequenceAt(29));
+
+    vr.setViewportStartAndHeight(1, 5);
+    vr.scrollUp(true);
+    assertEquals(vr.getStartSeq(), 0);
+    // can't scroll above top
+    vr.scrollUp(true);
+    assertEquals(vr.getStartSeq(), 0);
+
+    vr.setViewportStartAndHeight(23, 5);
+    vr.scrollUp(false);
+    assertEquals(vr.getStartSeq(), 24);
+    // can't scroll beyond bottom
+    vr.scrollUp(false);
+    assertEquals(vr.getStartSeq(), 24);
+  }
 
-    vr.setStartSeq(al.getHeight() - 1);
-    assertEquals(vr.getStartSeq(), al.getHeight() - 1);
+  @Test(groups = { "Functional" })
+  public void testScrollRight()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportStartAndWidth(1, 5);
+    vr.scrollRight(false);
+    assertEquals(vr.getStartRes(), 0);
+    // can't scroll left past start
+    vr.scrollRight(false);
+    assertEquals(vr.getStartRes(), 0);
+
+    vr.setViewportStartAndWidth(15, 5);
+    vr.scrollRight(true);
+    assertEquals(vr.getStartRes(), 16);
+    // can't scroll right past end
+    vr.scrollRight(true);
+    assertEquals(vr.getStartRes(), 16);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testScrollRightWithHidden()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+
+    // hide last 2 columns
+    HiddenColumns cols = new HiddenColumns();
+    cols.hideColumns(19, 20);
+    al.setHiddenColumns(cols);
+
+    vr.setViewportStartAndWidth(1, 5);
+    vr.scrollRight(false);
+    assertEquals(vr.getStartRes(), 0);
+    // can't scroll left past start
+    vr.scrollRight(false);
+    assertEquals(vr.getStartRes(), 0);
+
+    vr.setViewportStartAndWidth(13, 5);
+    vr.scrollRight(true);
+    assertEquals(vr.getStartRes(), 14);
+    // can't scroll right past last visible col
+    vr.scrollRight(true);
+    assertEquals(vr.getStartRes(), 14);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testScrollToWrappedVisible()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportStartAndWidth(5, 10);
+
+    vr.scrollToWrappedVisible(0);
+    assertEquals(vr.getStartRes(), 0);
+
+    vr.scrollToWrappedVisible(10);
+    assertEquals(vr.getStartRes(), 10);
+
+    vr.scrollToWrappedVisible(15);
+    assertEquals(vr.getStartRes(), 10);
+  }
+
+  // leave until JAL-2388 is merged and we can do without viewport
+  /*@Test(groups = { "Functional" })
+  public void testScrollToVisible()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportStartAndWidth(12,5);
+    vr.setViewportStartAndHeight(10,6);
+    vr.scrollToVisible(13,14)
+    
+    // no change
+    assertEquals(vr.getStartRes(), 12);
+    assertEquals(vr.getStartSeq(), 10);
+    
+    vr.scrollToVisible(5,6);
+    assertEquals(vr.getStartRes(), 5);
+    assertEquals(vr.getStartSeq(), 6);
+    
+    // test for hidden columns too
+  }*/
+
+  @Test(groups = { "Functional" })
+  public void testEventFiring()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    MockPropChangeListener l = new MockPropChangeListener(vr);
+    List<String> emptylist = new ArrayList<>();
+
+    vr.setViewportWidth(5);
+    vr.setViewportHeight(5);
+    l.reset();
+
+    // one event fired when startRes is called with new value
+    vr.setStartRes(4);
+    assertTrue(l.verify(1, Arrays.asList("startres")));
+    l.reset();
+
+    // no event fired for same value
+    vr.setStartRes(4);
+    assertTrue(l.verify(0, emptylist));
+    l.reset();
+
+    vr.setEndRes(10);
+    assertTrue(l.verify(1, Arrays.asList("startres")));
+    l.reset();
+
+    // no event fired for same value
+    vr.setEndRes(10);
+    assertTrue(l.verify(0, emptylist));
+    l.reset();
+
+    vr.setStartSeq(4);
+    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    l.reset();
+
+    vr.setStartSeq(4);
+    assertTrue(l.verify(0, emptylist));
+    l.reset();
+
+    vr.setEndSeq(10);
+    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    l.reset();
+
+    vr.setEndSeq(10);
+    assertTrue(l.verify(0, emptylist));
+    l.reset();
+
+    vr.setStartEndRes(2, 15);
+    assertTrue(l.verify(1, Arrays.asList("startres")));
+    l.reset();
+
+    vr.setStartEndRes(2, 15);
+    assertTrue(l.verify(0, emptylist));
+    l.reset();
+
+    // check new value fired by event is corrected startres
+    vr.setStartEndRes(-1, 5);
+    assertTrue(l.verify(1, Arrays.asList("startres"), Arrays.asList(0)));
+    l.reset();
+
+    // check new value fired by event is corrected endres
+    vr.setStartEndRes(0, -1);
+    assertTrue(l.verify(1, Arrays.asList("endres"), Arrays.asList(0)));
+    l.reset();
+
+    vr.setStartEndSeq(2, 15);
+    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    l.reset();
+
+    vr.setStartEndSeq(2, 15);
+    assertTrue(l.verify(0, emptylist));
+    l.reset();
+
+    vr.setStartEndRes(2, 2); // so seq and res values should be different, in
+                             // case of transposing in code
+    l.reset();
+
+    // check new value fired by event is corrected startseq
+    vr.setStartEndSeq(-1, 5);
+    assertTrue(l.verify(1, Arrays.asList("startseq"), Arrays.asList(0)));
+    l.reset();
+
+    // check new value fired by event is corrected endseq
+    vr.setStartEndSeq(0, -1);
+    assertTrue(l.verify(1, Arrays.asList("endseq"), Arrays.asList(0)));
+    l.reset();
+
+    // reset for later tests
+    vr.setStartEndSeq(2, 15);
+    l.reset();
+
+    // test viewport height and width setting triggers event
+    vr.setViewportHeight(10);
+    assertTrue(l.verify(1, Arrays.asList("endseq")));
+    l.reset();
+
+    vr.setViewportWidth(18);
+    assertTrue(l.verify(1, Arrays.asList("endres")));
+    l.reset();
+
+    // already has seq start set to 2, so triggers endseq
+    vr.setViewportStartAndHeight(2, 16);
+    assertTrue(l.verify(1, Arrays.asList("endseq")));
+    l.reset();
+
+    vr.setViewportStartAndWidth(1, 14);
+    assertTrue(l.verify(1, Arrays.asList("startres")));
+    l.reset();
+
+    // test page up/down triggers event
+    vr.pageUp();
+    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    l.reset();
+
+    vr.pageDown();
+    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    l.reset();
+
+    // test scrolling triggers event
+    vr.scrollUp(true);
+    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    l.reset();
+
+    vr.scrollUp(false);
+    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    l.reset();
+
+    vr.scrollRight(true);
+    assertTrue(l.verify(1, Arrays.asList("startres")));
+    l.reset();
+
+    vr.scrollRight(false);
+    assertTrue(l.verify(1, Arrays.asList("startres")));
+    l.reset();
+
+    vr.scrollToVisible(10, 10);
+    assertTrue(l.verify(4,
+            Arrays.asList("startseq", "startseq", "startseq", "startseq")));
+    l.reset();
+
+    vr.scrollToWrappedVisible(5);
+    assertTrue(l.verify(1, Arrays.asList("startres")));
+    l.reset();
+  }
+}
+
+// mock listener for property change events
+class MockPropChangeListener implements ViewportListenerI
+{
+  private int firecount = 0;
+
+  private List<String> events = new ArrayList<>();
+
+  private List<Integer> newvalues = new ArrayList<>();
+
+  public MockPropChangeListener(ViewportRanges vr)
+  {
+    vr.addPropertyChangeListener(this);
+  }
+
+  @Override
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    firecount++;
+    events.add(evt.getPropertyName());
+    newvalues.add((Integer) evt.getNewValue());
+  }
+
+  public boolean verify(int count, List<String> eventslist,
+          List<Integer> valueslist)
+  {
+    return (count == firecount) && events.equals(eventslist)
+            && newvalues.equals(valueslist);
+  }
+
+  public boolean verify(int count, List<String> eventslist)
+  {
+    return (count == firecount) && events.equals(eventslist);
+  }
+
+  public void reset()
+  {
+    firecount = 0;
+    events.clear();
+    newvalues.clear();
   }
 }
diff --git a/test/jalview/ws/jabaws/JpredJabaStructExportImport.java b/test/jalview/ws/jabaws/JpredJabaStructExportImport.java
deleted file mode 100644 (file)
index dc157e2..0000000
+++ /dev/null
@@ -1,327 +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.
- */
-package jalview.ws.jabaws;
-
-import static org.testng.AssertJUnit.assertNotNull;
-import static org.testng.AssertJUnit.assertTrue;
-
-import jalview.bin.Cache;
-import jalview.datamodel.AlignmentI;
-import jalview.gui.Jalview2XML;
-import jalview.gui.JvOptionPane;
-import jalview.io.AnnotationFile;
-import jalview.io.DataSourceType;
-import jalview.io.FileFormat;
-import jalview.io.FormatAdapter;
-import jalview.io.StockholmFileTest;
-import jalview.ws.jws2.JPred301Client;
-import jalview.ws.jws2.JabaParamStore;
-import jalview.ws.jws2.Jws2Discoverer;
-import jalview.ws.jws2.SequenceAnnotationWSClient;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
-import jalview.ws.params.AutoCalcSetting;
-
-import java.awt.Component;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-
-import org.testng.Assert;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeGroups;
-import org.testng.annotations.Test;
-
-import compbio.metadata.Argument;
-import compbio.metadata.WrongParameterException;
-
-public class JpredJabaStructExportImport
-{
-
-  @BeforeClass(alwaysRun = true)
-  public void setUpJvOptionPane()
-  {
-    JvOptionPane.setInteractiveMode(false);
-    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
-  }
-
-  public static String testseqs = "examples/uniref50.fa";
-
-  public static Jws2Discoverer disc;
-
-  public static Jws2Instance jpredws;
-
-  jalview.ws.jws2.JPred301Client jpredClient;
-
-  public static jalview.gui.AlignFrame af = null;
-
-  @BeforeGroups(groups = { "Network" })
-  public static void setUpBeforeClass() throws Exception
-  {
-    Cache.loadProperties("test/jalview/io/testProps.jvprops");
-    Cache.initLogger();
-    disc = JalviewJabawsTestUtils.getJabawsDiscoverer(false);
-
-    for (Jws2Instance svc : disc.getServices())
-    {
-      if (svc.getServiceTypeURI().toLowerCase().contains("jpred"))
-      {
-        jpredws = svc;
-      }
-    }
-
-    System.out.println("State of jpredws: " + jpredws);
-    Assert.assertNotNull(jpredws, "jpredws is null!");
-    jalview.io.FileLoader fl = new jalview.io.FileLoader(false);
-    af = fl.LoadFileWaitTillLoaded(testseqs, jalview.io.DataSourceType.FILE);
-    assertNotNull("Couldn't load test data ('" + testseqs + "')", af);
-  }
-
-  @AfterClass(alwaysRun = true)
-  public static void tearDownAfterClass() throws Exception
-  {
-    if (af != null)
-    {
-      af.setVisible(false);
-      af.dispose();
-    }
-  }
-
-  @Test(groups = { "Network" }, enabled = false)
-  public void testJPredStructOneSeqOnly()
-  {
-    af.selectAllSequenceMenuItem_actionPerformed(null);
-    af.getViewport()
-            .getSelectionGroup()
-            .addOrRemove(
-                    af.getViewport().getSelectionGroup().getSequenceAt(0),
-                    false);
-    af.hideSelSequences_actionPerformed(null);
-    jpredClient = new JPred301Client(jpredws, af, null, null);
-
-    assertTrue(
-            "Didn't find any default args to check for. Buggy implementation of hardwired arguments in client.",
-            jpredClient.selectDefaultArgs().size() > 0);
-
-    boolean success = false;
-    af.getViewport().getCalcManager().startWorker(jpredClient);
-    do
-    {
-      try
-      {
-        Thread.sleep(500);
-        List<Argument> args = JabaParamStore.getJabafromJwsArgs(af
-                .getViewport()
-                .getCalcIdSettingsFor(jpredClient.getCalcId())
-                .getArgumentSet()), defargs = jpredClient
-                .selectDefaultArgs();
-        for (Argument rg : args)
-        {
-          for (Argument defg : defargs)
-          {
-            if (defg.equals(rg))
-            {
-              success = true;
-            }
-          }
-        }
-        if (!success)
-        {
-          jpredClient.cancelCurrentJob();
-          Assert.fail("Jpred Client didn't run with hardwired default parameters.");
-        }
-
-      } catch (InterruptedException x)
-      {
-      }
-      ;
-    } while (af.getViewport().getCalcManager().isWorking());
-
-  }
-
-  @Test(groups = { "Network" }, enabled = false)
-  public void testJPredStructExport()
-  {
-
-    jpredClient = new JPred301Client(jpredws, af, null, null);
-
-    af.getViewport().getCalcManager().startWorker(jpredClient);
-
-    do
-    {
-      try
-      {
-        Thread.sleep(50);
-      } catch (InterruptedException x)
-      {
-      }
-      ;
-    } while (af.getViewport().getCalcManager().isWorking());
-
-    AlignmentI orig_alig = af.getViewport().getAlignment();
-
-    testAnnotationFileIO("Testing JPredWS Annotation IO", orig_alig);
-
-  }
-
-  public static void testAnnotationFileIO(String testname, AlignmentI al)
-  {
-    try
-    {
-      // what format would be appropriate for RNAalifold annotations?
-      String aligfileout = FileFormat.Pfam.getWriter(null).print(
-              al.getSequencesArray(), true);
-
-      String anfileout = new AnnotationFile()
-              .printAnnotationsForAlignment(al);
-      assertTrue(
-              "Test "
-                      + testname
-                      + "\nAlignment annotation file was not regenerated. Null string",
-              anfileout != null);
-      assertTrue(
-              "Test "
-                      + testname
-                      + "\nAlignment annotation file was not regenerated. Empty string",
-              anfileout.length() > "JALVIEW_ANNOTATION".length());
-
-      System.out.println("Output annotation file:\n" + anfileout
-              + "\n<<EOF\n");
-
-      // again what format would be appropriate?
-      AlignmentI al_new = new FormatAdapter().readFile(aligfileout,
-              DataSourceType.PASTE, FileFormat.Fasta);
-      assertTrue(
-              "Test "
-                      + testname
-                      + "\nregenerated annotation file did not annotate alignment.",
-              new AnnotationFile().readAnnotationFile(al_new, anfileout,
-                      DataSourceType.PASTE));
-
-      // test for consistency in io
-      StockholmFileTest.testAlignmentEquivalence(al, al_new, false, false,
-              false);
-      return;
-    } catch (Exception e)
-    {
-      e.printStackTrace();
-    }
-    Assert.fail("Test "
-            + testname
-            + "\nCouldn't complete Annotation file roundtrip input/output/input test.");
-  }
-
-  @Test(groups = { "Network" }, enabled = false)
-  public void testJpredwsSettingsRecovery()
-  {
-    Assert.fail("not implemnented");
-    List<compbio.metadata.Argument> opts = new ArrayList<compbio.metadata.Argument>();
-    for (compbio.metadata.Argument rg : (List<compbio.metadata.Argument>) jpredws
-            .getRunnerConfig().getArguments())
-    {
-      if (rg.getDescription().contains("emperature"))
-      {
-        try
-        {
-          rg.setValue("292");
-        } catch (WrongParameterException q)
-        {
-          Assert.fail("Couldn't set the temperature parameter "
-                  + q.getStackTrace());
-        }
-        opts.add(rg);
-      }
-      if (rg.getDescription().contains("max"))
-      {
-        opts.add(rg);
-      }
-    }
-    jpredClient = new JPred301Client(jpredws, af, null, opts);
-
-    af.getViewport().getCalcManager().startWorker(jpredClient);
-
-    do
-    {
-      try
-      {
-        Thread.sleep(50);
-      } catch (InterruptedException x)
-      {
-      }
-      ;
-    } while (af.getViewport().getCalcManager().isWorking());
-    AutoCalcSetting oldacs = af.getViewport().getCalcIdSettingsFor(
-            jpredClient.getCalcId());
-    String oldsettings = oldacs.getWsParamFile();
-    // write out parameters
-    jalview.gui.AlignFrame nalf = null;
-    assertTrue("Couldn't write out the Jar file",
-            new Jalview2XML(false).saveAlignment(af,
-                    "testJPredWS_param.jar", "trial parameter writeout"));
-    assertTrue("Couldn't read back the Jar file", (nalf = new Jalview2XML(
-            false).loadJalviewAlign("testJpredWS_param.jar")) != null);
-    if (nalf != null)
-    {
-      AutoCalcSetting acs = af.getViewport().getCalcIdSettingsFor(
-              jpredClient.getCalcId());
-      assertTrue("Calc ID settings not recovered from viewport stash",
-              acs.equals(oldacs));
-      assertTrue(
-              "Serialised Calc ID settings not identical to those recovered from viewport stash",
-              acs.getWsParamFile().equals(oldsettings));
-      JMenu nmenu = new JMenu();
-      new SequenceAnnotationWSClient()
-              .attachWSMenuEntry(nmenu, jpredws, af);
-      assertTrue("Couldn't get menu entry for service",
-              nmenu.getItemCount() > 0);
-      for (Component itm : nmenu.getMenuComponents())
-      {
-        if (itm instanceof JMenuItem)
-        {
-          JMenuItem i = (JMenuItem) itm;
-          if (i.getText().equals(
-                  jpredws.getAlignAnalysisUI().getAAconToggle()))
-          {
-            i.doClick();
-            break;
-          }
-        }
-      }
-      while (af.getViewport().isCalcInProgress())
-      {
-        try
-        {
-          Thread.sleep(200);
-        } catch (Exception x)
-        {
-        }
-        ;
-      }
-      AutoCalcSetting acs2 = af.getViewport().getCalcIdSettingsFor(
-              jpredClient.getCalcId());
-      assertTrue(
-              "Calc ID settings after recalculation has not been recovered.",
-              acs2.getWsParamFile().equals(oldsettings));
-    }
-  }
-}
index 998524a..6af831f 100644 (file)
@@ -66,6 +66,11 @@ public class MinJabawsClientTests
       MsaWS msaservice = null;
       for (Services service : registry.getSupportedServices())
       {
+        if (service == null)
+        {
+          // the 'unsupported service'
+          continue;
+        }
         if (service.equals(Services.ClustalOWS))
         {
           msaservice = (MsaWS) Jws2Client.connect(url, service);
index 5ea97ff..089c29f 100644 (file)
@@ -202,7 +202,9 @@ public class RNAStructExportImport
     } while (af.getViewport().getCalcManager().isWorking());
 
     AlignmentI orig_alig = af.getViewport().getAlignment();
-
+    // JBPNote: this assert fails (2.10.2) because the 'Reference Positions'
+    // annotation is mistakenly recognised as an RNA annotation row when read in
+    // as an annotation file.
     verifyAnnotationFileIO("Testing RNAalifold Annotation IO", orig_alig);
 
   }