Merge remote-tracking branch 'origin/develop' into imp/JAL-2774
authorkiramt <k.mourao@dundee.ac.uk>
Tue, 31 Oct 2017 13:59:31 +0000 (13:59 +0000)
committerkiramt <k.mourao@dundee.ac.uk>
Tue, 31 Oct 2017 13:59:31 +0000 (13:59 +0000)
Conflicts:
src/jalview/gui/SeqCanvas.java

130 files changed:
.checkstyle
RELEASE
examples/groovy/PIDmatrix.groovy [new file with mode: 0644]
help/html/calculations/pairwise.html
help/html/releases.html
src/MCview/AppletPDBCanvas.java
src/MCview/PDBCanvas.java
src/ext/edu/ucsf/rbvi/strucviz2/ChimeraResidue.java
src/jalview/analysis/AlignSeq.java
src/jalview/analysis/AlignmentUtils.java
src/jalview/api/AlignViewportI.java
src/jalview/api/AlignmentViewPanel.java
src/jalview/appletgui/APopupMenu.java
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AlignViewport.java
src/jalview/appletgui/AlignmentPanel.java
src/jalview/appletgui/AnnotationColourChooser.java
src/jalview/appletgui/AnnotationColumnChooser.java
src/jalview/appletgui/AnnotationLabels.java
src/jalview/appletgui/AnnotationPanel.java
src/jalview/appletgui/AnnotationRowFilter.java
src/jalview/appletgui/AppletJmol.java
src/jalview/appletgui/AppletJmolBinding.java
src/jalview/appletgui/ExtJmol.java
src/jalview/appletgui/FeatureRenderer.java
src/jalview/appletgui/FeatureSettings.java
src/jalview/appletgui/FontChooser.java
src/jalview/appletgui/IdPanel.java
src/jalview/appletgui/OverviewPanel.java
src/jalview/appletgui/PaintRefresher.java
src/jalview/appletgui/RedundancyPanel.java
src/jalview/appletgui/ScalePanel.java
src/jalview/appletgui/SeqPanel.java
src/jalview/appletgui/SliderPanel.java
src/jalview/appletgui/SplitFrame.java
src/jalview/appletgui/UserDefinedColours.java
src/jalview/controller/AlignViewController.java
src/jalview/datamodel/AlignmentAnnotation.java
src/jalview/datamodel/Mapping.java
src/jalview/datamodel/Sequence.java
src/jalview/ext/ensembl/EnsemblGene.java
src/jalview/ext/ensembl/EnsemblGenomes.java
src/jalview/ext/ensembl/EnsemblLookup.java
src/jalview/ext/ensembl/EnsemblProtein.java
src/jalview/ext/ensembl/EnsemblRestClient.java
src/jalview/ext/ensembl/EnsemblSymbol.java
src/jalview/ext/ensembl/EnsemblXref.java
src/jalview/ext/jmol/JalviewJmolBinding.java
src/jalview/ext/rbvi/chimera/AtomSpecModel.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/AlignmentPanel.java
src/jalview/gui/AnnotationChooser.java
src/jalview/gui/AnnotationColourChooser.java
src/jalview/gui/AnnotationColumnChooser.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/AnnotationPanel.java
src/jalview/gui/AnnotationRowFilter.java
src/jalview/gui/AppJmol.java
src/jalview/gui/AppJmolBinding.java
src/jalview/gui/AquaInternalFrameManager.java [new file with mode: 0644]
src/jalview/gui/CalculationChooser.java
src/jalview/gui/ChimeraViewFrame.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureColourChooser.java
src/jalview/gui/FeatureRenderer.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/FontChooser.java
src/jalview/gui/IProgressIndicator.java
src/jalview/gui/IdPanel.java
src/jalview/gui/IdwidthAdjuster.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/OverviewPanel.java
src/jalview/gui/PCAPanel.java
src/jalview/gui/PaintRefresher.java
src/jalview/gui/PairwiseAlignPanel.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/ProgressBar.java
src/jalview/gui/PromptUserConfig.java
src/jalview/gui/RedundancyPanel.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/SeqCanvas.java
src/jalview/gui/SeqPanel.java
src/jalview/gui/SliderPanel.java
src/jalview/gui/StructureChooser.java
src/jalview/gui/StructureViewerBase.java
src/jalview/gui/TextColourChooser.java
src/jalview/gui/TreePanel.java
src/jalview/gui/UserDefinedColours.java
src/jalview/gui/ViewSelectionMenu.java
src/jalview/io/FileLoader.java
src/jalview/io/InputStreamParser.java
src/jalview/io/WSWUBlastClient.java
src/jalview/javascript/JSFunctionExec.java
src/jalview/javascript/MouseOverStructureListener.java
src/jalview/renderer/ScaleRenderer.java
src/jalview/renderer/seqfeatures/FeatureRenderer.java
src/jalview/schemes/RNAHelicesColourChooser.java
src/jalview/structure/StructureSelectionManager.java
src/jalview/util/MappingUtils.java
src/jalview/viewmodel/AlignmentViewport.java
src/jalview/viewmodel/ViewportRanges.java
src/jalview/workers/AnnotationWorker.java
src/jalview/workers/ColumnCounterSetWorker.java
src/jalview/workers/ConsensusThread.java
src/jalview/workers/ConservationThread.java
src/jalview/workers/StrucConsensusThread.java
src/jalview/ws/DasSequenceFeatureFetcher.java
src/jalview/ws/jws2/AADisorderClient.java
src/jalview/ws/jws2/AbstractJabaCalcWorker.java
src/jalview/ws/jws2/jabaws2/Jws2Instance.java
test/jalview/analysis/AlignmentGenerator.java
test/jalview/analysis/AlignmentUtilsTests.java
test/jalview/analysis/TestAlignSeq.java
test/jalview/datamodel/SequenceTest.java
test/jalview/ext/ensembl/EnsemblGeneTest.java
test/jalview/ext/ensembl/EnsemblSeqProxyTest.java
test/jalview/ext/rbvi/chimera/AtomSpecModelTest.java
test/jalview/gui/AlignmentPanelTest.java
test/jalview/gui/FreeUpMemoryTest.java [new file with mode: 0644]
test/jalview/gui/PairwiseAlignmentPanelTest.java [new file with mode: 0644]
test/jalview/gui/ProgressBarTest.java
test/jalview/gui/SeqCanvasTest.java [new file with mode: 0644]
test/jalview/renderer/ScaleRendererTest.java
test/jalview/renderer/seqfeatures/FeatureColourFinderTest.java
test/jalview/structures/models/AAStructureBindingModelTest.java
test/jalview/util/MappingUtilsTest.java
test/jalview/viewmodel/ViewportRangesTest.java
utils/checkstyle/checkstyle-suppress.xml
utils/checkstyle/import-control.xml

index 0329bb7..a87fa04 100644 (file)
@@ -8,5 +8,4 @@
     <file-match-pattern match-pattern="src/.*.java" include-pattern="true"/>
     <file-match-pattern match-pattern="resources/.*.properties" include-pattern="true"/>
   </fileset>
-  <filter name="NonSrcDirs" enabled="false"/>
 </fileset-config>
diff --git a/RELEASE b/RELEASE
index cecefec..f1faf34 100644 (file)
--- a/RELEASE
+++ b/RELEASE
@@ -1,2 +1,2 @@
-jalview.release=releases/Release_2_10_2b1_Branch
-jalview.version=2.10.2b2
+jalview.release=releases/Release_2_10_3_Branch
+jalview.version=2.10.3
diff --git a/examples/groovy/PIDmatrix.groovy b/examples/groovy/PIDmatrix.groovy
new file mode 100644 (file)
index 0000000..b97abcc
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+
+import jalview.analysis.scoremodels.ScoreModels
+import jalview.analysis.scoremodels.SimilarityParams
+
+// generate matrix for current selection using standard Jalview PID
+
+printSimilarityMatrix(true,true,SimilarityParams.Jalview)
+
+/** 
+ * this function prints a sequence similarity matrix in PHYLIP format. 
+ * printSimilarityMatrix(selected-only, include-ids, pidMethod)
+ * 
+ * Allowed values for pidMethod:
+ * 
+ * Jalview's Comparison.PID method includes matching gaps 
+ * and counts over the length of the shorter gapped sequence
+ * SimilarityParams.Jalview;
+ *
+ * 'SeqSpace' mode PCA calculation does not count matching 
+ * gaps but uses longest gapped sequence length
+ *  SimilarityParams.SeqSpace;
+ *
+ * PID calcs from the Raghava-Barton paper
+ * SimilarityParams.PID1: ignores gap-gap, does not score gap-residue,
+ * includes gap-residue in lengths, matches on longer of two sequences.
+ * 
+ * SimilarityParams.PID2: ignores gap-gap,ignores gap-residue, 
+ * matches on longer of two sequences
+ * 
+ * SimilarityParams.PID3: ignores gap-gap,ignores gap-residue, 
+ * matches on shorter of sequences only
+ * 
+ * SimilarityParams.PID4: ignores gap-gap,does not score gap-residue,
+ * includes gap-residue in lengths,matches on shorter of sequences only.
+ */
+
+void printSimilarityMatrix(boolean selview=false, boolean includeids=true, SimilarityParams pidMethod) {
+
+  def currentAlignFrame = jalview.bin.Jalview.getCurrentAlignFrame()
+
+  jalview.gui.AlignViewport av = currentAlignFrame.getCurrentView()
+
+  jalview.datamodel.AlignmentView seqStrings = av.getAlignmentView(selview)
+
+  if (!selview || av.getSelectionGroup()==null) {
+    start = 0
+    end = av.getAlignment().getWidth()
+    seqs = av.getAlignment().getSequencesArray()
+  } else {
+    start = av.getSelectionGroup().getStartRes()
+    end = av.getSelectionGroup().getEndRes() + 1
+    seqs = av.getSelectionGroup().getSequencesInOrder(av.getAlignment())
+  }
+
+  distanceCalc = ScoreModels.getInstance().getScoreModel("PID",
+      (jalview.api.AlignmentViewPanel) currentAlignFrame.alignPanel)
+
+  def distance=distanceCalc.findSimilarities(
+      seqStrings.getSequenceStrings(jalview.util.Comparison.GAP_DASH),pidMethod)
+
+  // output the PHYLIP Matrix
+
+  print distance.width()+" "+distance.height()+"\n"
+
+  p = 0
+
+  for (v in 1..distance.height()) {
+
+    if (includeids) {
+      print seqs[p++].getDisplayId(false)+" "
+    }
+
+    for (r in 1..distance.width()) {
+      print distance.getValue(v-1,r-1)+" "
+    }
+
+    print "\n"
+  }
+}
\ No newline at end of file
index bb80b84..1090253 100755 (executable)
   <p>
     Gap open : 12 <br> Gap extend : 2
   </p>
-  <p>When you select the pairwise alignment option a new window will
-    come up which will display the alignments in a text format as they
-    are calculated. Also displayed is information about the alignment
-    such as alignment score, length and percentage identity between the
+  <p>When you select the pairwise alignment option, a new window
+    will come up which displays the alignments in a text format, for
+    example:</p>
+  <p>
+  <pre>
+    FER1_SPIOL/5-13 TTMMGMAT<br />
+                    |. .. ||<br />
+    FER1_MESCR/5-15 TAALSGAT
+    </pre>
+  shows the aligned sequences, where '|' links identical residues, and
+  (for peptide) '.' links residues that have a positive PAM250 score.
+  <p>The window also shows information about the alignment such as
+    alignment score, length and percentage identity between the
     sequences.</p>
-  <p>&nbsp;</p>
+  <p>A button is also provided to allow you to view the sequences as
+    an alignment.</p>
 </body>
 </html>
index ed51a6a..92af377 100755 (executable)
@@ -85,16 +85,65 @@ li:before {
               <!-- JAL 2523-->More reliable Ensembl fetching with HTTP
               429 rate limit request hander
             </li>
+            <li>
+              <!-- JAL-2773 -->Structure views don't get updated unless
+              their colours have changed
+            </li>
+            <li><!-- JAL-2495 -->All linked sequences are highlighted for a structure mousover (Jmol) or selection (Chimera)</li>
+            <li><!-- JAL-2790 -->'Cancel' button in progress bar for JABAWS AACon, RNAAliFold and Disorder prediction jobs
+            </li>
+            
+            <li><!-- JAL-2617 -->Stop codons are excluded in CDS/Protein view from Ensembl locus cross-references</li>
+            <li><!-- JAL-2685 -->Start/End limits are shown in Pairwise Alignment report</li>
           </ul>
+          <ul><li>Example groovy script for generating a matrix of percent identity scores for current alignment.</li></ul>
+          <em>Testing and Deployment</em>
+          <ul><li><!-- JAL-2727 -->Test to catch memory leaks in Jalview UI</li></ul>
+          </div>
       </td>
       <td><div align="left">
-          <em></em>
+          <em>General</em>
+          <ul>
+            <li><!-- JAL-2643 -->Pressing tab after updating the colour threshold text field doesn't trigger an update to the alignment view</li>
+            <li><!-- JAL-2682 -->Race condition when parsing sequence ID strings in parallel</li>
+            <li><!-- JAL-2608 -->Overview windows are also closed when alignment window is closed</li>
+            <li><!-- JAL-2548 -->Export of features doesn't always respect group visibility</li> 
+          </ul>
+          <em>Desktop</em>
           <ul>
+            <li><!-- JAL-2777 -->Structures with whitespace chainCode cannot be viewed in Chimera</li>
             <li><!-- JAL-2728 -->Protein annotation panel too high in CDS/Protein view
             </li> 
             <li><!-- JAL-2757 -->Can't edit the query after the server error warning icon is shown in Uniprot and PDB Free Text Search Dialogs
             </li> 
+            <li><!-- JAL-2253 -->Slow EnsemblGenome ID lookup</li>
+            <li><!-- JAL-2529 -->Revised Ensembl REST API CDNA query</li>
+            <li><!-- JAL-2739 -->Hidden column marker in last column not rendered when switching back from Wrapped to normal view</li> 
+            <li><!-- JAL-2768 -->Annotation display corrupted when scrolling right in unwapped alignment view</li> 
+            <li><!-- JAL-2542 -->Existing features on subsequence incorrectly relocated when full sequence retrieved from database</li> 
+            <li><!-- JAL-2733 -->Last reported memory still shown when Desktop->Show Memory is unticked (OSX only)</li>
+            <li><!-- JAL-2658 -->Amend Features dialog doesn't allow features of same type and group to be selected for amending</li>
+            <li><!-- JAL-2524 -->Jalview becomes sluggish in wide alignments when hidden columns are present</li>
+            <li><!-- JAL-2392 -->Jalview freezes when loading and displaying several structures</li>
+            <li><!-- JAL-2732 -->Black outlines left after resizing or moving a window</li>
+            <li><!-- JAL-1900,JAL-1625 -->Unable to minimise windows within the Jalview desktop on OSX</li>
+            <li><!-- JAL-2667 -->Mouse wheel doesn't scroll vertically when in wrapped alignment mode</li>
+            <li><!-- JAL-2636 -->Scale mark not shown when close to right hand end of alignment</li>
+            <li><!-- JAL-2684 -->Pairwise alignment only aligns selected regions of each selected sequence</li>
+            <li><!-- JAL-2973 -->Alignment ruler height set incorrectly after canceling the Alignment Window's Font dialog</li>
+            <li><!-- JAL-2036 -->Show cross-references not enabled after restoring project until a new view is created</li>           
+           </ul>
+          <strong><em>Applet</em></strong><br/>
+           <ul>
+            <li><!-- JAL-2687 -->Concurrent modification exception when closing alignment panel</li> 
           </ul>
+          <strong><em>BioJSON</em></strong><br/>
+          <ul>
+          <li>
+            <!-- JAL-2546 -->BioJSON export does not preserve non-positional features
+          </li>
+          </ul>
+          </div>
       </td>
     </tr>
     <tr>
@@ -1452,6 +1501,10 @@ li:before {
               after clicking on it to create new annotation for a
               column.
             </li>
+            <li>
+              <!-- JAL-1980 -->Null Pointer Exception raised when 
+              pressing Add on an orphaned cut'n'paste window.
+            </li>
             <!--  may exclude, this is an external service stability issue  JAL-1941 
             -- > RNA 3D structure not added via DSSR service</li> -->
           </ul>
index f94faba..b15c3cc 100644 (file)
@@ -159,7 +159,7 @@ public class AppletPDBCanvas extends Panel
 
     try
     {
-      pdb = ssm.setMapping(seq, chains, pdbentry.getFile(), protocol);
+      pdb = ssm.setMapping(seq, chains, pdbentry.getFile(), protocol, null);
 
       if (protocol == DataSourceType.PASTE)
       {
index b2f2503..ab172f2 100644 (file)
@@ -153,7 +153,8 @@ public class PDBCanvas extends JPanel
 
     try
     {
-      pdb = ssm.setMapping(seq, chains, pdbentry.getFile(), protocol);
+      pdb = ssm.setMapping(seq, chains, pdbentry.getFile(), protocol,
+              ap.alignFrame);
 
       if (protocol.equals(jalview.io.DataSourceType.PASTE))
       {
index 0045e97..3abbe75 100644 (file)
@@ -383,6 +383,8 @@ public class ChimeraResidue implements ChimeraStructuralObject,
   public void splitInsertionCode(String residue)
   {
     // OK, split the index into number and insertion code
+    // JBPNote - m.matches() can be true even if there is no resnum - this can
+    // cause NumberFormatExceptions below
     Pattern p = Pattern.compile("(\\d*)([A-Z]?)");
     Matcher m = p.matcher(residue);
     if (m.matches())
index 34a21e6..1b2578e 100755 (executable)
@@ -36,6 +36,7 @@ import jalview.util.MessageManager;
 
 import java.awt.Color;
 import java.awt.Graphics;
+import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -49,6 +50,14 @@ import java.util.StringTokenizer;
  */
 public class AlignSeq
 {
+  private static final int MAX_NAME_LENGTH = 30;
+
+  private static final int GAP_OPEN_COST = 120;
+
+  private static final int GAP_EXTEND_COST = 20;
+
+  private static final int GAP_INDEX = -1;
+
   public static final String PEP = "pep";
 
   public static final String DNA = "dna";
@@ -61,7 +70,7 @@ public class AlignSeq
 
   float[][] F;
 
-  int[][] traceback;
+  int[][] traceback; // todo is this actually used?
 
   int[] seq1;
 
@@ -96,30 +105,20 @@ public class AlignSeq
   /** DOCUMENT ME!! */
   public int seq2start;
 
-  /** DOCUMENT ME!! */
   public int seq2end;
 
   int count;
 
-  /** DOCUMENT ME!! */
   public float maxscore;
 
-  float pid;
-
   int prev = 0;
 
-  int gapOpen = 120;
-
-  int gapExtend = 20;
-
   StringBuffer output = new StringBuffer();
 
   String type; // AlignSeq.PEP or AlignSeq.DNA
 
   private ScoreMatrix scoreMatrix;
 
-  private static final int GAP_INDEX = -1;
-
   /**
    * Creates a new AlignSeq object.
    * 
@@ -378,11 +377,10 @@ public class AlignSeq
       }
     }
 
-    // System.out.println(maxi + " " + maxj + " " + score[maxi][maxj]);
     int i = maxi;
     int j = maxj;
     int trace;
-    maxscore = score[i][j] / 10;
+    maxscore = score[i][j] / 10f;
 
     seq1end = maxi + 1;
     seq2end = maxj + 1;
@@ -451,49 +449,48 @@ public class AlignSeq
   /**
    * DOCUMENT ME!
    */
-  public void printAlignment(java.io.PrintStream os)
+  public void printAlignment(PrintStream os)
   {
     // TODO: Use original sequence characters rather than re-translated
     // characters in output
     // Find the biggest id length for formatting purposes
-    String s1id = s1.getName(), s2id = s2.getName();
-    int maxid = s1.getName().length();
-    if (s2.getName().length() > maxid)
-    {
-      maxid = s2.getName().length();
-    }
-    if (maxid > 30)
+    String s1id = getAlignedSeq1().getDisplayId(true);
+    String s2id = getAlignedSeq2().getDisplayId(true);
+    int nameLength = Math.max(s1id.length(), s2id.length());
+    if (nameLength > MAX_NAME_LENGTH)
     {
-      maxid = 30;
+      int truncateBy = nameLength - MAX_NAME_LENGTH;
+      nameLength = MAX_NAME_LENGTH;
       // JAL-527 - truncate the sequence ids
-      if (s1.getName().length() > maxid)
+      if (s1id.length() > nameLength)
       {
-        s1id = s1.getName().substring(0, 30);
+        int slashPos = s1id.lastIndexOf('/');
+        s1id = s1id.substring(0, slashPos - truncateBy)
+                + s1id.substring(slashPos);
       }
-      if (s2.getName().length() > maxid)
+      if (s2id.length() > nameLength)
       {
-        s2id = s2.getName().substring(0, 30);
+        int slashPos = s2id.lastIndexOf('/');
+        s2id = s2id.substring(0, slashPos - truncateBy)
+                + s2id.substring(slashPos);
       }
     }
-    int len = 72 - maxid - 1;
+    int len = 72 - nameLength - 1;
     int nochunks = ((aseq1.length - count) / len)
             + ((aseq1.length - count) % len > 0 ? 1 : 0);
-    pid = 0;
+    float pid = 0f;
 
     output.append("Score = ").append(score[maxi][maxj]).append(NEWLINE);
     output.append("Length of alignment = ")
             .append(String.valueOf(aseq1.length - count)).append(NEWLINE);
     output.append("Sequence ");
-    output.append(new Format("%" + maxid + "s").form(s1.getName()));
-    output.append(" :  ").append(String.valueOf(s1.getStart()))
-            .append(" - ").append(String.valueOf(s1.getEnd()));
+    Format nameFormat = new Format("%" + nameLength + "s");
+    output.append(nameFormat.form(s1id));
     output.append(" (Sequence length = ")
             .append(String.valueOf(s1str.length())).append(")")
             .append(NEWLINE);
     output.append("Sequence ");
-    output.append(new Format("%" + maxid + "s").form(s2.getName()));
-    output.append(" :  ").append(String.valueOf(s2.getStart()))
-            .append(" - ").append(String.valueOf(s2.getEnd()));
+    output.append(nameFormat.form(s2id));
     output.append(" (Sequence length = ")
             .append(String.valueOf(s2str.length())).append(")")
             .append(NEWLINE).append(NEWLINE);
@@ -503,7 +500,7 @@ public class AlignSeq
     for (int j = 0; j < nochunks; j++)
     {
       // Print the first aligned sequence
-      output.append(new Format("%" + (maxid) + "s").form(s1id)).append(" ");
+      output.append(nameFormat.form(s1id)).append(" ");
 
       for (int i = 0; i < len; i++)
       {
@@ -514,7 +511,7 @@ public class AlignSeq
       }
 
       output.append(NEWLINE);
-      output.append(new Format("%" + (maxid) + "s").form(" ")).append(" ");
+      output.append(nameFormat.form(" ")).append(" ");
 
       /*
        * Print out the match symbols:
@@ -534,7 +531,7 @@ public class AlignSeq
             pid++;
             output.append("|");
           }
-          else if (type.equals("pep"))
+          else if (PEP.equals(type))
           {
             if (pam250.getPairwiseScore(c1, c2) > 0)
             {
@@ -554,8 +551,7 @@ public class AlignSeq
 
       // Now print the second aligned sequence
       output = output.append(NEWLINE);
-      output = output.append(new Format("%" + (maxid) + "s").form(s2id))
-              .append(" ");
+      output = output.append(nameFormat.form(s2id)).append(" ");
 
       for (int i = 0; i < len; i++)
       {
@@ -569,7 +565,8 @@ public class AlignSeq
     }
 
     pid = pid / (aseq1.length - count) * 100;
-    output = output.append(new Format("Percentage ID = %2.2f\n").form(pid));
+    output.append(new Format("Percentage ID = %3.2f\n").form(pid));
+    output.append(NEWLINE);
     try
     {
       os.print(output.toString());
@@ -591,7 +588,6 @@ public class AlignSeq
   public int findTrace(int i, int j)
   {
     int t = 0;
-    // float pairwiseScore = lookup[seq1[i]][seq2[j]];
     float pairwiseScore = scoreMatrix.getPairwiseScore(s1str.charAt(i),
             s2str.charAt(j));
     float max = score[i - 1][j - 1] + (pairwiseScore * 10);
@@ -640,19 +636,19 @@ public class AlignSeq
     // top left hand element
     score[0][0] = scoreMatrix.getPairwiseScore(s1str.charAt(0),
             s2str.charAt(0)) * 10;
-    E[0][0] = -gapExtend;
+    E[0][0] = -GAP_EXTEND_COST;
     F[0][0] = 0;
 
     // Calculate the top row first
     for (int j = 1; j < m; j++)
     {
       // What should these values be? 0 maybe
-      E[0][j] = max(score[0][j - 1] - gapOpen, E[0][j - 1] - gapExtend);
-      F[0][j] = -gapExtend;
+      E[0][j] = max(score[0][j - 1] - GAP_OPEN_COST, E[0][j - 1] - GAP_EXTEND_COST);
+      F[0][j] = -GAP_EXTEND_COST;
 
       float pairwiseScore = scoreMatrix.getPairwiseScore(s1str.charAt(0),
               s2str.charAt(j));
-      score[0][j] = max(pairwiseScore * 10, -gapOpen, -gapExtend);
+      score[0][j] = max(pairwiseScore * 10, -GAP_OPEN_COST, -GAP_EXTEND_COST);
 
       traceback[0][j] = 1;
     }
@@ -660,8 +656,8 @@ public class AlignSeq
     // Now do the left hand column
     for (int i = 1; i < n; i++)
     {
-      E[i][0] = -gapOpen;
-      F[i][0] = max(score[i - 1][0] - gapOpen, F[i - 1][0] - gapExtend);
+      E[i][0] = -GAP_OPEN_COST;
+      F[i][0] = max(score[i - 1][0] - GAP_OPEN_COST, F[i - 1][0] - GAP_EXTEND_COST);
 
       float pairwiseScore = scoreMatrix.getPairwiseScore(s1str.charAt(i),
               s2str.charAt(0));
@@ -674,8 +670,8 @@ public class AlignSeq
     {
       for (int j = 1; j < m; j++)
       {
-        E[i][j] = max(score[i][j - 1] - gapOpen, E[i][j - 1] - gapExtend);
-        F[i][j] = max(score[i - 1][j] - gapOpen, F[i - 1][j] - gapExtend);
+        E[i][j] = max(score[i][j - 1] - GAP_OPEN_COST, E[i][j - 1] - GAP_EXTEND_COST);
+        F[i][j] = max(score[i - 1][j] - GAP_OPEN_COST, F[i - 1][j] - GAP_EXTEND_COST);
 
         float pairwiseScore = scoreMatrix.getPairwiseScore(s1str.charAt(i),
                 s2str.charAt(j));
index 2b9b9f9..90d9197 100644 (file)
@@ -2164,7 +2164,10 @@ public class AlignmentUtils
 
   /**
    * Returns a mapping from dna to protein by inspecting sequence features of
-   * type "CDS" on the dna.
+   * type "CDS" on the dna. A mapping is constructed if the total CDS feature
+   * length is 3 times the peptide length (optionally after dropping a trailing
+   * stop codon). This method does not check whether the CDS nucleotide sequence
+   * translates to the peptide sequence.
    * 
    * @param dnaSeq
    * @param proteinSeq
@@ -2176,6 +2179,15 @@ public class AlignmentUtils
     List<int[]> ranges = findCdsPositions(dnaSeq);
     int mappedDnaLength = MappingUtils.getLength(ranges);
 
+    /*
+     * if not a whole number of codons, something is wrong,
+     * abort mapping
+     */
+    if (mappedDnaLength % CODON_LENGTH > 0)
+    {
+      return null;
+    }
+
     int proteinLength = proteinSeq.getLength();
     int proteinStart = proteinSeq.getStart();
     int proteinEnd = proteinSeq.getEnd();
@@ -2199,8 +2211,12 @@ public class AlignmentUtils
     if (codesForResidues == (proteinLength + 1))
     {
       // assuming extra codon is for STOP and not in peptide
+      // todo: check trailing codon is indeed a STOP codon
       codesForResidues--;
+      mappedDnaLength -= CODON_LENGTH;
+      MappingUtils.removeEndPositions(CODON_LENGTH, ranges);
     }
+
     if (codesForResidues == proteinLength)
     {
       proteinRange.add(new int[] { proteinStart, proteinEnd });
@@ -2211,7 +2227,7 @@ public class AlignmentUtils
 
   /**
    * Returns a list of CDS ranges found (as sequence positions base 1), i.e. of
-   * start/end positions of sequence features of type "CDS" (or a sub-type of
+   * [start, end] positions of sequence features of type "CDS" (or a sub-type of
    * CDS in the Sequence Ontology). The ranges are sorted into ascending start
    * position order, so this method is only valid for linear CDS in the same
    * sense as the protein product.
@@ -2230,7 +2246,6 @@ public class AlignmentUtils
       return result;
     }
     SequenceFeatures.sortFeatures(sfs, true);
-    int startPhase = 0;
 
     for (SequenceFeature sf : sfs)
     {
@@ -2248,7 +2263,7 @@ public class AlignmentUtils
        */
       int begin = sf.getBegin();
       int end = sf.getEnd();
-      if (result.isEmpty())
+      if (result.isEmpty() && phase > 0)
       {
         begin += phase;
         if (begin > end)
@@ -2263,16 +2278,6 @@ public class AlignmentUtils
     }
 
     /*
-     * remove 'startPhase' positions (usually 0) from the first range 
-     * so we begin at the start of a complete codon
-     */
-    if (!result.isEmpty())
-    {
-      // TODO JAL-2022 correctly model start phase > 0
-      result.get(0)[0] += startPhase;
-    }
-
-    /*
      * Finally sort ranges by start position. This avoids a dependency on 
      * keeping features in order on the sequence (if they are in order anyway,
      * the sort will have almost no work to do). The implicit assumption is CDS
index 3cb06c1..931eba6 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.api;
 
 import jalview.analysis.Conservation;
+import jalview.analysis.TreeModel;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
@@ -485,4 +486,8 @@ public interface AlignViewportI extends ViewStyleI
    */
   @Override
   void setProteinFontAsCdna(boolean b);
+
+  public abstract TreeModel getCurrentTree();
+
+  public abstract void setCurrentTree(TreeModel tree);
 }
index ef59996..0b1ca21 100644 (file)
@@ -43,9 +43,10 @@ public interface AlignmentViewPanel extends OOMHandlerI
    * 
    * @param updateOverview
    *          - if true, the overview panel will also be updated and repainted
+   * @param updateStructures
+   *          - if true then any linked structure views will also be updated
    */
-
-  void paintAlignment(boolean updateOverview);
+  void paintAlignment(boolean updateOverview, boolean updateStructures);
 
   /**
    * automatically adjust annotation panel height for new annotation whilst
index 9d44479..46bd4fd 100644 (file)
@@ -383,7 +383,7 @@ public class APopupMenu extends java.awt.PopupMenu
   void addFeatureLinks(final SequenceI seq, List<String> links)
   {
     Menu linkMenu = new Menu(MessageManager.getString("action.link"));
-    Map<String, List<String>> linkset = new LinkedHashMap<String, List<String>>();
+    Map<String, List<String>> linkset = new LinkedHashMap<>();
 
     for (String link : links)
     {
@@ -485,8 +485,8 @@ public class APopupMenu extends java.awt.PopupMenu
      * Temporary store to hold distinct calcId / type pairs for the tooltip.
      * Using TreeMap means calcIds are shown in alphabetical order.
      */
-    SortedMap<String, String> tipEntries = new TreeMap<String, String>();
-    final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<SequenceI, List<AlignmentAnnotation>>();
+    SortedMap<String, String> tipEntries = new TreeMap<>();
+    final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
     AlignmentI al = this.ap.av.getAlignment();
     AlignmentUtils.findAddableReferenceAnnotations(forSequences, tipEntries,
             candidates, al);
@@ -825,8 +825,8 @@ public class APopupMenu extends java.awt.PopupMenu
       }
 
       int gSize = sg.getSize();
-      List<SequenceI> seqs = new ArrayList<SequenceI>();
-      List<SequenceFeature> features = new ArrayList<SequenceFeature>();
+      List<SequenceI> seqs = new ArrayList<>();
+      List<SequenceFeature> features = new ArrayList<>();
 
       for (int i = 0; i < gSize; i++)
       {
@@ -930,7 +930,7 @@ public class APopupMenu extends java.awt.PopupMenu
     {
       seq.setName(dialog.getName());
       seq.setDescription(dialog.getDescription());
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
   }
 
@@ -1163,7 +1163,7 @@ public class APopupMenu extends java.awt.PopupMenu
 
   void refresh()
   {
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   protected void clustalColour_actionPerformed()
@@ -1339,7 +1339,7 @@ public class APopupMenu extends java.awt.PopupMenu
     SequenceGroup sg = ap.av.getSelectionGroup();
     ap.av.getAlignment().deleteGroup(sg);
     ap.av.setSelectionGroup(null);
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   void createGroupMenuItem_actionPerformed()
@@ -1440,8 +1440,8 @@ public class APopupMenu extends java.awt.PopupMenu
      * the insertion order, which is the order of the annotations on the
      * alignment.
      */
-    Map<String, List<List<String>>> shownTypes = new LinkedHashMap<String, List<List<String>>>();
-    Map<String, List<List<String>>> hiddenTypes = new LinkedHashMap<String, List<List<String>>>();
+    Map<String, List<List<String>>> shownTypes = new LinkedHashMap<>();
+    Map<String, List<List<String>>> hiddenTypes = new LinkedHashMap<>();
     AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes,
             AlignmentAnnotationUtils.asList(annotations), forSequences);
 
index ed04a0a..ef87671 100644 (file)
@@ -343,7 +343,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     createAlignFrameWindow(embedded);
     validate();
     alignPanel.adjustAnnotationHeight();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
   }
 
   public AlignViewport getAlignViewport()
@@ -415,7 +415,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
       {
         viewport.featureSettings.refreshTable();
       }
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       statusBar.setText(MessageManager
               .getString("label.successfully_added_features_alignment"));
     }
@@ -691,7 +691,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
       break;
 
     }
-    alignPanel.paintAlignment(true);
+    // TODO: repaint flags set only if the keystroke warrants it
+    alignPanel.paintAlignment(true, true);
   }
 
   /**
@@ -917,7 +918,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     {
       applyAutoAnnotationSettings_actionPerformed();
     }
-    alignPanel.paintAlignment(true);
+    // TODO: repaint flags set only if warranted
+    alignPanel.paintAlignment(true, true);
   }
 
   /**
@@ -1094,7 +1096,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     else if (source == invertColSel)
     {
       viewport.invertColumnSelection();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(false, false);
       viewport.sendSelection();
     }
     else if (source == remove2LeftMenuItem)
@@ -1128,34 +1130,34 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     else if (source == showColumns)
     {
       viewport.showAllHiddenColumns();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       viewport.sendSelection();
     }
     else if (source == showSeqs)
     {
       viewport.showAllHiddenSeqs();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       // uncomment if we want to slave sequence selections in split frame
       // viewport.sendSelection();
     }
     else if (source == hideColumns)
     {
       viewport.hideSelectedColumns();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       viewport.sendSelection();
     }
     else if (source == hideSequences
             && viewport.getSelectionGroup() != null)
     {
       viewport.hideAllSelectedSeqs();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       // uncomment if we want to slave sequence selections in split frame
       // viewport.sendSelection();
     }
     else if (source == hideAllButSelection)
     {
       toggleHiddenRegions(false, false);
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       viewport.sendSelection();
     }
     else if (source == hideAllSelection)
@@ -1164,14 +1166,14 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
       viewport.expandColSelection(sg, false);
       viewport.hideAllSelectedSeqs();
       viewport.hideSelectedColumns();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       viewport.sendSelection();
     }
     else if (source == showAllHidden)
     {
       viewport.showAllHiddenColumns();
       viewport.showAllHiddenSeqs();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       viewport.sendSelection();
     }
     else if (source == showGroupConsensus)
@@ -1601,10 +1603,12 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     {
       System.exit(0);
     }
-    else
+
+    viewport = null;
+    if (alignPanel != null && alignPanel.overviewPanel != null)
     {
+      alignPanel.overviewPanel.dispose();
     }
-    viewport = null;
     alignPanel = null;
     this.dispose();
   }
@@ -1781,7 +1785,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     }
     viewport.getAlignment().moveSelectedSequencesByOne(sg,
             up ? null : viewport.getHiddenRepSequences(), up);
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
 
     /*
      * Also move cDNA/protein complement sequences
@@ -1793,7 +1797,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
               viewport, complement);
       complement.getAlignment().moveSelectedSequencesByOne(mappedSelection,
               up ? null : complement.getHiddenRepSequences(), up);
-      getSplitFrame().getComplement(this).alignPanel.paintAlignment(true);
+      getSplitFrame().getComplement(this).alignPanel.paintAlignment(true,
+              false);
     }
   }
 
@@ -2226,7 +2231,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     {
       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
       alignPanel.updateAnnotation();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
     }
   }
 
@@ -2263,7 +2268,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     // JAL-2034 - should delegate to
     // alignPanel to decide if overview needs
     // updating.
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -2283,7 +2288,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     // JAL-2034 - should delegate to
     // alignPanel to decide if overview needs
     // updating.
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -2303,7 +2308,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
   public void invertColSel_actionPerformed()
   {
     viewport.invertColumnSelection();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -2595,19 +2600,19 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
   {
     viewport.setShowJVSuffix(seqLimits.getState());
     alignPanel.fontChanged();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   protected void colourTextMenuItem_actionPerformed()
   {
     viewport.setColourText(colourTextMenuItem.getState());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   protected void displayNonconservedMenuItem_actionPerformed()
   {
     viewport.setShowUnconserved(displayNonconservedMenuItem.getState());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   protected void wrapMenuItem_actionPerformed()
@@ -2617,7 +2622,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     scaleAbove.setEnabled(wrapMenuItem.getState());
     scaleLeft.setEnabled(wrapMenuItem.getState());
     scaleRight.setEnabled(wrapMenuItem.getState());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   public void overviewMenuItem_actionPerformed()
@@ -2660,7 +2665,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
   {
     viewport.setGlobalColourScheme(cs);
 
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
   }
 
   protected void modifyPID_actionPerformed()
@@ -2735,7 +2740,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
 
     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
             viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   public void sortIDMenuItem_actionPerformed()
@@ -2744,7 +2749,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     AlignmentSorter.sortByID(viewport.getAlignment());
     addHistoryItem(
             new OrderCommand("ID Sort", oldOrder, viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   public void sortLengthMenuItem_actionPerformed()
@@ -2753,7 +2758,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     AlignmentSorter.sortByLength(viewport.getAlignment());
     addHistoryItem(new OrderCommand("Length Sort", oldOrder,
             viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   public void sortGroupMenuItem_actionPerformed()
@@ -2762,7 +2767,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     AlignmentSorter.sortByGroup(viewport.getAlignment());
     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
             viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
 
   }
 
@@ -2802,7 +2807,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
           current.insertCharAt(Width - 1, viewport.getGapCharacter());
         }
       }
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(false, false);
     }
 
     if ((viewport.getSelectionGroup() != null
@@ -2866,7 +2871,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
           current.insertCharAt(Width - 1, viewport.getGapCharacter());
         }
       }
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(false, false);
 
     }
 
@@ -2919,7 +2924,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     addHistoryItem(new OrderCommand(MessageManager
             .formatMessage("label.order_by_params", new String[]
             { title }), oldOrder, viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -2977,7 +2982,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
       addHistoryItem(new OrderCommand(undoname, oldOrder,
               viewport.getAlignment()));
     }
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
     return true;
   }
 
@@ -4144,7 +4149,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     {
       // register the association(s) and quit, don't create any windows.
       if (StructureSelectionManager.getStructureSelectionManager(applet)
-              .setMapping(seqs, chains, pdb.getFile(), protocol) == null)
+              .setMapping(seqs, chains, pdb.getFile(), protocol, null) == null)
       {
         System.err.println("Failed to map " + pdb.getFile() + " ("
                 + protocol + ") to any sequences");
index b07666e..262948d 100644 (file)
@@ -20,7 +20,6 @@
  */
 package jalview.appletgui;
 
-import jalview.analysis.TreeModel;
 import jalview.api.AlignViewportI;
 import jalview.api.FeatureSettingsModelI;
 import jalview.bin.JalviewLite;
@@ -54,23 +53,12 @@ public class AlignViewport extends AlignmentViewport
 
   boolean validCharWidth = true;
 
-  TreeModel currentTree = null;
-
   public jalview.bin.JalviewLite applet;
 
   boolean MAC = false;
 
   private AnnotationColumnChooser annotationColumnSelectionState;
 
-  @Override
-  public void finalize()
-  {
-    applet = null;
-    quality = null;
-    alignment = null;
-    colSel = null;
-  }
-
   public AlignViewport(AlignmentI al, JalviewLite applet)
   {
     super(al);
@@ -274,16 +262,6 @@ public class AlignViewport extends AlignmentViewport
     ranges.setEndSeq(height / getCharHeight());
   }
 
-  public void setCurrentTree(TreeModel tree)
-  {
-    currentTree = tree;
-  }
-
-  public TreeModel getCurrentTree()
-  {
-    return currentTree;
-  }
-
   boolean centreColumnLabels;
 
   public boolean getCentreColumnLabels()
index 8e333ba..270b2f7 100644 (file)
@@ -73,23 +73,6 @@ public class AlignmentPanel extends Panel
   // this value is set false when selection area being dragged
   boolean fastPaint = true;
 
-  @Override
-  public void finalize() throws Throwable
-  {
-    alignFrame = null;
-    av = null;
-    vpRanges = null;
-    seqPanel = null;
-    seqPanelHolder = null;
-    sequenceHolderPanel = null;
-    scalePanel = null;
-    scalePanelHolder = null;
-    annotationPanel = null;
-    annotationPanelHolder = null;
-    annotationSpaceFillerHolder = null;
-    super.finalize();
-  }
-
   public AlignmentPanel(AlignFrame af, final AlignViewport av)
   {
     try
@@ -530,7 +513,7 @@ public class AlignmentPanel extends Panel
       vpRanges.scrollToWrappedVisible(start);
     }
 
-    paintAlignment(redrawOverview);
+    paintAlignment(redrawOverview, false);
     return true;
   }
 
@@ -579,7 +562,7 @@ public class AlignmentPanel extends Panel
     apvscroll.addNotify();
     hscroll.addNotify();
     validate();
-    paintAlignment(true);
+    paintAlignment(true, false);
   }
 
   /**
@@ -930,7 +913,8 @@ public class AlignmentPanel extends Panel
    * Repaint the alignment and annotations, and, optionally, any overview window
    */
   @Override
-  public void paintAlignment(boolean updateOverview)
+  public void paintAlignment(boolean updateOverview,
+          boolean updateStructures)
   {
     final AnnotationSorter sorter = new AnnotationSorter(getAlignment(),
             av.isShowAutocalculatedAbove());
@@ -938,13 +922,14 @@ public class AlignmentPanel extends Panel
             av.getSortAnnotationsBy());
     repaint();
 
-    if (updateOverview)
+    if (updateStructures)
     {
-      // TODO: determine if this paintAlignment changed structure colours
       jalview.structure.StructureSelectionManager
               .getStructureSelectionManager(av.applet)
               .sequenceColoursChanged(this);
-
+    }
+    if (updateOverview)
+    {
       if (overviewPanel != null)
       {
         overviewPanel.updateOverviewImage();
index 8de751a..533226e 100644 (file)
@@ -85,7 +85,7 @@ public class AnnotationColourChooser extends Panel implements
     oldcs = av.getGlobalColourScheme();
     if (av.getAlignment().getGroups() != null)
     {
-      oldgroupColours = new HashMap<SequenceGroup, ColourSchemeI>();
+      oldgroupColours = new HashMap<>();
       for (SequenceGroup sg : ap.av.getAlignment().getGroups())
       {
         oldgroupColours.put(sg, sg.getColourScheme());
@@ -180,8 +180,8 @@ public class AnnotationColourChooser extends Panel implements
     // TODO remove duplication with gui.AnnotationRowFilter
     // TODO add 'per sequence only' option / parameter
 
-    annotationLabels = new HashMap<AlignmentAnnotation, String>();
-    Vector<String> list = new Vector<String>();
+    annotationLabels = new HashMap<>();
+    Vector<String> list = new Vector<>();
     AlignmentAnnotation[] anns = av.getAlignment().getAlignmentAnnotation();
     if (anns == null)
     {
@@ -376,7 +376,7 @@ public class AnnotationColourChooser extends Panel implements
     else if (evt.getSource() == cancel)
     {
       reset();
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
       frame.setVisible(false);
     }
 
@@ -417,7 +417,7 @@ public class AnnotationColourChooser extends Panel implements
       }
 
       currentAnnotation.threshold.value = slider.getValue() / 1000f;
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
   }
 
@@ -559,7 +559,7 @@ public class AnnotationColourChooser extends Panel implements
 
     // update colours in linked windows
     ap.alignmentChanged();
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   void reset()
@@ -572,7 +572,7 @@ public class AnnotationColourChooser extends Panel implements
         sg.setColourScheme(oldgroupColours.get(sg));
       }
     }
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   @Override
@@ -588,7 +588,7 @@ public class AnnotationColourChooser extends Panel implements
   @Override
   public void mouseReleased(MouseEvent evt)
   {
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   @Override
index b4c1d54..7674de7 100644 (file)
@@ -306,7 +306,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
         av.getAlignment().setHiddenColumns(oldHidden);
       }
       av.sendSelection();
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
     }
 
   }
@@ -348,7 +348,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
           sliderDragging = false;
           valueChanged(true);
         }
-        ap.paintAlignment(true);
+        ap.paintAlignment(true, true);
       }
     });
   }
@@ -359,8 +359,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     if (slider.isEnabled())
     {
       getCurrentAnnotation().threshold.value = slider.getValue() / 1000f;
-      updateView();
-      ap.paintAlignment(false);
+      updateView(); // this also calls paintAlignment(true,true)
     }
   }
 
@@ -515,7 +514,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     filterParams = null;
     av.setAnnotationColumnSelectionState(this);
     av.sendSelection();
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   public HiddenColumns getOldHiddenColumns()
index 2fb737a..d8f65a5 100755 (executable)
@@ -226,7 +226,8 @@ public class AnnotationLabels extends Panel
     ap.annotationPanel.adjustPanelHeight();
     setSize(getSize().width, ap.annotationPanel.getSize().height);
     ap.validate();
-    ap.paintAlignment(true);
+    // TODO: only paint if we needed to
+    ap.paintAlignment(true, true);
   }
 
   boolean editLabelDescription(AlignmentAnnotation annotation)
@@ -548,7 +549,7 @@ public class AnnotationLabels extends Panel
                 {
                   ap.av.setIgnoreGapsConsensus(cbmi.getState(), ap);
                 }
-                ap.paintAlignment(true);
+                ap.paintAlignment(true, true);
               }
             });
             popup.add(cbmi);
@@ -756,7 +757,7 @@ public class AnnotationLabels extends Panel
                 }
               }
             }
-            ap.paintAlignment(false);
+            ap.paintAlignment(false, false);
             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
             ap.av.sendSelection();
           }
@@ -813,7 +814,7 @@ public class AnnotationLabels extends Panel
               sg.addSequence(aa[selectedRow].sequenceRef, false);
             }
             ap.av.setSelectionGroup(sg);
-            ap.paintAlignment(false);
+            ap.paintAlignment(false, false);
             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
             ap.av.sendSelection();
           }
index 88408bb..2b2fdea 100755 (executable)
@@ -439,7 +439,8 @@ public class AnnotationPanel extends Panel
       graphStretchY = evt.getY();
       av.calcPanelHeight();
       needValidating = true;
-      ap.paintAlignment(true);
+      // TODO: only update overview visible geometry
+      ap.paintAlignment(true, false);
     }
     else
     {
index 5efd177..c96dbab 100644 (file)
@@ -114,7 +114,7 @@ public abstract class AnnotationRowFilter extends Panel
   public void cancel_actionPerformed(ActionEvent e)
   {
     reset();
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
     frame.setVisible(false);
   }
 
index 49219b9..3d1442d 100644 (file)
@@ -134,7 +134,7 @@ public class AppletJmol extends EmbmenuFrame implements
 
   AlignmentPanel ap;
 
-  List<AlignmentPanel> _aps = new ArrayList<AlignmentPanel>(); // remove? never
+  List<AlignmentPanel> _aps = new ArrayList<>(); // remove? never
                                                                // added to
 
   String fileLoadingError;
@@ -213,7 +213,7 @@ public class AppletJmol extends EmbmenuFrame implements
     {
       reader = StructureSelectionManager
               .getStructureSelectionManager(ap.av.applet)
-              .setMapping(seq, chains, pdbentry.getFile(), protocol);
+              .setMapping(seq, chains, pdbentry.getFile(), protocol, null);
       // PROMPT USER HERE TO ADD TO NEW OR EXISTING VIEW?
       // FOR NOW, LETS JUST OPEN A NEW WINDOW
     }
@@ -394,7 +394,7 @@ public class AppletJmol extends EmbmenuFrame implements
 
   void centerViewer()
   {
-    Vector<String> toshow = new Vector<String>();
+    Vector<String> toshow = new Vector<>();
     for (int i = 0; i < chainMenu.getItemCount(); i++)
     {
       if (chainMenu.getItem(i) instanceof CheckboxMenuItem)
index d5d53fb..2f61b24 100644 (file)
@@ -24,6 +24,7 @@ import jalview.api.AlignmentViewPanel;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.ext.jmol.JalviewJmolBinding;
+import jalview.gui.IProgressIndicator;
 import jalview.io.DataSourceType;
 import jalview.structure.StructureSelectionManager;
 
@@ -183,4 +184,11 @@ class AppletJmolBinding extends JalviewJmolBinding
     // TODO Auto-generated method stub
     return null;
   }
+
+  @Override
+  protected IProgressIndicator getIProgressIndicator()
+  {
+    // no progress indicators on the applet
+    return null;
+  }
 }
index 3966536..89228d5 100644 (file)
@@ -26,6 +26,7 @@ import jalview.api.SequenceRenderer;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.ext.jmol.JalviewJmolBinding;
+import jalview.gui.IProgressIndicator;
 import jalview.io.DataSourceType;
 
 import java.awt.Container;
@@ -65,6 +66,13 @@ public class ExtJmol extends JalviewJmolBinding
   }
 
   @Override
+  protected IProgressIndicator getIProgressIndicator()
+  {
+    // no progress indicators on applet (could access javascript for this)
+    return null;
+  }
+
+  @Override
   public void updateColours(Object source)
   {
 
@@ -92,6 +100,7 @@ public class ExtJmol extends JalviewJmolBinding
     }
   }
 
+
   @Override
   public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment)
   {
@@ -137,8 +146,8 @@ public class ExtJmol extends JalviewJmolBinding
   @Override
   public void refreshPdbEntries()
   {
-    List<PDBEntry> pdbe = new ArrayList<PDBEntry>();
-    List<String> fileids = new ArrayList<String>();
+    List<PDBEntry> pdbe = new ArrayList<>();
+    List<String> fileids = new ArrayList<>();
     SequenceI[] sq = ap.av.getAlignment().getSequencesArray();
     for (int s = 0; s < sq.length; s++)
     {
index b35c079..df407d6 100644 (file)
@@ -493,7 +493,7 @@ public class FeatureRenderer
     }
     // findAllFeatures();
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
 
     return true;
   }
index 20d4d74..9a67499 100755 (executable)
@@ -377,8 +377,8 @@ public class FeatureSettings extends Panel
   // Group selection states
   void resetTable(boolean groupsChanged)
   {
-    List<String> displayableTypes = new ArrayList<String>();
-    Set<String> foundGroups = new HashSet<String>();
+    List<String> displayableTypes = new ArrayList<>();
+    Set<String> foundGroups = new HashSet<>();
 
     AlignmentI alignment = av.getAlignment();
 
@@ -391,7 +391,7 @@ public class FeatureSettings extends Panel
        * and keep track of which groups are visible
        */
       Set<String> groups = seq.getFeatures().getFeatureGroups(true);
-      Set<String> visibleGroups = new HashSet<String>();
+      Set<String> visibleGroups = new HashSet<>();
       for (String group : groups)
       {
         // if (group == null || fr.checkGroupVisibility(group, true))
@@ -600,7 +600,7 @@ public class FeatureSettings extends Panel
 
     fr.setFeaturePriority(data);
 
-    ap.paintAlignment(updateOverview);
+    ap.paintAlignment(updateOverview, updateOverview);
   }
 
   MyCheckbox selectedCheck;
@@ -680,7 +680,7 @@ public class FeatureSettings extends Panel
   {
     featurePanel.removeAll();
     resetTable(false);
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   @Override
@@ -732,7 +732,7 @@ public class FeatureSettings extends Panel
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
     fr.setTransparency((100 - transparency.getValue()) / 100f);
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   class MyCheckbox extends Checkbox
index c9a92b2..443ebce 100644 (file)
@@ -261,7 +261,7 @@ public class FontChooser extends Panel implements ItemListener
       {
         ap.av.setCharWidth(oldCharWidth);
       }
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, false);
     }
     else if (tp != null)
     {
index 7d9d278..15e269c 100755 (executable)
@@ -70,7 +70,7 @@ public class IdPanel extends Panel
     // TODO: add in group link parameter
 
     // make a list of label,url pairs
-    HashMap<String, String> urlList = new HashMap<String, String>();
+    HashMap<String, String> urlList = new HashMap<>();
     if (viewport.applet != null)
     {
       for (int i = 1; i < 10; i++)
@@ -198,7 +198,7 @@ public class IdPanel extends Panel
     }
 
     lastid = seq;
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
   }
 
   @Override
@@ -295,7 +295,7 @@ public class IdPanel extends Panel
       }
       else
       {
-        nlinks = new ArrayList<String>();
+        nlinks = new ArrayList<>();
       }
 
       for (SequenceFeature sf : sq.getFeatures().getNonPositionalFeatures())
@@ -333,7 +333,7 @@ public class IdPanel extends Panel
       selectSeq(seq);
     }
 
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
   }
 
   void selectSeq(int seq)
@@ -459,7 +459,7 @@ public class IdPanel extends Panel
           running = false;
         }
 
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(true, false);
         try
         {
           Thread.sleep(100);
index e74e1cd..8ce597d 100755 (executable)
@@ -31,6 +31,7 @@ import java.awt.BorderLayout;
 import java.awt.CheckboxMenuItem;
 import java.awt.Cursor;
 import java.awt.Dimension;
+import java.awt.Frame;
 import java.awt.Panel;
 import java.awt.PopupMenu;
 import java.awt.event.ComponentAdapter;
@@ -200,7 +201,7 @@ public class OverviewPanel extends Panel implements Runnable,
                 av.getAlignment().getHiddenSequences(),
                 av.getAlignment().getHiddenColumns());
       }
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
   }
 
@@ -322,6 +323,9 @@ public class OverviewPanel extends Panel implements Runnable,
     try
     {
       av.getRanges().removePropertyChangeListener(this);
+      Frame parent = (Frame) getParent();
+      parent.dispose();
+      parent.setVisible(false);
     } finally
     {
       av = null;
index 32507fe..fe99187 100755 (executable)
@@ -24,8 +24,8 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
 
 import java.awt.Component;
-import java.util.Enumeration;
 import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Vector;
@@ -78,13 +78,14 @@ public class PaintRefresher
       return;
     }
 
-    for (String id : components.keySet())
+    Iterator<String> it = components.keySet().iterator();
+    while (it.hasNext())
     {
-      Vector<Component> comps = components.get(id);
+      Vector<Component> comps = components.get(it.next());
       comps.removeElement(comp);
-      if (comps.size() == 0)
+      if (comps.isEmpty())
       {
-        components.remove(id);
+        it.remove();
       }
     }
   }
@@ -110,10 +111,10 @@ public class PaintRefresher
       return;
     }
 
-    Enumeration<Component> e = comps.elements();
-    while (e.hasMoreElements())
+    Iterator<Component> it = comps.iterator();
+    while (it.hasNext())
     {
-      comp = e.nextElement();
+      comp = it.next();
 
       if (comp == source)
       {
@@ -122,7 +123,7 @@ public class PaintRefresher
 
       if (!comp.isValid())
       {
-        comps.removeElement(comp);
+        it.remove();
       }
       else if (validateSequences && comp instanceof AlignmentPanel
               && source instanceof AlignmentPanel)
index 2aba20c..bd36b0d 100644 (file)
@@ -160,7 +160,7 @@ public class RedundancyPanel extends SliderPanel
 
     float value = slider.getValue();
 
-    List<SequenceI> redundantSequences = new ArrayList<SequenceI>();
+    List<SequenceI> redundantSequences = new ArrayList<>();
     for (int i = 0; i < redundancy.length; i++)
     {
       if (value <= redundancy[i])
@@ -247,7 +247,7 @@ public class RedundancyPanel extends SliderPanel
               ap.av.getAlignment().getSequences());
     }
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
 
     if (historyList.size() == 0)
     {
index ad53ea4..75d4040 100755 (executable)
@@ -141,7 +141,7 @@ public class ScalePanel extends Panel
       sg.setStartRes(min);
       sg.setEndRes(max);
     }
-    ap.paintAlignment(false);
+    ap.paintAlignment(false, false);
     av.sendSelection();
   }
 
@@ -167,7 +167,7 @@ public class ScalePanel extends Panel
         {
           av.showColumn(reveal[0]);
           reveal = null;
-          ap.paintAlignment(true);
+          ap.paintAlignment(true, true);
           av.sendSelection();
         }
       });
@@ -183,7 +183,7 @@ public class ScalePanel extends Panel
           {
             av.showAllHiddenColumns();
             reveal = null;
-            ap.paintAlignment(true);
+            ap.paintAlignment(true, true);
             av.sendSelection();
           }
         });
@@ -208,7 +208,7 @@ public class ScalePanel extends Panel
             av.setSelectionGroup(null);
           }
 
-          ap.paintAlignment(true);
+          ap.paintAlignment(true, true);
           av.sendSelection();
         }
       });
@@ -239,7 +239,7 @@ public class ScalePanel extends Panel
 
     if (!stretchingGroup)
     {
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
 
       return;
     }
@@ -256,7 +256,7 @@ public class ScalePanel extends Panel
     }
 
     stretchingGroup = false;
-    ap.paintAlignment(false);
+    ap.paintAlignment(false, false);
     av.sendSelection();
   }
 
@@ -285,7 +285,7 @@ public class ScalePanel extends Panel
     {
       stretchingGroup = true;
       cs.stretchGroup(res, sg, min, max);
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
   }
 
index f36a8e2..9a61f5f 100644 (file)
@@ -335,7 +335,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       sg.addSequence(sequence, false);
       av.setSelectionGroup(sg);
     }
-    ap.paintAlignment(false);
+    ap.paintAlignment(false, false);
     av.sendSelection();
   }
 
@@ -417,7 +417,6 @@ public class SeqPanel extends Panel implements MouseMotionListener,
    *          alignment column
    * @param seq
    *          index of sequence in alignment
-   * @return position of column in sequence or -1 if at gap
    */
   void setStatusMessage(SequenceI sequence, int column, int seq)
   {
@@ -983,7 +982,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
 
       lastMousePress = evt.getPoint();
 
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
       ap.annotationPanel.image = null;
       return;
     }
@@ -1450,7 +1449,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         {
           if (links == null)
           {
-            links = new Vector<String>();
+            links = new Vector<>();
           }
           links.addAll(sf.links);
         }
@@ -1524,7 +1523,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       }
     }
     PaintRefresher.Refresh(ap, av.getSequenceSetId());
-    ap.paintAlignment(needOverviewUpdate);
+    ap.paintAlignment(needOverviewUpdate, needOverviewUpdate);
     needOverviewUpdate = false;
     changeEndRes = false;
     changeStartRes = false;
index 565ebe8..5841e80 100644 (file)
@@ -441,7 +441,7 @@ public class SliderPanel extends Panel
   @Override
   public void mouseReleased(MouseEvent evt)
   {
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   @Override
index ed531d3..777e307 100644 (file)
@@ -187,9 +187,9 @@ public class SplitFrame extends EmbmenuFrame
     createSplitFrameWindow(embedded, applet);
     validate();
     topFrame.alignPanel.adjustAnnotationHeight();
-    topFrame.alignPanel.paintAlignment(true);
+    topFrame.alignPanel.paintAlignment(true, true);
     bottomFrame.alignPanel.adjustAnnotationHeight();
-    bottomFrame.alignPanel.paintAlignment(true);
+    bottomFrame.alignPanel.paintAlignment(true, true);
   }
 
   /**
index d1c0e1b..6831a73 100644 (file)
@@ -64,7 +64,7 @@ public class UserDefinedColours extends Panel
 
   Button selectedButton;
 
-  Vector<Color> oldColours = new Vector<Color>();
+  Vector<Color> oldColours = new Vector<>();
 
   ColourSchemeI oldColourScheme;
 
@@ -520,7 +520,7 @@ public class UserDefinedColours extends Panel
                 ap.av.isIgnoreGapsConsensus());
       }
       ap.seqPanel.seqCanvas.img = null;
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
     }
     else if (jmol != null)
     {
@@ -599,7 +599,7 @@ public class UserDefinedColours extends Panel
       {
         ap.av.setGlobalColourScheme(oldColourScheme);
       }
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
     }
 
     frame.setVisible(false);
index dd05843..460c2b3 100644 (file)
@@ -52,14 +52,6 @@ public class AlignViewController implements AlignViewControllerI
    */
   private AlignViewControllerGuiI avcg;
 
-  @Override
-  protected void finalize() throws Throwable
-  {
-    viewport = null;
-    alignPanel = null;
-    avcg = null;
-  };
-
   public AlignViewController(AlignViewControllerGuiI alignFrame,
           AlignViewportI viewport, AlignmentViewPanel alignPanel)
   {
@@ -190,7 +182,7 @@ public class AlignViewController implements AlignViewControllerI
       if (changed)
       {
         viewport.setColumnSelection(cs);
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(false, false);
         int columnCount = invert
                 ? (sqcol.getEndRes() - sqcol.getStartRes() + 1)
                         - bs.cardinality()
@@ -215,7 +207,7 @@ public class AlignViewController implements AlignViewControllerI
       if (!extendCurrent)
       {
         cs.clear();
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(false, false);
       }
     }
     return false;
@@ -337,7 +329,7 @@ public class AlignViewController implements AlignViewControllerI
     AlignmentSorter.sortByFeature(typ, gps, start, stop, al, method);
     avcg.addHistoryItem(new OrderCommand(methodText, oldOrder,
             viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
 
   }
 
@@ -375,7 +367,7 @@ public class AlignViewController implements AlignViewControllerI
       {
         avcg.getFeatureSettingsUI().discoverAllFeatureData();
       }
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
     }
 
     return featuresFile;
@@ -414,7 +406,7 @@ public class AlignViewController implements AlignViewControllerI
       if (changed)
       {
         viewport.setColumnSelection(cs);
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(false, false);
         int columnCount = invert
                 ? (sqcol.getEndRes() - sqcol.getStartRes() + 1)
                         - bs.cardinality()
@@ -438,7 +430,7 @@ public class AlignViewController implements AlignViewControllerI
       if (!extendCurrent)
       {
         cs.clear();
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(false, false);
       }
     }
     return false;
index c464af2..09facbf 100755 (executable)
@@ -241,19 +241,6 @@ public class AlignmentAnnotation
 
   private boolean isrna;
 
-  /*
-   * (non-Javadoc)
-   * 
-   * @see java.lang.Object#finalize()
-   */
-  @Override
-  protected void finalize() throws Throwable
-  {
-    sequenceRef = null;
-    groupRef = null;
-    super.finalize();
-  }
-
   public static int getGraphValueFromString(String string)
   {
     if (string.equalsIgnoreCase("BAR_GRAPH"))
index 328b96a..b5184fb 100644 (file)
@@ -693,19 +693,6 @@ public class Mapping
     to = tto;
   }
 
-  /*
-   * (non-Javadoc)
-   * 
-   * @see java.lang.Object#finalize()
-   */
-  @Override
-  protected void finalize() throws Throwable
-  {
-    map = null;
-    to = null;
-    super.finalize();
-  }
-
   /**
    * Returns an iterator which can serve up the aligned codon column positions
    * and their corresponding peptide products
index 796937d..96b0757 100755 (executable)
@@ -38,8 +38,6 @@ import java.util.List;
 import java.util.ListIterator;
 import java.util.Vector;
 
-import com.stevesoft.pat.Regex;
-
 import fr.orsay.lri.varna.models.rna.RNA;
 
 /**
@@ -51,11 +49,6 @@ import fr.orsay.lri.varna.models.rna.RNA;
  */
 public class Sequence extends ASequence implements SequenceI
 {
-  private static final Regex limitrx = new Regex(
-          "[/][0-9]{1,}[-][0-9]{1,}$");
-
-  private static final Regex endrx = new Regex("[0-9]{1,}$");
-
   SequenceI datasetSequence;
 
   String name;
@@ -151,6 +144,10 @@ public class Sequence extends ASequence implements SequenceI
     checkValidRange();
   }
 
+  /**
+   * If 'name' ends in /i-j, where i >= j > 0 are integers, extracts i and j as
+   * start and end respectively and removes the suffix from the name
+   */
   void parseId()
   {
     if (name == null)
@@ -159,17 +156,37 @@ public class Sequence extends ASequence implements SequenceI
               "POSSIBLE IMPLEMENTATION ERROR: null sequence name passed to constructor.");
       name = "";
     }
-    // Does sequence have the /start-end signature?
-    if (limitrx.search(name))
+    int slashPos = name.lastIndexOf('/');
+    if (slashPos > -1 && slashPos < name.length() - 1)
     {
-      name = limitrx.left();
-      endrx.search(limitrx.stringMatched());
-      setStart(Integer.parseInt(limitrx.stringMatched().substring(1,
-              endrx.matchedFrom() - 1)));
-      setEnd(Integer.parseInt(endrx.stringMatched()));
+      String suffix = name.substring(slashPos + 1);
+      String[] range = suffix.split("-");
+      if (range.length == 2)
+      {
+        try
+        {
+          int from = Integer.valueOf(range[0]);
+          int to = Integer.valueOf(range[1]);
+          if (from > 0 && to >= from)
+          {
+            name = name.substring(0, slashPos);
+            setStart(from);
+            setEnd(to);
+            checkValidRange();
+          }
+        } catch (NumberFormatException e)
+        {
+          // leave name unchanged if suffix is invalid
+        }
+      }
     }
   }
 
+  /**
+   * Ensures that 'end' is not before the end of the sequence, that is,
+   * (end-start+1) is at least as long as the count of ungapped positions. Note
+   * that end is permitted to be beyond the end of the sequence data.
+   */
   void checkValidRange()
   {
     // Note: JAL-774 :
@@ -178,7 +195,7 @@ public class Sequence extends ASequence implements SequenceI
       int endRes = 0;
       for (int j = 0; j < sequence.length; j++)
       {
-        if (!jalview.util.Comparison.isGap(sequence[j]))
+        if (!Comparison.isGap(sequence[j]))
         {
           endRes++;
         }
@@ -453,15 +470,15 @@ public class Sequence extends ASequence implements SequenceI
   }
 
   /**
-   * DOCUMENT ME!
+   * Sets the sequence name. If the name ends in /start-end, then the start-end
+   * values are parsed out and set, and the suffix is removed from the name.
    * 
-   * @param name
-   *          DOCUMENT ME!
+   * @param theName
    */
   @Override
-  public void setName(String name)
+  public void setName(String theName)
   {
-    this.name = name;
+    this.name = theName;
     this.parseId();
   }
 
@@ -1827,7 +1844,9 @@ public class Sequence extends ASequence implements SequenceI
      * and we may have included adjacent or enclosing features;
      * remove any that are not enclosing, non-contact features
      */
-    if (endPos > this.end || Comparison.isGap(sequence[toColumn - 1]))
+    boolean endColumnIsGapped = toColumn > 0 && toColumn <= sequence.length
+            && Comparison.isGap(sequence[toColumn - 1]);
+    if (endPos > this.end || endColumnIsGapped)
     {
       ListIterator<SequenceFeature> it = result.listIterator();
       while (it.hasNext())
index ad01324..50dfa90 100644 (file)
@@ -161,8 +161,9 @@ public class EnsemblGene extends EnsemblSeqProxy
   }
 
   /**
-   * Converts a query, which may contain one or more gene or transcript
-   * identifiers, into a non-redundant list of gene identifiers.
+   * Converts a query, which may contain one or more gene, transcript, or
+   * external (to Ensembl) identifiers, into a non-redundant list of gene
+   * identifiers.
    * 
    * @param accessions
    * @return
@@ -173,54 +174,30 @@ public class EnsemblGene extends EnsemblSeqProxy
 
     for (String acc : accessions.split(getAccessionSeparator()))
     {
-      if (isGeneIdentifier(acc))
-      {
-        if (!geneIds.contains(acc))
-        {
-          geneIds.add(acc);
-        }
-      }
-
       /*
-       * if given a transcript id, look up its gene parent
+       * First try lookup as an Ensembl (gene or transcript) identifier
        */
-      else if (isTranscriptIdentifier(acc))
+      String geneId = new EnsemblLookup(getDomain()).getGeneId(acc);
+      if (geneId != null)
       {
-        String geneId = new EnsemblLookup(getDomain()).getParent(acc);
-        if (geneId != null && !geneIds.contains(geneId))
+        if (!geneIds.contains(geneId))
         {
           geneIds.add(geneId);
         }
       }
-      else if (isProteinIdentifier(acc))
-      {
-        String tscriptId = new EnsemblLookup(getDomain()).getParent(acc);
-        if (tscriptId != null)
-        {
-          String geneId = new EnsemblLookup(getDomain())
-                  .getParent(tscriptId);
-
-          if (geneId != null && !geneIds.contains(geneId))
-          {
-            geneIds.add(geneId);
-          }
-        }
-        // NOTE - acc is lost if it resembles an ENS.+ ID but isn't actually
-        // resolving to one... e.g. ENSMICP00000009241
-      }
-      /*
-       * if given a gene or other external name, lookup and fetch 
-       * the corresponding gene for all model organisms 
-       */
       else
       {
+        /*
+         * if given a gene or other external name, lookup and fetch 
+         * the corresponding gene for all model organisms 
+         */
         List<String> ids = new EnsemblSymbol(getDomain(), getDbSource(),
-                getDbVersion()).getIds(acc);
-        for (String geneId : ids)
+                getDbVersion()).getGeneIds(acc);
+        for (String id : ids)
         {
-          if (!geneIds.contains(geneId))
+          if (!geneIds.contains(id))
           {
-            geneIds.add(geneId);
+            geneIds.add(id);
           }
         }
       }
@@ -229,30 +206,6 @@ public class EnsemblGene extends EnsemblSeqProxy
   }
 
   /**
-   * Attempts to get Ensembl stable identifiers for model organisms for a gene
-   * name by calling the xrefs symbol REST service to resolve the gene name.
-   * 
-   * @param query
-   * @return
-   */
-  protected String getGeneIdentifiersForName(String query)
-  {
-    List<String> ids = new EnsemblSymbol(getDomain(), getDbSource(),
-            getDbVersion()).getIds(query);
-    if (ids != null)
-    {
-      for (String id : ids)
-      {
-        if (isGeneIdentifier(id))
-        {
-          return id;
-        }
-      }
-    }
-    return null;
-  }
-
-  /**
    * Constructs all transcripts for the gene, as identified by "transcript"
    * features whose Parent is the requested gene. The coding transcript
    * sequences (i.e. with introns omitted) are added to the alignment.
index ef46a5b..b40df50 100644 (file)
@@ -39,17 +39,12 @@ public class EnsemblGenomes extends EnsemblGene
   }
 
   @Override
-  public boolean isGeneIdentifier(String query)
-  {
-    return true;
-  }
-
-  @Override
   public String getDbName()
   {
     return "EnsemblGenomes";
   }
 
+  private String Wrong[];
   @Override
   public String getTestQuery()
   {
index 6483401..31da9c0 100644 (file)
@@ -43,6 +43,13 @@ import org.json.simple.parser.ParseException;
 public class EnsemblLookup extends EnsemblRestClient
 {
 
+  private static final String OBJECT_TYPE_TRANSLATION = "Translation";
+  private static final String PARENT = "Parent";
+  private static final String OBJECT_TYPE_TRANSCRIPT = "Transcript";
+  private static final String ID = "id";
+  private static final String OBJECT_TYPE_GENE = "Gene";
+  private static final String OBJECT_TYPE = "object_type";
+
   /**
    * Default constructor (to use rest.ensembl.org)
    */
@@ -87,7 +94,7 @@ public class EnsemblLookup extends EnsemblRestClient
   protected URL getUrl(String identifier)
   {
     String url = getDomain() + "/lookup/id/" + identifier
-            + "?content-type=application/json";
+            + CONTENT_TYPE_JSON;
     try
     {
       return new URL(url);
@@ -122,7 +129,7 @@ public class EnsemblLookup extends EnsemblRestClient
    * @param identifier
    * @return
    */
-  public String getParent(String identifier)
+  public String getGeneId(String identifier)
   {
     List<String> ids = Arrays.asList(new String[] { identifier });
 
@@ -155,8 +162,10 @@ public class EnsemblLookup extends EnsemblRestClient
   }
 
   /**
-   * Parses "Parent" from the JSON response and returns the value, or null if
-   * not found
+   * Parses the JSON response and returns the gene identifier, or null if not
+   * found. If the returned object_type is Gene, returns the id, if Transcript
+   * returns the Parent. If it is Translation (peptide identifier), then the
+   * Parent is the transcript identifier, so we redo the search with this value.
    * 
    * @param br
    * @return
@@ -164,17 +173,42 @@ public class EnsemblLookup extends EnsemblRestClient
    */
   protected String parseResponse(BufferedReader br) throws IOException
   {
-    String parent = null;
+    String geneId = null;
     JSONParser jp = new JSONParser();
     try
     {
       JSONObject val = (JSONObject) jp.parse(br);
-      parent = val.get("Parent").toString();
+      String type = val.get(OBJECT_TYPE).toString();
+      if (OBJECT_TYPE_GENE.equalsIgnoreCase(type))
+      {
+        geneId = val.get(ID).toString();
+      }
+      else if (OBJECT_TYPE_TRANSCRIPT.equalsIgnoreCase(type))
+      {
+        geneId = val.get(PARENT).toString();
+      }
+      else if (OBJECT_TYPE_TRANSLATION.equalsIgnoreCase(type))
+      {
+        String transcriptId = val.get(PARENT).toString();
+        try
+        {
+          geneId = getGeneId(transcriptId);
+        } catch (StackOverflowError e)
+        {
+          /*
+           * unlikely data condition error!
+           */
+          System.err
+                  .println("** Ensembl lookup "
+                          + getUrl(transcriptId).toString()
+                          + " looping on Parent!");
+        }
+      }
     } catch (ParseException e)
     {
       // ignore
     }
-    return parent;
+    return geneId;
   }
 
 }
index 1554a0b..99006aa 100644 (file)
@@ -23,8 +23,6 @@ package jalview.ext.ensembl;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceFeature;
 
-import java.util.List;
-
 import com.stevesoft.pat.Regex;
 
 /**
index c06d13e..b1bc8e5 100644 (file)
@@ -43,8 +43,6 @@ import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
 import org.json.simple.parser.JSONParser;
 
-import com.stevesoft.pat.Regex;
-
 /**
  * Base class for Ensembl REST service clients
  * 
@@ -68,9 +66,9 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
    * @see https://github.com/Ensembl/ensembl-rest/wiki/Change-log
    * @see http://rest.ensembl.org/info/rest?content-type=application/json
    */
-  private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "5.0";
+  private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "6.0";
 
-  private static final String LATEST_ENSEMBL_REST_VERSION = "5.0";
+  private static final String LATEST_ENSEMBL_REST_VERSION = "6.1";
 
   private static final String REST_CHANGE_LOG = "https://github.com/Ensembl/ensembl-rest/wiki/Change-log";
 
@@ -83,18 +81,11 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
 
   private final static long VERSION_RETEST_INTERVAL = 1000L * 3600; // 1 hr
 
-  private static final Regex PROTEIN_REGEX = new Regex(
-          "(ENS)([A-Z]{3}|)P[0-9]{11}$");
-
-  private static final Regex TRANSCRIPT_REGEX = new Regex(
-          "(ENS)([A-Z]{3}|)T[0-9]{11}$");
-
-  private static final Regex GENE_REGEX = new Regex(
-          "(ENS)([A-Z]{3}|)G[0-9]{11}$");
+  protected static final String CONTENT_TYPE_JSON = "?content-type=application/json";
 
   static
   {
-    domainData = new HashMap<String, EnsemblInfo>();
+    domainData = new HashMap<>();
     domainData.put(ENSEMBL_REST,
             new EnsemblInfo(ENSEMBL_REST, LATEST_ENSEMBL_REST_VERSION));
     domainData.put(ENSEMBL_GENOMES_REST, new EnsemblInfo(
@@ -121,42 +112,6 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     setDomain(d);
   }
 
-  /**
-   * Answers true if the query matches the regular expression pattern for an
-   * Ensembl transcript stable identifier
-   * 
-   * @param query
-   * @return
-   */
-  public boolean isTranscriptIdentifier(String query)
-  {
-    return query == null ? false : TRANSCRIPT_REGEX.search(query);
-  }
-
-  /**
-   * Answers true if the query matches the regular expression pattern for an
-   * Ensembl protein stable identifier
-   * 
-   * @param query
-   * @return
-   */
-  public boolean isProteinIdentifier(String query)
-  {
-    return query == null ? false : PROTEIN_REGEX.search(query);
-  }
-
-  /**
-   * Answers true if the query matches the regular expression pattern for an
-   * Ensembl gene stable identifier
-   * 
-   * @param query
-   * @return
-   */
-  public boolean isGeneIdentifier(String query)
-  {
-    return query == null ? false : GENE_REGEX.search(query);
-  }
-
   @Override
   public boolean queryInProgress()
   {
@@ -218,8 +173,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     {
       // note this format works for both ensembl and ensemblgenomes
       // info/ping.json works for ensembl only (March 2016)
-      URL ping = new URL(
-              getDomain() + "/info/ping?content-type=application/json");
+      URL ping = new URL(getDomain() + "/info/ping" + CONTENT_TYPE_JSON);
 
       /*
        * expect {"ping":1} if ok
@@ -228,6 +182,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
       br = getHttpResponse(ping, null, 2 * 1000);
       if (br == null)
       {
+        // error reponse status
         return false;
       }
       JSONParser jp = new JSONParser();
@@ -506,9 +461,12 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     URL url = null;
     try
     {
-      url = new URL(
-              getDomain() + "/info/rest?content-type=application/json");
+      url = new URL(getDomain() + "/info/rest" + CONTENT_TYPE_JSON);
       BufferedReader br = getHttpResponse(url, null);
+      if (br == null)
+      {
+        return;
+      }
       JSONObject val = (JSONObject) jp.parse(br);
       String version = val.get("release").toString();
       String majorVersion = version.substring(0, version.indexOf("."));
@@ -571,8 +529,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
 
     try
     {
-      url = new URL(
-              getDomain() + "/info/data?content-type=application/json");
+      url = new URL(getDomain() + "/info/data" + CONTENT_TYPE_JSON);
       br = getHttpResponse(url, null);
       if (br != null)
       {
index e2e38b5..75598a0 100644 (file)
@@ -42,6 +42,10 @@ import org.json.simple.parser.ParseException;
  */
 public class EnsemblSymbol extends EnsemblXref
 {
+  private static final String GENE = "gene";
+  private static final String TYPE = "type";
+  private static final String ID = "id";
+
   /**
    * Constructor given the target domain to fetch data from
    * 
@@ -73,8 +77,9 @@ public class EnsemblSymbol extends EnsemblXref
       while (rvals.hasNext())
       {
         JSONObject val = (JSONObject) rvals.next();
-        String id = val.get("id").toString();
-        if (id != null && isGeneIdentifier(id))
+        String id = val.get(ID).toString();
+        String type = val.get(TYPE).toString();
+        if (id != null && GENE.equals(type))
         {
           result = id;
           break;
@@ -87,12 +92,31 @@ public class EnsemblSymbol extends EnsemblXref
     return result;
   }
 
-  protected URL getUrl(String id, Species species)
+  /**
+   * Constructs the URL for the REST symbol endpoint
+   * 
+   * @param id
+   *          the accession id (Ensembl or external)
+   * @param species
+   *          a species name recognisable by Ensembl
+   * @param type
+   *          an optional type to filter the response (gene, transcript,
+   *          translation)
+   * @return
+   */
+  protected URL getUrl(String id, Species species, String... type)
   {
-    String url = getDomain() + "/xrefs/symbol/" + species.toString() + "/"
-            + id + "?content-type=application/json";
+    StringBuilder sb = new StringBuilder();
+    sb.append(getDomain()).append("/xrefs/symbol/")
+            .append(species.toString()).append("/").append(id)
+            .append(CONTENT_TYPE_JSON);
+    for (String t : type)
+    {
+      sb.append("&object_type=").append(t);
+    }
     try
     {
+      String url = sb.toString();
       return new URL(url);
     } catch (MalformedURLException e)
     {
@@ -107,7 +131,7 @@ public class EnsemblSymbol extends EnsemblXref
    * @param identifier
    * @return
    */
-  public List<String> getIds(String identifier)
+  public List<String> getGeneIds(String identifier)
   {
     List<String> result = new ArrayList<String>();
     List<String> ids = new ArrayList<String>();
@@ -121,14 +145,15 @@ public class EnsemblSymbol extends EnsemblXref
       {
         for (Species taxon : Species.getModelOrganisms())
         {
-          URL url = getUrl(query, taxon);
+          URL url = getUrl(query, taxon, GENE);
           if (url != null)
           {
             br = getHttpResponse(url, ids);
             if (br != null)
             {
               String geneId = parseSymbolResponse(br);
-              if (geneId != null)
+              System.out.println(url + " returned " + geneId);
+              if (geneId != null && !result.contains(geneId))
               {
                 result.add(geneId);
               }
index c002c08..27c448e 100644 (file)
@@ -171,16 +171,13 @@ class EnsemblXref extends EnsemblRestClient
       while (rvals.hasNext())
       {
         JSONObject val = (JSONObject) rvals.next();
-        String dbname = val.get("dbname").toString();
-        if (GO_GENE_ONTOLOGY.equals(dbname))
-        {
-          continue;
-        }
+        String db = val.get("dbname").toString();
         String id = val.get("primary_id").toString();
-        if (dbname != null && id != null)
+        if (db != null && id != null
+                && !GO_GENE_ONTOLOGY.equals(db))
         {
-          dbname = DBRefUtils.getCanonicalName(dbname);
-          DBRefEntry dbref = new DBRefEntry(dbname, getXRefVersion(), id);
+          db = DBRefUtils.getCanonicalName(db);
+          DBRefEntry dbref = new DBRefEntry(db, getXRefVersion(), id);
           result.add(dbref);
         }
       }
@@ -214,7 +211,7 @@ class EnsemblXref extends EnsemblRestClient
   protected URL getUrl(String identifier)
   {
     String url = getDomain() + "/xrefs/id/" + identifier
-            + "?content-type=application/json&all_levels=1";
+            + CONTENT_TYPE_JSON + "&all_levels=1";
     try
     {
       return new URL(url);
index 96dfcfe..41bc116 100644 (file)
@@ -27,6 +27,7 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
+import jalview.gui.IProgressIndicator;
 import jalview.io.DataSourceType;
 import jalview.io.StructureFile;
 import jalview.schemes.ColourSchemeI;
@@ -72,7 +73,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
    */
   private boolean associateNewStructs = false;
 
-  Vector<String> atomsPicked = new Vector<String>();
+  Vector<String> atomsPicked = new Vector<>();
 
   private List<String> chainNames;
 
@@ -610,7 +611,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     }
     if (modelFileNames == null)
     {
-      List<String> mset = new ArrayList<String>();
+      List<String> mset = new ArrayList<>();
       _modelFileNameMap = new int[viewer.ms.mc];
       String m = viewer.ms.getModelFileName(0);
       if (m != null)
@@ -670,7 +671,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
   @Override
   public synchronized String[] getStructureFiles()
   {
-    List<String> mset = new ArrayList<String>();
+    List<String> mset = new ArrayList<>();
     if (viewer == null)
     {
       return new String[0];
@@ -975,6 +976,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
         notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
                 (String) data[0]);
         // also highlight in alignment
+        // deliberate fall through
       case HOVER:
         notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
                 (String) data[0]);
@@ -1059,8 +1061,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     fileLoadingError = null;
     String[] oldmodels = modelFileNames;
     modelFileNames = null;
-    chainNames = new ArrayList<String>();
-    chainFile = new Hashtable<String, String>();
+    chainNames = new ArrayList<>();
+    chainFile = new Hashtable<>();
     boolean notifyLoaded = false;
     String[] modelfilenames = getStructureFiles();
     // first check if we've lost any structures
@@ -1126,7 +1128,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
           // see JAL-623 - need method of matching pasted data up
           {
             pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
-                    pdbfile, DataSourceType.PASTE);
+                    pdbfile, DataSourceType.PASTE,
+                    getIProgressIndicator());
             getPdbEntry(modelnum).setFile("INLINE" + pdb.getId());
             matches = true;
             foundEntry = true;
@@ -1158,7 +1161,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
             }
             // Explicitly map to the filename used by Jmol ;
             pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
-                    fileName, protocol);
+                    fileName, protocol, getIProgressIndicator());
             // pdbentry[pe].getFile(), protocol);
 
           }
@@ -1226,6 +1229,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     return chainNames;
   }
 
+  protected abstract IProgressIndicator getIProgressIndicator();
+
   public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
   {
     notifyAtomPicked(iatom, strMeasure, null);
index f923f7f..39d6704 100644 (file)
@@ -120,7 +120,7 @@ public class AtomSpecModel
 
       for (String chain : modelData.keySet())
       {
-        chain = chain.trim();
+        chain = " ".equals(chain) ? chain : chain.trim();
 
         List<int[]> rangeList = modelData.get(chain);
 
@@ -192,9 +192,10 @@ public class AtomSpecModel
     {
       sb.append(start).append("-").append(end);
     }
-    if (chain.length() > 0)
-    {
-      sb.append(".").append(chain);
+
+    sb.append(".");
+    if (!" ".equals(chain)) {
+      sb.append(chain);
     }
   }
 }
index 13b715e..298688b 100644 (file)
@@ -163,8 +163,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
   AlignViewport viewport;
 
-  ViewportRanges vpRanges;
-
   public AlignViewControllerI avc;
 
   List<AlignmentPanel> alignPanels = new ArrayList<>();
@@ -336,7 +334,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       progressBar = new ProgressBar(this.statusPanel, this.statusBar);
     }
 
-    vpRanges = viewport.getRanges();
     avc = new jalview.controller.AlignViewController(this, viewport,
             alignPanel);
     if (viewport.getAlignmentConservationAnnotation() == null)
@@ -654,9 +651,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                   { (viewport.cursorMode ? "on" : "off") }));
           if (viewport.cursorMode)
           {
-            alignPanel.getSeqPanel().seqCanvas.cursorX = vpRanges
+            ViewportRanges ranges = viewport.getRanges();
+            alignPanel.getSeqPanel().seqCanvas.cursorX = ranges
                     .getStartRes();
-            alignPanel.getSeqPanel().seqCanvas.cursorY = vpRanges
+            alignPanel.getSeqPanel().seqCanvas.cursorY = ranges
                     .getStartSeq();
           }
           alignPanel.getSeqPanel().seqCanvas.repaint();
@@ -689,10 +687,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           break;
         }
         case KeyEvent.VK_PAGE_UP:
-          vpRanges.pageUp();
+          viewport.getRanges().pageUp();
           break;
         case KeyEvent.VK_PAGE_DOWN:
-          vpRanges.pageDown();
+          viewport.getRanges().pageDown();
           break;
         }
       }
@@ -1711,7 +1709,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     viewport.getAlignment().moveSelectedSequencesByOne(sg,
             viewport.getHiddenRepSequences(), up);
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   synchronized void slideSequences(boolean right, int size)
@@ -2147,7 +2145,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       {
 
         // propagate alignment changed.
-        vpRanges.setEndSeq(alignment.getHeight());
+        viewport.getRanges().setEndSeq(alignment.getHeight());
         if (annotationAdded)
         {
           // Duplicate sequence annotation in all views.
@@ -2397,7 +2395,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
       alignPanel.updateAnnotation();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
     }
   }
 
@@ -2423,7 +2421,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // JAL-2034 - should delegate to
     // alignPanel to decide if overview needs
     // updating.
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
   }
 
@@ -2448,7 +2446,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // JAL-2034 - should delegate to
     // alignPanel to decide if overview needs
     // updating.
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -2479,7 +2477,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // alignPanel to decide if overview needs
     // updating.
 
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -2488,7 +2486,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void invertColSel_actionPerformed(ActionEvent e)
   {
     viewport.invertColumnSelection();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
     viewport.sendSelection();
   }
 
@@ -2548,7 +2546,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       {
         trimRegion = new TrimRegionCommand("Remove Left", true, seqs,
                 column, viewport.getAlignment());
-        vpRanges.setStartRes(0);
+        viewport.getRanges().setStartRes(0);
       }
       else
       {
@@ -2613,13 +2611,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // This is to maintain viewport position on first residue
     // of first sequence
     SequenceI seq = viewport.getAlignment().getSequenceAt(0);
-    int startRes = seq.findPosition(vpRanges.getStartRes());
+    ViewportRanges ranges = viewport.getRanges();
+    int startRes = seq.findPosition(ranges.getStartRes());
     // ShiftList shifts;
     // viewport.getAlignment().removeGaps(shifts=new ShiftList());
     // edit.alColumnChanges=shifts.getInverse();
     // if (viewport.hasHiddenColumns)
     // viewport.getColumnSelection().compensateForEdits(shifts);
-    vpRanges.setStartRes(seq.findIndex(startRes) - 1);
+    ranges.setStartRes(seq.findIndex(startRes) - 1);
     viewport.firePropertyChange("alignment", null,
             viewport.getAlignment().getSequences());
 
@@ -2652,12 +2651,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // This is to maintain viewport position on first residue
     // of first sequence
     SequenceI seq = viewport.getAlignment().getSequenceAt(0);
-    int startRes = seq.findPosition(vpRanges.getStartRes());
+    int startRes = seq.findPosition(viewport.getRanges().getStartRes());
 
     addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
             viewport.getAlignment()));
 
-    vpRanges.setStartRes(seq.findIndex(startRes) - 1);
+    viewport.getRanges().setStartRes(seq.findIndex(startRes) - 1);
 
     viewport.firePropertyChange("alignment", null,
             viewport.getAlignment().getSequences());
@@ -2713,8 +2712,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     /*
      * Create a new AlignmentPanel (with its own, new Viewport)
      */
-    AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel,
-            true);
+    AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel);
     if (!copyAnnotation)
     {
       /*
@@ -2868,21 +2866,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     alignPanel.getIdPanel().getIdCanvas()
             .setPreferredSize(alignPanel.calculateIdWidth());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   @Override
   public void idRightAlign_actionPerformed(ActionEvent e)
   {
     viewport.setRightAlignIds(idRightAlign.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   @Override
   public void centreColumnLabels_actionPerformed(ActionEvent e)
   {
     viewport.setCentreColumnLabels(centreColumnLabelsMenuItem.getState());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /*
@@ -2915,7 +2913,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void colourTextMenuItem_actionPerformed(ActionEvent e)
   {
     viewport.setColourText(colourTextMenuItem.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
@@ -2944,7 +2942,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void showAllColumns_actionPerformed(ActionEvent e)
   {
     viewport.showAllHiddenColumns();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
 
@@ -3048,7 +3046,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.expandColSelection(sg, false);
     viewport.hideAllSelectedSeqs();
     viewport.hideSelectedColumns();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
 
@@ -3064,7 +3062,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     viewport.showAllHiddenColumns();
     viewport.showAllHiddenSeqs();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
 
@@ -3072,7 +3070,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void hideSelColumns_actionPerformed(ActionEvent e)
   {
     viewport.hideSelectedColumns();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
 
@@ -3093,7 +3091,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void scaleAbove_actionPerformed(ActionEvent e)
   {
     viewport.setScaleAboveWrapped(scaleAbove.isSelected());
-    alignPanel.paintAlignment(true);
+    // TODO: do we actually need to update overview for scale above change ?
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3106,7 +3105,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void scaleLeft_actionPerformed(ActionEvent e)
   {
     viewport.setScaleLeftWrapped(scaleLeft.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3119,7 +3118,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void scaleRight_actionPerformed(ActionEvent e)
   {
     viewport.setScaleRightWrapped(scaleRight.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3132,7 +3131,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
   {
     viewport.setShowBoxes(viewBoxesMenuItem.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
@@ -3145,7 +3144,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void viewTextMenuItem_actionPerformed(ActionEvent e)
   {
     viewport.setShowText(viewTextMenuItem.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
@@ -3158,7 +3157,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
   {
     viewport.setRenderGaps(renderGapsMenuItem.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   public FeatureSettings featureSettings;
@@ -3196,7 +3195,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void showSeqFeatures_actionPerformed(ActionEvent evt)
   {
     viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
   }
 
   /**
@@ -3353,7 +3352,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     viewport.setGlobalColourScheme(cs);
 
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
   }
 
   /**
@@ -3438,7 +3437,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             viewport.getAlignment().getSequenceAt(0));
     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
             viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3454,7 +3453,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     AlignmentSorter.sortByID(viewport.getAlignment());
     addHistoryItem(
             new OrderCommand("ID Sort", oldOrder, viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3470,7 +3469,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     AlignmentSorter.sortByLength(viewport.getAlignment());
     addHistoryItem(new OrderCommand("Length Sort", oldOrder,
             viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3487,7 +3486,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
             viewport.getAlignment()));
 
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3644,7 +3643,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         addHistoryItem(new OrderCommand(order.getName(), oldOrder,
                 viewport.getAlignment()));
 
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(true, false);
       }
     });
   }
@@ -3673,7 +3672,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 viewport.getAlignment());// ,viewport.getSelectionGroup());
         addHistoryItem(new OrderCommand("Sort by " + scoreLabel, oldOrder,
                 viewport.getAlignment()));
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(true, false);
       }
     });
   }
@@ -3788,7 +3787,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       addHistoryItem(new OrderCommand(undoname, oldOrder,
               viewport.getAlignment()));
     }
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
     return true;
   }
 
@@ -4503,7 +4502,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                       assocfiles++;
                     }
                   }
-                  alignPanel.paintAlignment(true);
+                  // TODO: do we need to update overview ? only if features are
+                  // shown I guess
+                  alignPanel.paintAlignment(true, false);
                 }
               }
             }
@@ -4650,7 +4651,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           {
             if (parseFeaturesFile(file, sourceType))
             {
-              alignPanel.paintAlignment(true);
+              alignPanel.paintAlignment(true, true);
             }
           }
           else
@@ -4665,7 +4666,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         alignPanel.adjustAnnotationHeight();
         viewport.updateSequenceIdColours();
         buildSortByAnnotationScoresMenu();
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(true, true);
       }
     } catch (Exception ex)
     {
@@ -5190,7 +5191,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void showUnconservedMenuItem_actionPerformed(ActionEvent e)
   {
     viewport.setShowUnconserved(showNonconservedMenuItem.getState());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /*
@@ -5279,7 +5280,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
       alignPanel.updateAnnotation();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
     }
   }
 
@@ -5291,7 +5292,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       viewport.getAlignment().setSeqrep(null);
       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
       alignPanel.updateAnnotation();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
     }
   }
 
@@ -5381,7 +5382,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     this.alignPanel.av.setSortAnnotationsBy(getAnnotationSortOrder());
     this.alignPanel.av
             .setShowAutocalculatedAbove(isShowAutoCalculatedAbove());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
index c22a37d..90271c8 100644 (file)
@@ -76,8 +76,6 @@ public class AlignViewport extends AlignmentViewport
 {
   Font font;
 
-  TreeModel currentTree = null;
-
   boolean cursorMode = false;
 
   boolean antiAlias = false;
@@ -448,27 +446,6 @@ public class AlignViewport extends AlignmentViewport
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param tree
-   *          DOCUMENT ME!
-   */
-  public void setCurrentTree(TreeModel tree)
-  {
-    currentTree = tree;
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
-  public TreeModel getCurrentTree()
-  {
-    return currentTree;
-  }
-
-  /**
    * returns the visible column regions of the alignment
    * 
    * @param selectedRegionOnly
@@ -1110,5 +1087,4 @@ public class AlignViewport extends AlignmentViewport
     }
     fr.setTransparency(featureSettings.getTransparency());
   }
-
 }
index c700635..3a1dbe8 100644 (file)
@@ -76,8 +76,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
 {
   public AlignViewport av;
 
-  ViewportRanges vpRanges;
-
   OverviewPanel overviewPanel;
 
   private SeqPanel seqPanel;
@@ -97,9 +95,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
   private AnnotationLabels alabels;
 
-  // this value is set false when selection area being dragged
-  boolean fastPaint = true;
-
   private int hextent = 0;
 
   private int vextent = 0;
@@ -124,7 +119,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
   {
     alignFrame = af;
     this.av = av;
-    vpRanges = av.getRanges();
     setSeqPanel(new SeqPanel(av, this));
     setIdPanel(new IdPanel(av, this));
 
@@ -156,11 +150,12 @@ public class AlignmentPanel extends GAlignmentPanel implements
         // reset the viewport ranges when the alignment panel is resized
         // in particular, this initialises the end residue value when Jalview
         // is initialised
+        ViewportRanges ranges = av.getRanges();
         if (av.getWrapAlignment())
         {
           int widthInRes = getSeqPanel().seqCanvas.getWrappedCanvasWidth(
                   getSeqPanel().seqCanvas.getWidth());
-          vpRanges.setViewportWidth(widthInRes);
+          ranges.setViewportWidth(widthInRes);
         }
         else
         {
@@ -169,8 +164,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
           int heightInSeq = getSeqPanel().seqCanvas.getHeight()
                   / av.getCharHeight();
 
-          vpRanges.setViewportWidth(widthInRes);
-          vpRanges.setViewportHeight(heightInSeq);
+          ranges.setViewportWidth(widthInRes);
+          ranges.setViewportHeight(heightInSeq);
         }
       }
 
@@ -214,7 +209,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
     alignFrame.updateEditMenuBar();
 
-    paintAlignment(true);
+    // no idea if we need to update structure
+    paintAlignment(true, true);
 
   }
 
@@ -379,6 +375,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
           int verticalOffset, boolean redrawOverview, boolean centre)
   {
     int startv, endv, starts, ends;
+    ViewportRanges ranges = av.getRanges();
 
     if (results == null || results.isEmpty() || av == null
             || av.getAlignment() == null)
@@ -406,7 +403,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
      */
     if (centre)
     {
-      int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2 - 1;
+      int offset = (ranges.getEndRes() - ranges.getStartRes() + 1) / 2 - 1;
       start = Math.max(start - offset, 0);
       end = end + offset - 1;
     }
@@ -442,33 +439,33 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
     if (!av.getWrapAlignment())
     {
-      if ((startv = vpRanges.getStartRes()) >= start)
+      if ((startv = ranges.getStartRes()) >= start)
       {
         /*
          * Scroll left to make start of search results visible
          */
         setScrollValues(start, seqIndex);
       }
-      else if ((endv = vpRanges.getEndRes()) <= end)
+      else if ((endv = ranges.getEndRes()) <= end)
       {
         /*
          * Scroll right to make end of search results visible
          */
         setScrollValues(startv + end - endv, seqIndex);
       }
-      else if ((starts = vpRanges.getStartSeq()) > seqIndex)
+      else if ((starts = ranges.getStartSeq()) > seqIndex)
       {
         /*
          * Scroll up to make start of search results visible
          */
-        setScrollValues(vpRanges.getStartRes(), seqIndex);
+        setScrollValues(ranges.getStartRes(), seqIndex);
       }
-      else if ((ends = vpRanges.getEndSeq()) <= seqIndex)
+      else if ((ends = ranges.getEndSeq()) <= seqIndex)
       {
         /*
          * Scroll down to make end of search results visible
          */
-        setScrollValues(vpRanges.getStartRes(), starts + seqIndex - ends
+        setScrollValues(ranges.getStartRes(), starts + seqIndex - ends
                 + 1);
       }
       /*
@@ -478,10 +475,10 @@ public class AlignmentPanel extends GAlignmentPanel implements
     }
     else
     {
-      scrollNeeded = vpRanges.scrollToWrappedVisible(start);
+      scrollNeeded = ranges.scrollToWrappedVisible(start);
     }
 
-    paintAlignment(redrawOverview);
+    paintAlignment(redrawOverview, false);
 
     return scrollNeeded;
   }
@@ -538,7 +535,9 @@ public class AlignmentPanel extends GAlignmentPanel implements
     }
     validateAnnotationDimensions(true);
     addNotify();
-    paintAlignment(true);
+    // TODO: many places call this method and also paintAlignment with various
+    // different settings. this means multiple redraws are triggered...
+    paintAlignment(true, false);
   }
 
   /**
@@ -605,7 +604,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
     fontChanged();
     setAnnotationVisible(av.isShowAnnotation());
     boolean wrap = av.getWrapAlignment();
-    vpRanges.setStartSeq(0);
+    ViewportRanges ranges = av.getRanges();
+    ranges.setStartSeq(0);
     scalePanelHolder.setVisible(!wrap);
     hscroll.setVisible(!wrap);
     idwidthAdjuster.setVisible(!wrap);
@@ -628,16 +628,16 @@ public class AlignmentPanel extends GAlignmentPanel implements
       {
         int widthInRes = getSeqPanel().seqCanvas
                 .getWrappedCanvasWidth(canvasWidth);
-        vpRanges.setViewportWidth(widthInRes);
+        ranges.setViewportWidth(widthInRes);
       }
       else
       {
-        int widthInRes = (canvasWidth / av.getCharWidth()) - 1;
+        int widthInRes = (canvasWidth / av.getCharWidth());
         int heightInSeq = (getSeqPanel().seqCanvas.getHeight()
-                / av.getCharHeight()) - 1;
+                / av.getCharHeight());
 
-        vpRanges.setViewportWidth(widthInRes);
-        vpRanges.setViewportHeight(heightInSeq);
+        ranges.setViewportWidth(widthInRes);
+        ranges.setViewportHeight(heightInSeq);
       }
     }
 
@@ -736,10 +736,12 @@ public class AlignmentPanel extends GAlignmentPanel implements
       return;
     }
 
+    ViewportRanges ranges = av.getRanges();
+
     if (evt.getSource() == hscroll)
     {
-      int oldX = vpRanges.getStartRes();
-      int oldwidth = vpRanges.getViewportWidth();
+      int oldX = ranges.getStartRes();
+      int oldwidth = ranges.getViewportWidth();
       int x = hscroll.getValue();
       int width = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
 
@@ -750,12 +752,12 @@ public class AlignmentPanel extends GAlignmentPanel implements
       {
         return;
       }
-      vpRanges.setViewportStartAndWidth(x, width);
+      ranges.setViewportStartAndWidth(x, width);
     }
     else if (evt.getSource() == vscroll)
     {
-      int oldY = vpRanges.getStartSeq();
-      int oldheight = vpRanges.getViewportHeight();
+      int oldY = ranges.getStartSeq();
+      int oldheight = ranges.getViewportHeight();
       int y = vscroll.getValue();
       int height = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight();
 
@@ -766,12 +768,9 @@ public class AlignmentPanel extends GAlignmentPanel implements
       {
         return;
       }
-      vpRanges.setViewportStartAndHeight(y, height);
-    }
-    if (!fastPaint)
-    {
-      repaint();
+      ranges.setViewportStartAndHeight(y, height);
     }
+    repaint();
   }
 
   /**
@@ -786,6 +785,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
     {
       return; // no horizontal scroll when wrapped
     }
+    final ViewportRanges ranges = av.getRanges();
+
     if (evt.getSource() == vscroll)
     {
       int newY = vscroll.getValue();
@@ -795,8 +796,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
        * this prevents infinite recursion of events when the scroll/viewport
        * ranges values are the same
        */
-      int oldX = vpRanges.getStartRes();
-      int oldY = vpRanges.getWrappedScrollPosition(oldX);
+      int oldX = ranges.getStartRes();
+      int oldY = ranges.getWrappedScrollPosition(oldX);
       if (oldY == newY)
       {
         return;
@@ -806,9 +807,9 @@ public class AlignmentPanel extends GAlignmentPanel implements
         /*
          * limit page up/down to one width's worth of positions
          */
-        int rowSize = vpRanges.getViewportWidth();
+        int rowSize = ranges.getViewportWidth();
         int newX = newY > oldY ? oldX + rowSize : oldX - rowSize;
-        vpRanges.setViewportStartAndWidth(Math.max(0, newX), rowSize);
+        ranges.setViewportStartAndWidth(Math.max(0, newX), rowSize);
       }
     }
     else
@@ -829,20 +830,20 @@ public class AlignmentPanel extends GAlignmentPanel implements
                   "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);
+          ranges.setStartRes(0);
+          ranges.setStartSeq(0);
         }
       });
     }
     repaint();
   }
 
-  /**
-   * Repaint the alignment including the annotations and overview panels (if
-   * shown).
+  /* (non-Javadoc)
+   * @see jalview.api.AlignmentViewPanel#paintAlignment(boolean)
    */
   @Override
-  public void paintAlignment(boolean updateOverview)
+  public void paintAlignment(boolean updateOverview,
+          boolean updateStructures)
   {
     final AnnotationSorter sorter = new AnnotationSorter(getAlignment(),
             av.isShowAutocalculatedAbove());
@@ -850,10 +851,12 @@ public class AlignmentPanel extends GAlignmentPanel implements
             av.getSortAnnotationsBy());
     repaint();
 
-    if (updateOverview)
+    if (updateStructures)
     {
-      // TODO: determine if this paintAlignment changed structure colours
       av.getStructureSelectionManager().sequenceColoursChanged(this);
+    }
+    if (updateOverview)
+    {
 
       if (overviewPanel != null)
       {
@@ -881,7 +884,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
     /*
      * set scroll bar positions
      */
-    setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
+    ViewportRanges ranges = av.getRanges();
+    setScrollValues(ranges.getStartRes(), ranges.getStartSeq());
   }
 
   /**
@@ -893,8 +897,9 @@ public class AlignmentPanel extends GAlignmentPanel implements
    */
   private void setScrollingForWrappedPanel(int topLeftColumn)
   {
-    int scrollPosition = vpRanges.getWrappedScrollPosition(topLeftColumn);
-    int maxScroll = vpRanges.getWrappedMaxScroll(topLeftColumn);
+    ViewportRanges ranges = av.getRanges();
+    int scrollPosition = ranges.getWrappedScrollPosition(topLeftColumn);
+    int maxScroll = ranges.getWrappedMaxScroll(topLeftColumn);
 
     /*
      * a scrollbar's value can be set to at most (maximum-extent)
@@ -1605,13 +1610,14 @@ public class AlignmentPanel extends GAlignmentPanel implements
     if (annotationPanel != null)
     {
       annotationPanel.dispose();
+      annotationPanel = null;
     }
 
     if (av != null)
     {
       av.removePropertyChangeListener(propertyChangeListener);
-      jalview.structure.StructureSelectionManager ssm = av
-              .getStructureSelectionManager();
+      propertyChangeListener = null;
+      StructureSelectionManager ssm = av.getStructureSelectionManager();
       ssm.removeStructureViewerListener(getSeqPanel(), null);
       ssm.removeSelectionListener(getSeqPanel());
       ssm.removeCommandListener(av);
@@ -1634,9 +1640,15 @@ public class AlignmentPanel extends GAlignmentPanel implements
    */
   protected void closeChildFrames()
   {
+    if (overviewPanel != null)
+    {
+      overviewPanel.dispose();
+      overviewPanel = null;
+    }
     if (calculationDialog != null)
     {
       calculationDialog.closeFrame();
+      calculationDialog = null;
     }
   }
 
@@ -1866,7 +1878,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
     if (adjustHeight)
     {
       // sort, repaint, update overview
-      paintAlignment(true);
+      paintAlignment(true, false);
     }
     else
     {
@@ -1883,8 +1895,9 @@ public class AlignmentPanel extends GAlignmentPanel implements
   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();
+    ViewportRanges ranges = av.getRanges();
+    int x = ranges.getStartRes();
+    int y = ranges.getStartSeq();
     setScrollValues(x, y);
 
     // now update any complementary alignment (its viewport ranges object
index 26796de..84883d7 100644 (file)
@@ -82,7 +82,7 @@ public class AnnotationChooser extends JPanel
   private boolean applyToUnselectedSequences;
 
   // currently selected 'annotation type' checkboxes
-  private Map<String, String> selectedTypes = new HashMap<String, String>();
+  private Map<String, String> selectedTypes = new HashMap<>();
 
   /**
    * Constructor.
@@ -202,7 +202,7 @@ public class AnnotationChooser extends JPanel
     // this.ap.alabels.setSize(this.ap.alabels.getSize().width,
     // this.ap.annotationPanel.getSize().height);
     // this.ap.validate();
-    this.ap.paintAlignment(true);
+    this.ap.paintAlignment(true, false);
   }
 
   /**
@@ -233,7 +233,7 @@ public class AnnotationChooser extends JPanel
     // this.ap.alabels.setSize(this.ap.alabels.getSize().width,
     // this.ap.annotationPanel.getSize().height);
     // this.ap.validate();
-    this.ap.paintAlignment(true);
+    this.ap.paintAlignment(true, false);
   }
 
   /**
@@ -251,7 +251,7 @@ public class AnnotationChooser extends JPanel
 
     this.ap.updateAnnotation();
     // this.ap.annotationPanel.adjustPanelHeight();
-    this.ap.paintAlignment(true);
+    this.ap.paintAlignment(true, false);
   }
 
   /**
@@ -356,7 +356,7 @@ public class AnnotationChooser extends JPanel
   public static List<String> getAnnotationTypes(AlignmentI alignment,
           boolean sequenceSpecificOnly)
   {
-    List<String> result = new ArrayList<String>();
+    List<String> result = new ArrayList<>();
     for (AlignmentAnnotation aa : alignment.getAlignmentAnnotation())
     {
       if (!sequenceSpecificOnly || aa.sequenceRef != null)
index 8d123bb..153f70c 100644 (file)
@@ -79,7 +79,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
     oldcs = av.getGlobalColourScheme();
     if (av.getAlignment().getGroups() != null)
     {
-      oldgroupColours = new Hashtable<SequenceGroup, ColourSchemeI>();
+      oldgroupColours = new Hashtable<>();
       for (SequenceGroup sg : ap.av.getAlignment().getGroups())
       {
         if (sg.getColourScheme() != null)
@@ -122,7 +122,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
     }
     Vector<String> annotItems = getAnnotationItems(
             seqAssociated.isSelected());
-    annotations = new JComboBox<String>(annotItems);
+    annotations = new JComboBox<>(annotItems);
 
     populateThresholdComboBox(threshold);
 
@@ -341,7 +341,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
       getCurrentAnnotation().threshold.value = slider.getValue() / 1000f;
       propagateSeqAssociatedThreshold(updateAllAnnotation,
               getCurrentAnnotation());
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
   }
 
@@ -415,12 +415,9 @@ public class AnnotationColourChooser extends AnnotationRowFilter
     colorAlignmentContaining(getCurrentAnnotation(), selectedThresholdItem);
 
     ap.alignmentChanged();
-    // ensure all associated views (overviews, structures, etc) are notified of
-    // updated colours.
-    ap.paintAlignment(true);
   }
 
-  protected boolean colorAlignmentContaining(AlignmentAnnotation currentAnn,
+  protected void colorAlignmentContaining(AlignmentAnnotation currentAnn,
           int selectedThresholdOption)
   {
 
@@ -460,7 +457,6 @@ public class AnnotationColourChooser extends AnnotationRowFilter
                 acg.getInstance(sg, ap.av.getHiddenRepSequences()));
       }
     }
-    return false;
   }
 
 }
index 84b2c6f..020e027 100644 (file)
@@ -254,7 +254,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter
         av.getAlignment().setHiddenColumns(oldHidden);
       }
       av.sendSelection();
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
     }
   }
 
@@ -267,7 +267,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter
       updateView();
       propagateSeqAssociatedThreshold(updateAllAnnotation,
               getCurrentAnnotation());
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
   }
 
@@ -391,7 +391,8 @@ public class AnnotationColumnChooser extends AnnotationRowFilter
     av.getColumnSelection().filterAnnotations(
             getCurrentAnnotation().annotations, filterParams);
 
-    if (getActionOption() == ACTION_OPTION_HIDE)
+    boolean hideCols = getActionOption() == ACTION_OPTION_HIDE;
+    if (hideCols)
     {
       av.hideSelectedColumns();
     }
@@ -399,7 +400,8 @@ public class AnnotationColumnChooser extends AnnotationRowFilter
 
     filterParams = null;
     av.setAnnotationColumnSelectionState(this);
-    ap.paintAlignment(true);
+    // only update overview and structures if columns were hidden
+    ap.paintAlignment(hideCols, hideCols);
   }
 
   public HiddenColumns getOldHiddenColumns()
index d07cae2..b94a615 100755 (executable)
@@ -705,7 +705,7 @@ public class AnnotationLabels extends JPanel
         d = ap.annotationSpaceFillerHolder.getPreferredSize();
         ap.annotationSpaceFillerHolder
                 .setPreferredSize(new Dimension(d.width, d.height - dif));
-        ap.paintAlignment(true);
+        ap.paintAlignment(true, false);
       }
 
       ap.addNotify();
@@ -855,7 +855,7 @@ public class AnnotationLabels extends JPanel
               }
             }
 
-            ap.paintAlignment(false);
+            ap.paintAlignment(false, false);
             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
             ap.av.sendSelection();
           }
@@ -912,7 +912,7 @@ public class AnnotationLabels extends JPanel
               sg.addSequence(aa[selectedRow].sequenceRef, false);
             }
             ap.av.setSelectionGroup(sg);
-            ap.paintAlignment(false);
+            ap.paintAlignment(false, false);
             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
             ap.av.sendSelection();
           }
index c9d65fa..ef41047 100755 (executable)
@@ -670,7 +670,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       }
       graphStretchY = evt.getY();
       adjustPanelHeight();
-      ap.paintAlignment(true);
+      ap.paintAlignment(false, false);
     }
     else
     {
index 8b2486f..71ad6a5 100644 (file)
@@ -80,7 +80,7 @@ public abstract class AnnotationRowFilter extends JPanel
    */
   protected boolean sliderDragging = false;
 
-  protected JComboBox<String> threshold = new JComboBox<String>();
+  protected JComboBox<String> threshold = new JComboBox<>();
 
   protected JComboBox<String> annotations;
 
@@ -177,7 +177,6 @@ public abstract class AnnotationRowFilter extends JPanel
           sliderDragging = false;
           valueChanged(true);
         }
-        ap.paintAlignment(true);
       }
     });
   }
@@ -192,9 +191,9 @@ public abstract class AnnotationRowFilter extends JPanel
    */
   public Vector<String> getAnnotationItems(boolean isSeqAssociated)
   {
-    annotationLabels = new HashMap<AlignmentAnnotation, String>();
+    annotationLabels = new HashMap<>();
 
-    Vector<String> list = new Vector<String>();
+    Vector<String> list = new Vector<>();
     int index = 1;
     int[] anmap = new int[av.getAlignment()
             .getAlignmentAnnotation().length];
@@ -271,7 +270,7 @@ public abstract class AnnotationRowFilter extends JPanel
   public void cancel_actionPerformed()
   {
     reset();
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
     try
     {
       frame.setClosed(true);
@@ -413,6 +412,11 @@ public abstract class AnnotationRowFilter extends JPanel
     this.currentAnnotation = annotation;
   }
 
+  /**
+   * update associated view model and trigger any necessary repaints.
+   * 
+   * @param updateAllAnnotation
+   */
   protected abstract void valueChanged(boolean updateAllAnnotation);
 
   protected abstract void updateView();
index a4597d3..fef7451 100644 (file)
@@ -157,6 +157,11 @@ public class AppJmol extends StructureViewerBase
 
   IProgressIndicator progressBar = null;
 
+  @Override
+  protected IProgressIndicator getIProgressIndicator()
+  {
+    return progressBar;
+  }
   /**
    * add a single PDB structure to a new or existing Jmol view
    * 
@@ -248,7 +253,7 @@ public class AppJmol extends StructureViewerBase
   @Override
   protected List<StructureViewerBase> getViewersFor(AlignmentPanel apanel)
   {
-    List<StructureViewerBase> result = new ArrayList<StructureViewerBase>();
+    List<StructureViewerBase> result = new ArrayList<>();
     JInternalFrame[] frames = Desktop.instance.getAllFrames();
 
     for (JInternalFrame frame : frames)
@@ -300,7 +305,7 @@ public class AppJmol extends StructureViewerBase
   @Override
   void showSelectedChains()
   {
-    Vector<String> toshow = new Vector<String>();
+    Vector<String> toshow = new Vector<>();
     for (int i = 0; i < chainMenu.getItemCount(); i++)
     {
       if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
@@ -489,7 +494,7 @@ public class AppJmol extends StructureViewerBase
     // todo - record which pdbids were successfully imported.
     StringBuilder errormsgs = new StringBuilder();
 
-    List<String> files = new ArrayList<String>();
+    List<String> files = new ArrayList<>();
     String pdbid = "";
     try
     {
index 9325172..724cec1 100644 (file)
@@ -49,6 +49,12 @@ public class AppJmolBinding extends JalviewJmolBinding
   }
 
   @Override
+  protected IProgressIndicator getIProgressIndicator()
+  {
+    return appJmolWindow.progressBar;
+  }
+
+  @Override
   public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment)
   {
     return new SequenceRenderer(((AlignmentPanel) alignment).av);
diff --git a/src/jalview/gui/AquaInternalFrameManager.java b/src/jalview/gui/AquaInternalFrameManager.java
new file mode 100644 (file)
index 0000000..ea809eb
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jalview.gui;
+
+import java.awt.Container;
+import java.beans.PropertyVetoException;
+import java.util.Vector;
+
+import javax.swing.DefaultDesktopManager;
+import javax.swing.DesktopManager;
+import javax.swing.JInternalFrame;
+
+/**
+ * Based on AquaInternalFrameManager
+ *
+ * DesktopManager implementation for Aqua
+ *
+ * Mac is more like Windows than it's like Motif/Basic
+ *
+ * From WindowsDesktopManager:
+ *
+ * This class implements a DesktopManager which more closely follows the MDI
+ * model than the DefaultDesktopManager. Unlike the DefaultDesktopManager
+ * policy, MDI requires that the selected and activated child frames are the
+ * same, and that that frame always be the top-most window.
+ * <p>
+ * The maximized state is managed by the DesktopManager with MDI, instead of
+ * just being a property of the individual child frame. This means that if the
+ * currently selected window is maximized and another window is selected, that
+ * new window will be maximized.
+ *
+ * Downloaded from
+ * https://raw.githubusercontent.com/frohoff/jdk8u-jdk/master/src/macosx/classes/com/apple/laf/AquaInternalFrameManager.java
+ * 
+ * Patch from Jim Procter - when the most recently opened frame is closed,
+ * correct behaviour is to go to the next most recent frame, rather than wrap
+ * around to the bottom of the window stack (as the original implementation
+ * does)
+ * 
+ * @see com.sun.java.swing.plaf.windows.WindowsDesktopManager
+ */
+public class AquaInternalFrameManager extends DefaultDesktopManager
+{
+  // Variables
+
+  /* The frame which is currently selected/activated.
+   * We store this value to enforce Mac's single-selection model.
+   */
+  JInternalFrame fCurrentFrame;
+
+  JInternalFrame fInitialFrame;
+
+  /* The list of frames, sorted by order of creation.
+   * This list is necessary because by default the order of
+   * child frames in the JDesktopPane changes during frame
+   * activation (the activated frame is moved to index 0).
+   * We preserve the creation order so that "next" and "previous"
+   * frame actions make sense.
+   */
+  Vector<JInternalFrame> fChildFrames = new Vector<>(1);
+
+  /**
+   * keep a reference to the original LAF manager so we can iconise/de-iconise
+   * correctly
+   */
+  private DesktopManager ourManager;
+
+  public AquaInternalFrameManager(DesktopManager desktopManager)
+  {
+    ourManager = desktopManager;
+  }
+
+  @Override
+  public void closeFrame(final JInternalFrame f)
+  {
+    if (f == fCurrentFrame)
+    {
+      boolean mostRecentFrame = fChildFrames
+              .indexOf(f) == fChildFrames.size() - 1;
+      if (!mostRecentFrame)
+      {
+        activateNextFrame();
+      }
+      else
+      {
+        activatePreviousFrame();
+      }
+    }
+    fChildFrames.removeElement(f);
+    super.closeFrame(f);
+  }
+
+  @Override
+  public void deiconifyFrame(final JInternalFrame f)
+  {
+    JInternalFrame.JDesktopIcon desktopIcon;
+
+    desktopIcon = f.getDesktopIcon();
+    // If the icon moved, move the frame to that spot before expanding it
+    // reshape does delta checks for us
+    f.reshape(desktopIcon.getX(), desktopIcon.getY(), f.getWidth(),
+            f.getHeight());
+    ourManager.deiconifyFrame(f);
+  }
+
+  void addIcon(final Container c,
+          final JInternalFrame.JDesktopIcon desktopIcon)
+  {
+    c.add(desktopIcon);
+  }
+
+  /**
+   * Removes the frame from its parent and adds its desktopIcon to the parent.
+   */
+  @Override
+  public void iconifyFrame(final JInternalFrame f)
+  {
+    ourManager.iconifyFrame(f);
+  }
+
+  // WindowsDesktopManager code
+  @Override
+  public void activateFrame(final JInternalFrame f)
+  {
+    try
+    {
+      if (f != null)
+      {
+        super.activateFrame(f);
+      }
+
+      // If this is the first activation, add to child list.
+      if (fChildFrames.indexOf(f) == -1)
+      {
+        fChildFrames.addElement(f);
+      }
+
+      if (fCurrentFrame != null && f != fCurrentFrame)
+      {
+        if (fCurrentFrame.isSelected())
+        {
+          fCurrentFrame.setSelected(false);
+        }
+      }
+
+      if (f != null && !f.isSelected())
+      {
+        f.setSelected(true);
+      }
+
+      fCurrentFrame = f;
+    } catch (final PropertyVetoException e)
+    {
+    }
+  }
+
+  private void switchFrame(final boolean next)
+  {
+    if (fCurrentFrame == null)
+    {
+      // initialize first frame we find
+      if (fInitialFrame != null)
+      {
+        activateFrame(fInitialFrame);
+      }
+      return;
+    }
+
+    final int count = fChildFrames.size();
+    if (count <= 1)
+    {
+      // No other child frames.
+      return;
+    }
+
+    final int currentIndex = fChildFrames.indexOf(fCurrentFrame);
+    if (currentIndex == -1)
+    {
+      // the "current frame" is no longer in the list
+      fCurrentFrame = null;
+      return;
+    }
+
+    int nextIndex;
+    if (next)
+    {
+      nextIndex = currentIndex + 1;
+      if (nextIndex == count)
+      {
+        nextIndex = 0;
+      }
+    }
+    else
+    {
+      nextIndex = currentIndex - 1;
+      if (nextIndex == -1)
+      {
+        nextIndex = count - 1;
+      }
+    }
+    final JInternalFrame f = fChildFrames.elementAt(nextIndex);
+    activateFrame(f);
+    fCurrentFrame = f;
+  }
+
+  /**
+   * Activate the next child JInternalFrame, as determined by the frames'
+   * Z-order. If there is only one child frame, it remains activated. If there
+   * are no child frames, nothing happens.
+   */
+  public void activateNextFrame()
+  {
+    switchFrame(true);
+  }
+
+  /**
+   * same as above but will activate a frame if none have been selected
+   */
+  public void activateNextFrame(final JInternalFrame f)
+  {
+    fInitialFrame = f;
+    switchFrame(true);
+  }
+
+  /**
+   * Activate the previous child JInternalFrame, as determined by the frames'
+   * Z-order. If there is only one child frame, it remains activated. If there
+   * are no child frames, nothing happens.
+   */
+  public void activatePreviousFrame()
+  {
+    switchFrame(false);
+  }
+}
\ No newline at end of file
index a9f3966..e403dba 100644 (file)
@@ -105,6 +105,11 @@ public class CalculationChooser extends JPanel
 
   List<String> tips = new ArrayList<String>();
 
+  /*
+   * the most recently opened PCA results panel
+   */
+  private PCAPanel pcaPanel;
+
   /**
    * Constructor
    * 
@@ -534,7 +539,7 @@ public class CalculationChooser extends JPanel
               JvOptionPane.WARNING_MESSAGE);
       return;
     }
-    new PCAPanel(af.alignPanel, modelName, params);
+    pcaPanel = new PCAPanel(af.alignPanel, modelName, params);
   }
 
   /**
@@ -592,4 +597,9 @@ public class CalculationChooser extends JPanel
     {
     }
   }
+
+  public PCAPanel getPcaPanel()
+  {
+    return pcaPanel;
+  }
 }
index ba360af..89de2e8 100644 (file)
@@ -358,7 +358,7 @@ public class ChimeraViewFrame extends StructureViewerBase
   @Override
   protected List<StructureViewerBase> getViewersFor(AlignmentPanel ap)
   {
-    List<StructureViewerBase> result = new ArrayList<StructureViewerBase>();
+    List<StructureViewerBase> result = new ArrayList<>();
     JInternalFrame[] frames = Desktop.instance.getAllFrames();
 
     for (JInternalFrame frame : frames)
@@ -414,7 +414,7 @@ public class ChimeraViewFrame extends StructureViewerBase
   @Override
   void showSelectedChains()
   {
-    List<String> toshow = new ArrayList<String>();
+    List<String> toshow = new ArrayList<>();
     for (int i = 0; i < chainMenu.getItemCount(); i++)
     {
       if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
@@ -484,8 +484,8 @@ public class ChimeraViewFrame extends StructureViewerBase
     // todo - record which pdbids were successfully imported.
     StringBuilder errormsgs = new StringBuilder(128);
     StringBuilder files = new StringBuilder(128);
-    List<PDBEntry> filePDB = new ArrayList<PDBEntry>();
-    List<Integer> filePDBpos = new ArrayList<Integer>();
+    List<PDBEntry> filePDB = new ArrayList<>();
+    List<Integer> filePDBpos = new ArrayList<>();
     PDBEntry thePdbEntry = null;
     StructureFile pdb = null;
     try
@@ -598,9 +598,12 @@ public class ChimeraViewFrame extends StructureViewerBase
               stopProgressBar("", startTime);
             }
             // Explicitly map to the filename used by Chimera ;
+
             pdb = jmb.getSsm().setMapping(jmb.getSequence()[pos],
-                    jmb.getChains()[pos], pe.getFile(), protocol);
+                    jmb.getChains()[pos], pe.getFile(), protocol,
+                    progressBar);
             stashFoundChains(pdb, pe.getFile());
+
           } catch (OutOfMemoryError oomerror)
           {
             new OOMWarning(
@@ -658,7 +661,7 @@ public class ChimeraViewFrame extends StructureViewerBase
 
   /**
    * Fetch PDB data and save to a local file. Returns the full path to the file,
-   * or null if fetch fails.
+   * or null if fetch fails. TODO: refactor to common with Jmol ? duplication
    * 
    * @param processingEntry
    * @return
@@ -891,4 +894,10 @@ public class ChimeraViewFrame extends StructureViewerBase
     }
     return reply;
   }
+
+  @Override
+  protected IProgressIndicator getIProgressIndicator()
+  {
+    return progressBar;
+  }
 }
index 1f8983f..2d1ba12 100644 (file)
@@ -68,8 +68,6 @@ import java.awt.dnd.DropTargetEvent;
 import java.awt.dnd.DropTargetListener;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
@@ -361,7 +359,10 @@ public class Desktop extends jalview.jbgui.GDesktop
     desktop.setDesktopManager(
             new MyDesktopManager(
                     (Platform.isWindows() ? new DefaultDesktopManager()
-                            : desktop.getDesktopManager())));
+                            : Platform.isAMac()
+                                    ? new AquaInternalFrameManager(
+                                            desktop.getDesktopManager())
+                                    : desktop.getDesktopManager())));
 
     Rectangle dims = getLastKnownDimensions("");
     if (dims != null)
@@ -431,24 +432,6 @@ public class Desktop extends jalview.jbgui.GDesktop
     });
     desktop.addMouseListener(ma);
 
-    this.addFocusListener(new FocusListener()
-    {
-
-      @Override
-      public void focusLost(FocusEvent e)
-      {
-        // TODO Auto-generated method stub
-
-      }
-
-      @Override
-      public void focusGained(FocusEvent e)
-      {
-        Cache.log.debug("Relaying windows after focus gain");
-        // make sure that we sort windows properly after we gain focus
-        instance.relayerWindows();
-      }
-    });
     this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
     // Spawn a thread that shows the splashscreen
     SwingUtilities.invokeLater(new Runnable()
@@ -886,6 +869,10 @@ public class Desktop extends jalview.jbgui.GDesktop
         JInternalFrame itf = desktop.getSelectedFrame();
         if (itf != null)
         {
+          if (itf instanceof AlignFrame)
+          {
+            Jalview.setCurrentAlignFrame((AlignFrame) itf);
+          }
           itf.requestFocus();
         }
       }
@@ -912,15 +899,7 @@ public class Desktop extends jalview.jbgui.GDesktop
           menuItem.removeActionListener(menuItem.getActionListeners()[0]);
         }
         windowMenu.remove(menuItem);
-        JInternalFrame itf = desktop.getSelectedFrame();
-        if (itf != null)
-        {
-          itf.requestFocus();
-          if (itf instanceof AlignFrame)
-          {
-            Jalview.setCurrentAlignFrame((AlignFrame) itf);
-          }
-        }
+
         System.gc();
       };
     });
@@ -2512,14 +2491,6 @@ public class Desktop extends jalview.jbgui.GDesktop
     }
   }
 
-  /**
-   * fixes stacking order after a modal dialog to ensure windows that should be
-   * on top actually are
-   */
-  public void relayerWindows()
-  {
-
-  }
 
   /**
    * Accessor method to quickly get all the AlignmentFrames loaded.
index b27328d..d8db546 100644 (file)
@@ -147,7 +147,7 @@ public class FeatureColourChooser extends JalviewDialog
          */
         if (ap != null)
         {
-          ap.paintAlignment(true);
+          ap.paintAlignment(true, true);
         }
       }
     });
@@ -396,9 +396,9 @@ public class FeatureColourChooser extends JalviewDialog
    * feature type, and repaints the alignment, and optionally the Overview
    * and/or structure viewer if open
    * 
-   * @param updateOverview
+   * @param updateStructsAndOverview
    */
-  void changeColour(boolean updateOverview)
+  void changeColour(boolean updateStructsAndOverview)
   {
     // Check if combobox is still adjusting
     if (adjusting)
@@ -507,7 +507,7 @@ public class FeatureColourChooser extends JalviewDialog
     }
     fr.setColour(type, acg);
     cs = acg;
-    ap.paintAlignment(updateOverview);
+    ap.paintAlignment(updateStructsAndOverview, updateStructsAndOverview);
   }
 
   @Override
@@ -539,7 +539,7 @@ public class FeatureColourChooser extends JalviewDialog
   void reset()
   {
     fr.setColour(type, oldcs);
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
     cs = null;
   }
 
@@ -565,7 +565,7 @@ public class FeatureColourChooser extends JalviewDialog
       /*
        * force repaint of any Overview window or structure
        */
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
     } catch (NumberFormatException ex)
     {
     }
index 17f5a71..9c4b009 100644 (file)
@@ -243,7 +243,7 @@ public class FeatureRenderer
       JPanel choosePanel = new JPanel();
       choosePanel.add(new JLabel(
               MessageManager.getString("label.select_feature") + ":"));
-      final JComboBox<String> overlaps = new JComboBox<String>();
+      final JComboBox<String> overlaps = new JComboBox<>();
       List<String> added = new ArrayList<>();
       for (SequenceFeature sf : features)
       {
@@ -487,7 +487,7 @@ public class FeatureRenderer
 
         featuresAdded();
 
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(true, true);
 
         return true;
       }
@@ -497,7 +497,7 @@ public class FeatureRenderer
       }
     }
 
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
 
     return true;
   }
index 0963b31..3f1d9c7 100644 (file)
@@ -131,6 +131,11 @@ public class FeatureSettings extends JPanel
   private static final int MIN_WIDTH = 400;
 
   private static final int MIN_HEIGHT = 400;
+  
+  /**
+   * when true, constructor is still executing - so ignore UI events
+   */
+  protected volatile boolean inConstruction = true;
 
   /**
    * Constructor
@@ -303,6 +308,7 @@ public class FeatureSettings extends JPanel
               };
             });
     frame.setLayer(JLayeredPane.PALETTE_LAYER);
+    inConstruction = false;
   }
 
   protected void popupSort(final int selectedRow, final String type,
@@ -485,7 +491,7 @@ public class FeatureSettings extends JPanel
   @Override
   synchronized public void discoverAllFeatureData()
   {
-    Set<String> allGroups = new HashSet<String>();
+    Set<String> allGroups = new HashSet<>();
     AlignmentI alignment = af.getViewport().getAlignment();
 
     for (int i = 0; i < alignment.getHeight(); i++)
@@ -535,13 +541,8 @@ public class FeatureSettings extends JPanel
       public void itemStateChanged(ItemEvent evt)
       {
         fr.setGroupVisibility(check.getText(), check.isSelected());
-        af.alignPanel.getSeqPanel().seqCanvas.repaint();
-        if (af.alignPanel.overviewPanel != null)
-        {
-          af.alignPanel.overviewPanel.updateOverviewImage();
-        }
-
         resetTable(new String[] { grp });
+        af.alignPanel.paintAlignment(true, true);
       }
     });
     groupPanel.add(check);
@@ -557,12 +558,12 @@ public class FeatureSettings extends JPanel
       return;
     }
     resettingTable = true;
-    typeWidth = new Hashtable<String, float[]>();
+    typeWidth = new Hashtable<>();
     // TODO: change avWidth calculation to 'per-sequence' average and use long
     // rather than float
 
-    Set<String> displayableTypes = new HashSet<String>();
-    Set<String> foundGroups = new HashSet<String>();
+    Set<String> displayableTypes = new HashSet<>();
+    Set<String> foundGroups = new HashSet<>();
 
     /*
      * determine which feature types may be visible depending on 
@@ -578,7 +579,7 @@ public class FeatureSettings extends JPanel
        * and keep track of which groups are visible
        */
       Set<String> groups = seq.getFeatures().getFeatureGroups(true);
-      Set<String> visibleGroups = new HashSet<String>();
+      Set<String> visibleGroups = new HashSet<>();
       for (String group : groups)
       {
         if (group == null || checkGroupState(group))
@@ -1058,7 +1059,7 @@ public class FeatureSettings extends JPanel
   {
     if (fr.setFeaturePriority(data, visibleNew))
     {
-      af.alignPanel.paintAlignment(true);
+      af.alignPanel.paintAlignment(true, true);
     }
   }
 
@@ -1237,8 +1238,11 @@ public class FeatureSettings extends JPanel
       @Override
       public void stateChanged(ChangeEvent evt)
       {
-        fr.setTransparency((100 - transparency.getValue()) / 100f);
-        af.alignPanel.paintAlignment(true);
+        if (!inConstruction)
+        {
+          fr.setTransparency((100 - transparency.getValue()) / 100f);
+          af.alignPanel.paintAlignment(true,true);
+        }
       }
     });
 
index 6cddcca..f3c8e8f 100755 (executable)
@@ -183,7 +183,7 @@ public class FontChooser extends GFontChooser
   {
     ap.av.antiAlias = smoothFont.isSelected();
     ap.getAnnotationPanel().image = null;
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, false);
     if (ap.av.getCodingComplement() != null && ap.av.isProteinFontAsCdna())
     {
       ((AlignViewport) ap.av
@@ -235,7 +235,7 @@ public class FontChooser extends GFontChooser
       ap.av.setScaleProteinAsCdna(oldProteinScale);
       ap.av.setProteinFontAsCdna(oldMirrorFont);
       ap.av.antiAlias = oldSmoothFont;
-      ap.paintAlignment(true);
+      ap.fontChanged();
 
       if (scaleAsCdna.isVisible() && scaleAsCdna.isEnabled())
       {
index 981e94c..35bd871 100644 (file)
@@ -34,7 +34,8 @@ public interface IProgressIndicator
    * is removed with a second call with same ID.
    * 
    * @param message
-   *          - displayed message for operation
+   *          - displayed message for operation. Please ensure message is
+   *          internationalised.
    * @param id
    *          - unique handle for this indicator
    */
index 3cc0ed3..1f2a3ad 100755 (executable)
@@ -138,7 +138,7 @@ public class IdPanel extends JPanel
     }
 
     lastid = seq;
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
@@ -154,7 +154,7 @@ public class IdPanel extends JPanel
       {
         av.getRanges().scrollRight(true);
       }
-      else if (!av.getWrapAlignment())
+      else
       {
         av.getRanges().scrollUp(false);
       }
@@ -165,7 +165,7 @@ public class IdPanel extends JPanel
       {
         av.getRanges().scrollRight(false);
       }
-      else if (!av.getWrapAlignment())
+      else
       {
         av.getRanges().scrollUp(true);
       }
@@ -313,7 +313,7 @@ public class IdPanel extends JPanel
 
     av.isSelectionGroupChanged(true);
 
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
@@ -507,7 +507,7 @@ public class IdPanel extends JPanel
           running = false;
         }
 
-        alignPanel.paintAlignment(false);
+        alignPanel.paintAlignment(false, false);
 
         try
         {
index 3c4107f..8400543 100755 (executable)
@@ -75,6 +75,7 @@ public class IdwidthAdjuster extends JPanel
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mousePressed(MouseEvent evt)
   {
     oldX = evt.getX();
@@ -86,6 +87,7 @@ public class IdwidthAdjuster extends JPanel
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseReleased(MouseEvent evt)
   {
     active = false;
@@ -112,6 +114,7 @@ public class IdwidthAdjuster extends JPanel
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseEntered(MouseEvent evt)
   {
     active = true;
@@ -124,6 +127,7 @@ public class IdwidthAdjuster extends JPanel
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseExited(MouseEvent evt)
   {
     active = false;
@@ -136,6 +140,7 @@ public class IdwidthAdjuster extends JPanel
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseDragged(MouseEvent evt)
   {
     active = true;
@@ -149,7 +154,7 @@ public class IdwidthAdjuster extends JPanel
     {
       viewport.setIdWidth(newWidth);
 
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, false);
     }
 
     oldX = evt.getX();
@@ -161,6 +166,7 @@ public class IdwidthAdjuster extends JPanel
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseMoved(MouseEvent evt)
   {
   }
@@ -171,6 +177,7 @@ public class IdwidthAdjuster extends JPanel
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseClicked(MouseEvent evt)
   {
   }
@@ -181,6 +188,7 @@ public class IdwidthAdjuster extends JPanel
    * @param g
    *          DOCUMENT ME!
    */
+  @Override
   public void paintComponent(Graphics g)
   {
     g.setColor(Color.white);
index b357234..4a15024 100644 (file)
@@ -216,34 +216,6 @@ public class Jalview2XML
     }
   }
 
-  void clearSeqRefs()
-  {
-    if (_cleartables)
-    {
-      if (seqRefIds != null)
-      {
-        seqRefIds.clear();
-      }
-      if (seqsToIds != null)
-      {
-        seqsToIds.clear();
-      }
-      if (incompleteSeqs != null)
-      {
-        incompleteSeqs.clear();
-      }
-      // seqRefIds = null;
-      // seqsToIds = null;
-    }
-    else
-    {
-      // do nothing
-      warn("clearSeqRefs called when _cleartables was not set. Doing nothing.");
-      // seqRefIds = new Hashtable();
-      // seqsToIds = new IdentityHashMap();
-    }
-  }
-
   void initSeqRefs()
   {
     if (seqsToIds == null)
@@ -1084,7 +1056,7 @@ public class Jalview2XML
 
     // SAVE TREES
     // /////////////////////////////////
-    if (!storeDS && av.currentTree != null)
+    if (!storeDS && av.getCurrentTree() != null)
     {
       // FIND ANY ASSOCIATED TREES
       // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
@@ -1102,7 +1074,7 @@ public class Jalview2XML
             {
               Tree tree = new Tree();
               tree.setTitle(tp.getTitle());
-              tree.setCurrentTree((av.currentTree == tp.getTree()));
+              tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
               tree.setNewick(tp.getTree().print());
               tree.setThreshold(tp.treeCanvas.threshold);
 
@@ -4250,7 +4222,8 @@ public class Jalview2XML
       StructureData filedat = oldFiles.get(id);
       String pdbFile = filedat.getFilePath();
       SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
-      binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE);
+      binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
+              null);
       binding.addSequenceForStructFile(pdbFile, seq);
     }
     // and add the AlignmentPanel's reference to the view panel
@@ -5342,28 +5315,25 @@ public class Jalview2XML
 
   }
 
-  public jalview.gui.AlignmentPanel copyAlignPanel(AlignmentPanel ap,
-          boolean keepSeqRefs)
+  /**
+   * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
+   * view as XML (but not to file), and then reloading it
+   * 
+   * @param ap
+   * @return
+   */
+  public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
   {
     initSeqRefs();
     JalviewModel jm = saveState(ap, null, null, null);
 
-    if (!keepSeqRefs)
-    {
-      clearSeqRefs();
-      jm.getJalviewModelSequence().getViewport(0).setSequenceSetId(null);
-    }
-    else
-    {
-      uniqueSetSuffix = "";
-      jm.getJalviewModelSequence().getViewport(0).setId(null); // we don't
-      // overwrite the
-      // view we just
-      // copied
-    }
+    uniqueSetSuffix = "";
+    jm.getJalviewModelSequence().getViewport(0).setId(null);
+    // we don't overwrite the view we just copied
+
     if (this.frefedSequence == null)
     {
-      frefedSequence = new Vector();
+      frefedSequence = new Vector<SeqFref>();
     }
 
     viewportsAdded.clear();
@@ -5383,32 +5353,8 @@ public class Jalview2XML
     return af.alignPanel;
   }
 
-  /**
-   * flag indicating if hashtables should be cleared on finalization TODO this
-   * flag may not be necessary
-   */
-  private final boolean _cleartables = true;
-
   private Hashtable jvids2vobj;
 
-  /*
-   * (non-Javadoc)
-   * 
-   * @see java.lang.Object#finalize()
-   */
-  @Override
-  protected void finalize() throws Throwable
-  {
-    // really make sure we have no buried refs left.
-    if (_cleartables)
-    {
-      clearSeqRefs();
-    }
-    this.seqRefIds = null;
-    this.seqsToIds = null;
-    super.finalize();
-  }
-
   private void warn(String msg)
   {
     warn(msg, null);
index 51d7a84..9ddb751 100755 (executable)
@@ -40,8 +40,10 @@ import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseMotionAdapter;
 import java.beans.PropertyChangeEvent;
+import java.beans.PropertyVetoException;
 
 import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JInternalFrame;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.SwingUtilities;
@@ -350,8 +352,22 @@ public class OverviewPanel extends JPanel
   {
     try
     {
-      av.getRanges().removePropertyChangeListener(this);
+      if (av != null)
+      {
+        av.getRanges().removePropertyChangeListener(this);
+      }
+
       oviewCanvas.dispose();
+
+      /*
+       * close the parent frame (which also removes it from the
+       * Desktop Windows menu)
+       */
+      ((JInternalFrame) SwingUtilities.getAncestorOfClass(
+              JInternalFrame.class, (this))).setClosed(true);
+    } catch (PropertyVetoException e)
+    {
+      // ignore
     } finally
     {
       progressPanel = null;
index f861a7c..9f52d26 100644 (file)
@@ -79,6 +79,8 @@ public class PCAPanel extends GPCAPanel
 
   int top = 0;
 
+  private boolean working;
+
   /**
    * Creates a new PCAPanel object using default score model and parameters
    * 
@@ -234,6 +236,7 @@ public class PCAPanel extends GPCAPanel
       message = MessageManager.getString("label.pca_calculating");
     }
     progress.setProgressBar(message, progId);
+    working = true;
     try
     {
       calcSettings.setEnabled(false);
@@ -252,6 +255,7 @@ public class PCAPanel extends GPCAPanel
     } catch (OutOfMemoryError er)
     {
       new OOMWarning("calculating PCA", er);
+      working = false;
       return;
     } finally
     {
@@ -266,6 +270,7 @@ public class PCAPanel extends GPCAPanel
               .getString("label.principal_component_analysis"), 475, 450);
       this.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
     }
+    working = false;
   }
 
   @Override
@@ -788,4 +793,14 @@ public class PCAPanel extends GPCAPanel
     top = t;
     zCombobox.setSelectedIndex(2);
   }
+
+  /**
+   * Answers true if PCA calculation is in progress, else false
+   * 
+   * @return
+   */
+  public boolean isWorking()
+  {
+    return working;
+  }
 }
index d731e70..ced5544 100755 (executable)
@@ -26,9 +26,9 @@ import jalview.datamodel.SequenceI;
 import java.awt.Component;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 
 /**
  * Route datamodel/view update events for a sequence set to any display
@@ -74,26 +74,21 @@ public class PaintRefresher
    */
   public static void RemoveComponent(Component comp)
   {
-    List<String> emptied = new ArrayList<String>();
-    for (Entry<String, List<Component>> registered : components.entrySet())
+    if (components == null)
     {
-      String id = registered.getKey();
-      List<Component> comps = components.get(id);
+      return;
+    }
+
+    Iterator<String> it = components.keySet().iterator();
+    while (it.hasNext())
+    {
+      List<Component> comps = components.get(it.next());
       comps.remove(comp);
       if (comps.isEmpty())
       {
-        emptied.add(id);
+        it.remove();
       }
     }
-
-    /*
-     * Remove now empty ids after the above (to avoid
-     * ConcurrentModificationException).
-     */
-    for (String id : emptied)
-    {
-      components.remove(id);
-    }
   }
 
   public static void Refresh(Component source, String id)
index f75407c..d081794 100755 (executable)
@@ -22,7 +22,8 @@ package jalview.gui;
 
 import jalview.analysis.AlignSeq;
 import jalview.datamodel.Alignment;
-import jalview.datamodel.Sequence;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.jbgui.GPairwiseAlignPanel;
 import jalview.util.MessageManager;
@@ -40,49 +41,56 @@ import java.util.Vector;
 public class PairwiseAlignPanel extends GPairwiseAlignPanel
 {
 
+  private static final String DASHES = "---------------------\n";
+
   AlignmentViewport av;
 
-  Vector sequences;
+  Vector<SequenceI> sequences;
 
   /**
    * Creates a new PairwiseAlignPanel object.
    * 
-   * @param av
+   * @param viewport
    *          DOCUMENT ME!
    */
-  public PairwiseAlignPanel(AlignmentViewport av)
+  public PairwiseAlignPanel(AlignmentViewport viewport)
   {
     super();
-    this.av = av;
+    this.av = viewport;
 
-    sequences = new Vector();
+    sequences = new Vector<SequenceI>();
 
-    SequenceI[] seqs;
-    String[] seqStrings = av.getViewAsString(true);
+    SequenceGroup selectionGroup = viewport.getSelectionGroup();
+    boolean isSelection = selectionGroup != null
+            && selectionGroup.getSize() > 0;
+    AlignmentView view = viewport.getAlignmentView(isSelection);
+    // String[] seqStrings = viewport.getViewAsString(true);
+    String[] seqStrings = view.getSequenceStrings(viewport
+            .getGapCharacter());
 
-    if (av.getSelectionGroup() == null)
+    SequenceI[] seqs;
+    if (isSelection)
     {
-      seqs = av.getAlignment().getSequencesArray();
+      seqs = (SequenceI[]) view.getAlignmentAndHiddenColumns(viewport
+              .getGapCharacter())[0];
     }
     else
     {
-      seqs = av.getSelectionGroup().getSequencesInOrder(av.getAlignment());
+      seqs = av.getAlignment().getSequencesArray();
     }
 
-    String type = (av.getAlignment().isNucleotide()) ? AlignSeq.DNA
+    String type = (viewport.getAlignment().isNucleotide()) ? AlignSeq.DNA
             : AlignSeq.PEP;
 
     float[][] scores = new float[seqs.length][seqs.length];
-    double totscore = 0;
+    double totscore = 0D;
     int count = seqs.length;
-
-    Sequence seq;
+    boolean first = true;
 
     for (int i = 1; i < count; i++)
     {
       for (int j = 0; j < i; j++)
       {
-
         AlignSeq as = new AlignSeq(seqs[i], seqStrings[i], seqs[j],
                 seqStrings[j], type);
 
@@ -94,9 +102,15 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel
         as.calcScoreMatrix();
         as.traceAlignment();
 
+        if (!first)
+        {
+          System.out.println(DASHES);
+          textarea.append(DASHES);
+        }
+        first = false;
         as.printAlignment(System.out);
-        scores[i][j] = (float) as.getMaxScore()
-                / (float) as.getASeq1().length;
+        scores[i][j] = as.getMaxScore()
+                / as.getASeq1().length;
         totscore = totscore + scores[i][j];
 
         textarea.append(as.getOutput());
@@ -107,28 +121,53 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel
 
     if (count > 2)
     {
-      System.out.println(
-              "Pairwise alignment scaled similarity score matrix\n");
+      printScoreMatrix(seqs, scores, totscore);
+    }
+  }
 
-      for (int i = 0; i < count; i++)
-      {
-        jalview.util.Format.print(System.out, "%s \n",
-                ("" + i) + " " + seqs[i].getName());
-      }
+  /**
+   * Prints a matrix of seqi-seqj pairwise alignment scores to sysout
+   * 
+   * @param seqs
+   * @param scores
+   * @param totscore
+   */
+  protected void printScoreMatrix(SequenceI[] seqs, float[][] scores,
+          double totscore)
+  {
+    System.out
+            .println("Pairwise alignment scaled similarity score matrix\n");
 
-      System.out.println("\n");
+    for (int i = 0; i < seqs.length; i++)
+    {
+      System.out.println(String.format("%3d %s", i + 1,
+              seqs[i].getDisplayId(true)));
+    }
+
+    /*
+     * table heading columns for sequences 1, 2, 3...
+     */
+    System.out.print("\n ");
+    for (int i = 0; i < seqs.length; i++)
+    {
+      System.out.print(String.format("%7d", i + 1));
+    }
+    System.out.println();
 
-      for (int i = 0; i < count; i++)
+    for (int i = 0; i < seqs.length; i++)
+    {
+      System.out.print(String.format("%3d", i + 1));
+      for (int j = 0; j < i; j++)
       {
-        for (int j = 0; j < i; j++)
-        {
-          jalview.util.Format.print(System.out, "%7.3f",
-                  scores[i][j] / totscore);
-        }
+        /*
+         * as a fraction of tot score, outputs are 0 <= score <= 1
+         */
+        System.out.print(String.format("%7.3f", scores[i][j] / totscore));
       }
-
-      System.out.println("\n");
+      System.out.println();
     }
+
+    System.out.println("\n");
   }
 
   /**
@@ -137,13 +176,14 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   protected void viewInEditorButton_actionPerformed(ActionEvent e)
   {
-    Sequence[] seq = new Sequence[sequences.size()];
+    SequenceI[] seq = new SequenceI[sequences.size()];
 
     for (int i = 0; i < sequences.size(); i++)
     {
-      seq[i] = (Sequence) sequences.elementAt(i);
+      seq[i] = sequences.elementAt(i);
     }
 
     AlignFrame af = new AlignFrame(new Alignment(seq),
index 846ba64..850a09a 100644 (file)
@@ -1743,7 +1743,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       }
 
       sequence.setName(dialog.getName().replace(' ', '_'));
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
 
     sequence.setDescription(dialog.getDescription());
index ea341e3..011d810 100644 (file)
@@ -89,8 +89,8 @@ public class ProgressBar implements IProgressIndicator
     }
     this.statusPanel = container;
     this.statusBar = statusBar;
-    this.progressBars = new Hashtable<Long, JPanel>();
-    this.progressBarHandlers = new Hashtable<Long, IProgressIndicatorHandler>();
+    this.progressBars = new Hashtable<>();
+    this.progressBarHandlers = new Hashtable<>();
 
   }
 
@@ -119,46 +119,52 @@ public class ProgressBar implements IProgressIndicator
    * execution.
    */
   @Override
-  public void setProgressBar(String message, long id)
+  public void setProgressBar(final String message, final long id)
   {
-    Long longId = Long.valueOf(id);
-
-    JPanel progressPanel = progressBars.get(longId);
-    if (progressPanel != null)
+    SwingUtilities.invokeLater(new Runnable()
     {
-      /*
-       * Progress bar is displayed for this id - remove it now, and any handler
-       */
-      progressBars.remove(id);
-      if (message != null && statusBar != null)
-      {
-        statusBar.setText(message);
-      }
-      if (progressBarHandlers.containsKey(longId))
+      @Override
+      public void run()
       {
-        progressBarHandlers.remove(longId);
-      }
-      removeRow(progressPanel);
-    }
-    else
-    {
-      /*
-       * No progress bar for this id - add one now
-       */
-      progressPanel = new JPanel(new BorderLayout(10, 5));
+        JPanel progressPanel = progressBars.get(id);
+        if (progressPanel != null)
+        {
+          /*
+           * Progress bar is displayed for this id - remove it now, and any handler
+           */
+          progressBars.remove(id);
+          if (message != null && statusBar != null)
+          {
+            statusBar.setText(message);
+          }
+          if (progressBarHandlers.containsKey(id))
+          {
+            progressBarHandlers.remove(id);
+          }
+          removeRow(progressPanel);
+        }
+        else
+        {
+          /*
+           * No progress bar for this id - add one now
+           */
+          progressPanel = new JPanel(new BorderLayout(10, 5));
 
-      JProgressBar progressBar = new JProgressBar();
-      progressBar.setIndeterminate(true);
+          JProgressBar progressBar = new JProgressBar();
+          progressBar.setIndeterminate(true);
 
-      progressPanel.add(new JLabel(message), BorderLayout.WEST);
-      progressPanel.add(progressBar, BorderLayout.CENTER);
+          progressPanel.add(new JLabel(message), BorderLayout.WEST);
+          progressPanel.add(progressBar, BorderLayout.CENTER);
 
-      addRow(progressPanel);
+          addRow(progressPanel);
 
-      progressBars.put(longId, progressPanel);
-    }
+          progressBars.put(id, progressPanel);
+        }
+
+        refreshLayout();
+      }
+    });
 
-    refreshLayout();
   }
 
   /**
@@ -215,41 +221,50 @@ public class ProgressBar implements IProgressIndicator
   public void registerHandler(final long id,
           final IProgressIndicatorHandler handler)
   {
-    Long longId = Long.valueOf(id);
-    final JPanel progressPanel = progressBars.get(longId);
-    if (progressPanel == null)
-    {
-      System.err.println(
-              "call setProgressBar before registering the progress bar's handler.");
-      return;
-    }
-
-    /*
-     * Nothing useful to do if not a Cancel handler
-     */
-    if (!handler.canCancel())
-    {
-      return;
-    }
-
-    progressBarHandlers.put(longId, handler);
-    JButton cancel = new JButton(MessageManager.getString("action.cancel"));
     final IProgressIndicator us = this;
-    cancel.addActionListener(new ActionListener()
-    {
 
+    SwingUtilities.invokeLater(new Runnable()
+    {
       @Override
-      public void actionPerformed(ActionEvent e)
+      public void run()
       {
-        handler.cancelActivity(id);
-        us.setProgressBar(MessageManager
-                .formatMessage("label.cancelled_params", new Object[]
-                { ((JLabel) progressPanel.getComponent(0)).getText() }),
-                id);
+        final JPanel progressPanel = progressBars.get(id);
+        if (progressPanel == null)
+        {
+          System.err.println(
+                  "call setProgressBar before registering the progress bar's handler.");
+          return;
+        }
+
+        /*
+         * Nothing useful to do if not a Cancel handler
+         */
+        if (!handler.canCancel())
+        {
+          return;
+        }
+
+        progressBarHandlers.put(id, handler);
+        JButton cancel = new JButton(
+                MessageManager.getString("action.cancel"));
+        cancel.addActionListener(new ActionListener()
+        {
+
+          @Override
+          public void actionPerformed(ActionEvent e)
+          {
+            handler.cancelActivity(id);
+            us.setProgressBar(MessageManager
+                    .formatMessage("label.cancelled_params", new Object[]
+                    { ((JLabel) progressPanel.getComponent(0)).getText() }),
+                    id);
+          }
+        });
+        progressPanel.add(cancel, BorderLayout.EAST);
+        refreshLayout();
+
       }
     });
-    progressPanel.add(cancel, BorderLayout.EAST);
-    refreshLayout();
   }
 
 }
index 6261015..cb59452 100644 (file)
@@ -24,8 +24,6 @@ import jalview.bin.Cache;
 
 import java.awt.Component;
 
-import javax.swing.JOptionPane;
-
 public class PromptUserConfig implements Runnable
 {
   /**
@@ -120,6 +118,7 @@ public class PromptUserConfig implements Runnable
     this.allowCancel = allowCancel;
   }
 
+  @Override
   public void run()
   {
     if (property == null)
@@ -206,12 +205,7 @@ public class PromptUserConfig implements Runnable
               (allowCancel) ? JvOptionPane.YES_NO_CANCEL_OPTION
                       : JvOptionPane.YES_NO_OPTION,
               JvOptionPane.QUESTION_MESSAGE);
-      // now, ask the desktop to relayer any external windows that might have
-      // been obsured
-      if (Desktop.instance != null)
-      {
-        Desktop.instance.relayerWindows();
-      }
+
       // and finish parsing the result
       jalview.bin.Cache.log.debug("Got response : " + reply);
       if (reply == JvOptionPane.YES_OPTION)
index 8bf2fba..c4390c0 100755 (executable)
@@ -54,7 +54,7 @@ public class RedundancyPanel extends GSliderPanel implements Runnable
 
   AlignmentPanel ap;
 
-  Stack<CommandI> historyList = new Stack<CommandI>();
+  Stack<CommandI> historyList = new Stack<>();
 
   // simpler than synching with alignFrame.
 
@@ -194,7 +194,7 @@ public class RedundancyPanel extends GSliderPanel implements Runnable
     }
 
     float value = slider.getValue();
-    List<SequenceI> redundantSequences = new ArrayList<SequenceI>();
+    List<SequenceI> redundantSequences = new ArrayList<>();
     for (int i = 0; i < redundancy.length; i++)
     {
       if (value <= redundancy[i])
@@ -295,7 +295,7 @@ public class RedundancyPanel extends GSliderPanel implements Runnable
       af.updateEditMenuBar();
     }
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
 
     if (historyList.size() == 0)
     {
index 6b2f9c9..2dc198e 100755 (executable)
@@ -168,7 +168,7 @@ public class ScalePanel extends JPanel
         {
           av.showColumn(reveal[0]);
           reveal = null;
-          ap.paintAlignment(true);
+          ap.paintAlignment(true, true);
           av.sendSelection();
         }
       });
@@ -184,7 +184,7 @@ public class ScalePanel extends JPanel
           {
             av.showAllHiddenColumns();
             reveal = null;
-            ap.paintAlignment(true);
+            ap.paintAlignment(true, true);
             av.sendSelection();
           }
         });
@@ -208,7 +208,7 @@ public class ScalePanel extends JPanel
             av.setSelectionGroup(null);
           }
 
-          ap.paintAlignment(true);
+          ap.paintAlignment(true, true);
           av.sendSelection();
         }
       });
@@ -260,7 +260,7 @@ public class ScalePanel extends JPanel
       sg.setEndRes(max);
     }
     av.setSelectionGroup(sg);
-    ap.paintAlignment(false);
+    ap.paintAlignment(false, false);
     av.sendSelection();
   }
 
@@ -297,7 +297,7 @@ public class ScalePanel extends JPanel
       }
       else
       {
-        ap.paintAlignment(false);
+        ap.paintAlignment(false, false);
       }
       return;
     }
@@ -316,7 +316,7 @@ public class ScalePanel extends JPanel
       }
     }
     stretchingGroup = false;
-    ap.paintAlignment(false);
+    ap.paintAlignment(false, false);
     av.sendSelection();
   }
 
@@ -346,7 +346,7 @@ public class ScalePanel extends JPanel
     {
       stretchingGroup = true;
       cs.stretchGroup(res, sg, min, max);
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
   }
 
index 403cbcf..320102f 100755 (executable)
@@ -1502,7 +1502,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     }
     else if (av.getWrapAlignment())
     {
-      if (eventName.equals(ViewportRanges.STARTRES))
+      if (eventName.equals(ViewportRanges.STARTRES)
+              || eventName.equals(ViewportRanges.STARTRESANDSEQ))
       {
         repaint();
       }
@@ -1698,4 +1699,14 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
     return repeatHeight;
   }
+  
+  /**
+   * Answers the width in pixels of the left scale labels (0 if not shown)
+   * 
+   * @return
+   */
+  int getLabelWidthWest()
+  {
+    return labelWidthWest;
+  }
 }
index e99e577..2223ee5 100644 (file)
@@ -215,8 +215,8 @@ public class SeqPanel extends JPanel
               + hgap + seqCanvas.getAnnotationHeight();
 
       int y = evt.getY();
-      y -= hgap;
-      x = Math.max(0, x - seqCanvas.labelWidthWest);
+      y = Math.max(0, y - hgap);
+      x = Math.max(0, x - seqCanvas.getLabelWidthWest());
 
       int cwidth = seqCanvas.getWrappedCanvasWidth(this.getWidth());
       if (cwidth < 1)
@@ -484,7 +484,7 @@ public class SeqPanel extends JPanel
       av.setSelectionGroup(sg);
     }
 
-    ap.paintAlignment(false);
+    ap.paintAlignment(false, false);
     av.sendSelection();
   }
 
@@ -719,10 +719,12 @@ public class SeqPanel extends JPanel
   }
 
   /**
-   * DOCUMENT ME!
+   * Action on mouse movement is to update the status bar to show the current
+   * sequence position, and (if features are shown) to show any features at the
+   * position in a tooltip. Does nothing if the mouse move does not change
+   * residue position.
    * 
    * @param evt
-   *          DOCUMENT ME!
    */
   @Override
   public void mouseMoved(MouseEvent evt)
@@ -735,7 +737,8 @@ public class SeqPanel extends JPanel
     }
 
     final int column = findColumn(evt);
-    int seq = findSeq(evt);
+    final int seq = findSeq(evt);
+
     if (column < 0 || seq < 0 || seq >= av.getAlignment().getHeight())
     {
       lastMouseSeq = -1;
@@ -852,11 +855,12 @@ public class SeqPanel extends JPanel
 
   /**
    * set when the current UI interaction has resulted in a change that requires
-   * overview shading to be recalculated. this could be changed to something
-   * more expressive that indicates what actually has changed, so selective
-   * redraws can be applied
+   * shading in overviews and structures to be recalculated. this could be
+   * changed to a something more expressive that indicates what actually has
+   * changed, so selective redraws can be applied (ie. only structures, only
+   * overview, etc)
    */
-  private boolean needOverviewUpdate = false; // TODO: refactor to avcontroller
+  private boolean updateOverviewAndStructs = false; // TODO: refactor to avcontroller
 
   /**
    * set if av.getSelectionGroup() refers to a group that is defined on the
@@ -1057,7 +1061,7 @@ public class SeqPanel extends JPanel
         }
         if (newWidth > 0)
         {
-          ap.paintAlignment(false);
+          ap.paintAlignment(false, false);
           if (copyChanges)
           {
             /*
@@ -1626,7 +1630,7 @@ public class SeqPanel extends JPanel
         av.getRanges().scrollRight(true);
 
       }
-      else if (!av.getWrapAlignment())
+      else
       {
         av.getRanges().scrollUp(false);
       }
@@ -1637,12 +1641,18 @@ public class SeqPanel extends JPanel
       {
         av.getRanges().scrollRight(false);
       }
-      else if (!av.getWrapAlignment())
+      else
       {
         av.getRanges().scrollUp(true);
       }
     }
-    // TODO Update tooltip for new position.
+
+    /*
+     * update status bar and tooltip for new position
+     * (need to synthesize a mouse movement to refresh tooltip)
+     */
+    mouseMoved(e);
+    ToolTipManager.sharedInstance().mouseMoved(e);
   }
 
   /**
@@ -1656,7 +1666,7 @@ public class SeqPanel extends JPanel
     final int res = findColumn(evt);
     final int seq = findSeq(evt);
     oldSeq = seq;
-    needOverviewUpdate = false;
+    updateOverviewAndStructs = false;
 
     startWrapBlock = wrappedBlock;
 
@@ -1821,7 +1831,7 @@ public class SeqPanel extends JPanel
     // 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()
+    updateOverviewAndStructs |= vischange && av.isSelectionDefinedGroup()
             && afterDrag;
     if (stretchGroup.cs != null)
     {
@@ -1841,8 +1851,10 @@ public class SeqPanel extends JPanel
       }
     }
     PaintRefresher.Refresh(this, av.getSequenceSetId());
-    ap.paintAlignment(needOverviewUpdate);
-    needOverviewUpdate = false;
+    // TODO: structure colours only need updating if stretchGroup used to or now
+    // does contain sequences with structure views
+    ap.paintAlignment(updateOverviewAndStructs, updateOverviewAndStructs);
+    updateOverviewAndStructs = false;
     changeEndRes = false;
     changeStartRes = false;
     stretchGroup = null;
@@ -1896,7 +1908,7 @@ public class SeqPanel extends JPanel
       if (res > (stretchGroup.getStartRes() - 1))
       {
         stretchGroup.setEndRes(res);
-        needOverviewUpdate |= av.isSelectionDefinedGroup();
+        updateOverviewAndStructs |= av.isSelectionDefinedGroup();
       }
     }
     else if (changeStartRes)
@@ -1904,7 +1916,7 @@ public class SeqPanel extends JPanel
       if (res < (stretchGroup.getEndRes() + 1))
       {
         stretchGroup.setStartRes(res);
-        needOverviewUpdate |= av.isSelectionDefinedGroup();
+        updateOverviewAndStructs |= av.isSelectionDefinedGroup();
       }
     }
 
@@ -1938,7 +1950,7 @@ public class SeqPanel extends JPanel
       if (stretchGroup.getSequences(null).contains(nextSeq))
       {
         stretchGroup.deleteSequence(seq, false);
-        needOverviewUpdate |= av.isSelectionDefinedGroup();
+        updateOverviewAndStructs |= av.isSelectionDefinedGroup();
       }
       else
       {
@@ -1948,7 +1960,7 @@ public class SeqPanel extends JPanel
         }
 
         stretchGroup.addSequence(nextSeq, false);
-        needOverviewUpdate |= av.isSelectionDefinedGroup();
+        updateOverviewAndStructs |= av.isSelectionDefinedGroup();
       }
     }
 
index e6ec822..93a2457 100755 (executable)
@@ -127,7 +127,7 @@ public class SliderPanel extends GSliderPanel
       @Override
       public void mouseReleased(MouseEvent evt)
       {
-        ap.paintAlignment(true);
+        ap.paintAlignment(true, true);
       }
     });
 
index da10e3f..20f4a49 100644 (file)
@@ -157,8 +157,8 @@ public class StructureChooser extends GStructureChooser
     Collection<FTSDataColumnI> wantedFields = pdbDocFieldPrefs
             .getStructureSummaryFields();
 
-    discoveredStructuresSet = new LinkedHashSet<FTSData>();
-    HashSet<String> errors = new HashSet<String>();
+    discoveredStructuresSet = new LinkedHashSet<>();
+    HashSet<String> errors = new HashSet<>();
     for (SequenceI seq : selectedSequences)
     {
       FTSRestRequest pdbRequest = new FTSRestRequest();
@@ -223,7 +223,7 @@ public class StructureChooser extends GStructureChooser
 
   public void loadLocalCachedPDBEntries()
   {
-    ArrayList<CachedPDB> entries = new ArrayList<CachedPDB>();
+    ArrayList<CachedPDB> entries = new ArrayList<>();
     for (SequenceI seq : selectedSequences)
     {
       if (seq.getDatasetSequence() != null
@@ -257,7 +257,7 @@ public class StructureChooser extends GStructureChooser
     boolean isPDBRefsFound = false;
     boolean isUniProtRefsFound = false;
     StringBuilder queryBuilder = new StringBuilder();
-    Set<String> seqRefs = new LinkedHashSet<String>();
+    Set<String> seqRefs = new LinkedHashSet<>();
 
     if (seq.getAllPDBEntries() != null
             && queryBuilder.length() < MAX_QLENGTH)
@@ -401,8 +401,8 @@ public class StructureChooser extends GStructureChooser
         lbl_loading.setVisible(true);
         Collection<FTSDataColumnI> wantedFields = pdbDocFieldPrefs
                 .getStructureSummaryFields();
-        Collection<FTSData> filteredResponse = new HashSet<FTSData>();
-        HashSet<String> errors = new HashSet<String>();
+        Collection<FTSData> filteredResponse = new HashSet<>();
+        HashSet<String> errors = new HashSet<>();
 
         for (SequenceI seq : selectedSequences)
         {
@@ -453,7 +453,7 @@ public class StructureChooser extends GStructureChooser
         if (!filteredResponse.isEmpty())
         {
           final int filterResponseCount = filteredResponse.size();
-          Collection<FTSData> reorderedStructuresSet = new LinkedHashSet<FTSData>();
+          Collection<FTSData> reorderedStructuresSet = new LinkedHashSet<>();
           reorderedStructuresSet.addAll(filteredResponse);
           reorderedStructuresSet.addAll(discoveredStructuresSet);
           getResultTable().setModel(FTSRestResponse
@@ -725,11 +725,10 @@ public class StructureChooser extends GStructureChooser
   @Override
   public void ok_ActionPerformed()
   {
-    final long progressSessionId = System.currentTimeMillis();
     final StructureSelectionManager ssm = ap.getStructureSelectionManager();
+
     final int preferredHeight = pnl_filter.getHeight();
-    ssm.setProgressIndicator(this);
-    ssm.setProgressSessionId(progressSessionId);
+
     new Thread(new Runnable()
     {
       @Override
@@ -747,7 +746,7 @@ public class StructureChooser extends GStructureChooser
           int[] selectedRows = getResultTable().getSelectedRows();
           PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
           int count = 0;
-          List<SequenceI> selectedSeqsToView = new ArrayList<SequenceI>();
+          List<SequenceI> selectedSeqsToView = new ArrayList<>();
           for (int row : selectedRows)
           {
             String pdbIdStr = getResultTable()
@@ -761,6 +760,7 @@ public class StructureChooser extends GStructureChooser
               pdbEntry = getFindEntry(pdbIdStr,
                       selectedSeq.getAllPDBEntries());
             }
+
             if (pdbEntry == null)
             {
               pdbEntry = new PDBEntry();
@@ -783,7 +783,7 @@ public class StructureChooser extends GStructureChooser
                   .getModelIndex();
           int refSeqColIndex = tbl_local_pdb.getColumn("Ref Sequence")
                   .getModelIndex();
-          List<SequenceI> selectedSeqsToView = new ArrayList<SequenceI>();
+          List<SequenceI> selectedSeqsToView = new ArrayList<>();
           for (int row : selectedRows)
           {
             PDBEntry pdbEntry = (PDBEntry) tbl_local_pdb.getValueAt(row,
@@ -805,7 +805,6 @@ public class StructureChooser extends GStructureChooser
           {
             selectedSequence = userSelectedSeq;
           }
-
           String pdbIdStr = txt_search.getText();
           PDBEntry pdbEntry = selectedSequence.getPDBEntry(pdbIdStr);
           if (pdbEntry == null)
@@ -847,6 +846,7 @@ public class StructureChooser extends GStructureChooser
                   { selectedSequence });
         }
         closeAction(preferredHeight);
+        mainFrame.dispose();
       }
     }).start();
   }
@@ -870,13 +870,15 @@ public class StructureChooser extends GStructureChooser
           final PDBEntry[] pdbEntriesToView,
           final AlignmentPanel alignPanel, SequenceI[] sequences)
   {
-    ssm.setProgressBar(MessageManager
-            .getString("status.launching_3d_structure_viewer"));
+    long progressId = sequences.hashCode();
+    setProgressBar(MessageManager
+            .getString("status.launching_3d_structure_viewer"), progressId);
     final StructureViewer sViewer = new StructureViewer(ssm);
+    setProgressBar(null, progressId);
 
     if (SiftsSettings.isMapWithSifts())
     {
-      List<SequenceI> seqsWithoutSourceDBRef = new ArrayList<SequenceI>();
+      List<SequenceI> seqsWithoutSourceDBRef = new ArrayList<>();
       int p = 0;
       // TODO: skip PDBEntry:Sequence pairs where PDBEntry doesn't look like a
       // real PDB ID. For moment, we can also safely do this if there is already
@@ -907,41 +909,43 @@ public class StructureChooser extends GStructureChooser
       if (!seqsWithoutSourceDBRef.isEmpty())
       {
         int y = seqsWithoutSourceDBRef.size();
-        ssm.setProgressBar(null);
-        ssm.setProgressBar(MessageManager.formatMessage(
+        setProgressBar(MessageManager.formatMessage(
                 "status.fetching_dbrefs_for_sequences_without_valid_refs",
-                y));
+                y), progressId);
         SequenceI[] seqWithoutSrcDBRef = new SequenceI[y];
         int x = 0;
         for (SequenceI fSeq : seqsWithoutSourceDBRef)
         {
           seqWithoutSrcDBRef[x++] = fSeq;
         }
+
         DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef);
         dbRefFetcher.fetchDBRefs(true);
+
+        setProgressBar("Fetch complete.", progressId); // todo i18n
       }
     }
     if (pdbEntriesToView.length > 1)
     {
-      ArrayList<SequenceI[]> seqsMap = new ArrayList<SequenceI[]>();
+      ArrayList<SequenceI[]> seqsMap = new ArrayList<>();
       for (SequenceI seq : sequences)
       {
         seqsMap.add(new SequenceI[] { seq });
       }
       SequenceI[][] collatedSeqs = seqsMap.toArray(new SequenceI[0][0]);
-      ssm.setProgressBar(null);
-      ssm.setProgressBar(MessageManager.getString(
-              "status.fetching_3d_structures_for_selected_entries"));
+
+      setProgressBar(MessageManager
+                    .getString("status.fetching_3d_structures_for_selected_entries"), progressId);
       sViewer.viewStructures(pdbEntriesToView, collatedSeqs, alignPanel);
     }
     else
     {
-      ssm.setProgressBar(null);
-      ssm.setProgressBar(MessageManager.formatMessage(
+      setProgressBar(MessageManager.formatMessage(
               "status.fetching_3d_structures_for",
-              pdbEntriesToView[0].getId()));
+              pdbEntriesToView[0].getId()),progressId);
       sViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
     }
+    setProgressBar(null, progressId);
   }
 
   /**
@@ -1000,7 +1004,7 @@ public class StructureChooser extends GStructureChooser
           String searchTerm = txt_search.getText().toLowerCase();
           searchTerm = searchTerm.split(":")[0];
           // System.out.println(">>>>> search term : " + searchTerm);
-          List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+          List<FTSDataColumnI> wantedFields = new ArrayList<>();
           FTSRestRequest pdbRequest = new FTSRestRequest();
           pdbRequest.setAllowEmptySeq(false);
           pdbRequest.setResponseSize(1);
@@ -1062,7 +1066,7 @@ public class StructureChooser extends GStructureChooser
 
     public PDBEntryTableModel(List<CachedPDB> pdbEntries)
     {
-      this.pdbEntries = new ArrayList<CachedPDB>(pdbEntries);
+      this.pdbEntries = new ArrayList<>(pdbEntries);
     }
 
     @Override
index 3ba9947..31c20ed 100644 (file)
@@ -83,18 +83,18 @@ public abstract class StructureViewerBase extends GStructureViewer
   /**
    * list of sequenceSet ids associated with the view
    */
-  protected List<String> _aps = new ArrayList<String>();
+  protected List<String> _aps = new ArrayList<>();
 
   /**
    * list of alignment panels to use for superposition
    */
-  protected Vector<AlignmentPanel> _alignwith = new Vector<AlignmentPanel>();
+  protected Vector<AlignmentPanel> _alignwith = new Vector<>();
 
   /**
    * list of alignment panels that are used for colouring structures by aligned
    * sequences
    */
-  protected Vector<AlignmentPanel> _colourwith = new Vector<AlignmentPanel>();
+  protected Vector<AlignmentPanel> _colourwith = new Vector<>();
 
   private String viewId = null;
 
@@ -170,7 +170,7 @@ public abstract class StructureViewerBase extends GStructureViewer
   {
     if (_alignwith == null)
     {
-      _alignwith = new Vector<AlignmentPanel>();
+      _alignwith = new Vector<>();
     }
     if (_alignwith.size() == 0 && ap != null)
     {
@@ -310,6 +310,8 @@ public abstract class StructureViewerBase extends GStructureViewer
 
   public abstract ViewerType getViewerType();
 
+  protected abstract IProgressIndicator getIProgressIndicator();
+
   /**
    * add a new structure (with associated sequences and chains) to this viewer,
    * retrieving it if necessary first.
@@ -460,7 +462,7 @@ public abstract class StructureViewerBase extends GStructureViewer
      * create the mappings
      */
     apanel.getStructureSelectionManager().setMapping(seq, chains,
-            pdbFilename, DataSourceType.FILE);
+            pdbFilename, DataSourceType.FILE, getIProgressIndicator());
 
     /*
      * alert the FeatureRenderer to show new (PDB RESNUM) features
@@ -468,7 +470,9 @@ public abstract class StructureViewerBase extends GStructureViewer
     if (apanel.getSeqPanel().seqCanvas.fr != null)
     {
       apanel.getSeqPanel().seqCanvas.fr.featuresAdded();
-      apanel.paintAlignment(true);
+      // note - we don't do a refresh for structure here because we do it
+      // explicitly for all panels later on
+      apanel.paintAlignment(true, false);
     }
 
     /*
@@ -717,11 +721,11 @@ public abstract class StructureViewerBase extends GStructureViewer
 
     if (_colourwith == null)
     {
-      _colourwith = new Vector<AlignmentPanel>();
+      _colourwith = new Vector<>();
     }
     if (_alignwith == null)
     {
-      _alignwith = new Vector<AlignmentPanel>();
+      _alignwith = new Vector<>();
     }
 
     ViewSelectionMenu seqColourBy = new ViewSelectionMenu(
@@ -888,7 +892,7 @@ public abstract class StructureViewerBase extends GStructureViewer
     binding.setColourBySequence(seqColour.isSelected());
     if (_colourwith == null)
     {
-      _colourwith = new Vector<AlignmentPanel>();
+      _colourwith = new Vector<>();
     }
     if (binding.isColourBySequence())
     {
index 3986561..53e2dee 100644 (file)
@@ -184,9 +184,9 @@ public class TextColourChooser
    */
   protected void saveInitialSettings()
   {
-    groupColour1 = new HashMap<SequenceGroup, Color>();
-    groupColour2 = new HashMap<SequenceGroup, Color>();
-    groupThreshold = new HashMap<SequenceGroup, Integer>();
+    groupColour1 = new HashMap<>();
+    groupColour2 = new HashMap<>();
+    groupThreshold = new HashMap<>();
 
     if (sg == null)
     {
@@ -237,7 +237,7 @@ public class TextColourChooser
       sg.textColour = col;
     }
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(false, false);
   }
 
   void colour2Changed(Color col)
@@ -255,7 +255,7 @@ public class TextColourChooser
       sg.textColour2 = col;
     }
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(false, false);
   }
 
   void thresholdChanged(int value)
@@ -273,7 +273,7 @@ public class TextColourChooser
       sg.thresholdTextColour = value;
     }
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(false, false);
   }
 
   void setGroupTextColour()
index 5e14fce..2727db1 100755 (executable)
@@ -55,6 +55,7 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.image.BufferedImage;
 import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
 import java.io.FileOutputStream;
 import java.util.ArrayList;
 import java.util.List;
@@ -63,6 +64,8 @@ import javax.imageio.ImageIO;
 import javax.swing.ButtonGroup;
 import javax.swing.JMenuItem;
 import javax.swing.JRadioButtonMenuItem;
+import javax.swing.event.InternalFrameAdapter;
+import javax.swing.event.InternalFrameEvent;
 
 import org.jibble.epsgraphics.EpsGraphics2D;
 
@@ -141,7 +144,35 @@ public class TreePanel extends GTreePanel
 
     buildAssociatedViewMenu();
 
-    av.addPropertyChangeListener(new java.beans.PropertyChangeListener()
+    final PropertyChangeListener listener = addAlignmentListener();
+
+    /*
+     * remove listener when window is closed, so that this
+     * panel can be garbage collected
+     */
+    addInternalFrameListener(new InternalFrameAdapter()
+    {
+      @Override
+      public void internalFrameClosed(InternalFrameEvent evt)
+      {
+        if (av != null)
+        {
+          av.removePropertyChangeListener(listener);
+        }
+      }
+    });
+
+    TreeLoader tl = new TreeLoader(newTree, inputData);
+    tl.start();
+
+  }
+
+  /**
+   * @return
+   */
+  protected PropertyChangeListener addAlignmentListener()
+  {
+    final PropertyChangeListener listener = new PropertyChangeListener()
     {
       @Override
       public void propertyChange(PropertyChangeEvent evt)
@@ -168,11 +199,9 @@ public class TreePanel extends GTreePanel
           repaint();
         }
       }
-    });
-
-    TreeLoader tl = new TreeLoader(newTree, inputData);
-    tl.start();
-
+    };
+    av.addPropertyChangeListener(listener);
+    return listener;
   }
 
   @Override
@@ -493,7 +522,7 @@ public class TreePanel extends GTreePanel
 
     if (treeCanvas.applyToAllViews)
     {
-      final ArrayList<CommandI> commands = new ArrayList<CommandI>();
+      final ArrayList<CommandI> commands = new ArrayList<>();
       for (AlignmentPanel ap : PaintRefresher
               .getAssociatedPanels(av.getSequenceSetId()))
       {
@@ -550,13 +579,14 @@ public class TreePanel extends GTreePanel
 
   public CommandI sortAlignmentIn(AlignmentPanel ap)
   {
+    // TODO: move to alignment view controller
     AlignmentViewport viewport = ap.av;
     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
     AlignmentSorter.sortByTree(viewport.getAlignment(), tree);
     CommandI undo;
     undo = new OrderCommand("Tree Sort", oldOrder, viewport.getAlignment());
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, false);
     return undo;
   }
 
index 8b45c40..3290500 100755 (executable)
@@ -136,7 +136,7 @@ public class UserDefinedColours extends GUserDefinedColours
   UserDefinedColours()
   {
     super();
-    selectedButtons = new ArrayList<JButton>();
+    selectedButtons = new ArrayList<>();
   }
 
   void showFrame()
@@ -163,7 +163,7 @@ public class UserDefinedColours extends GUserDefinedColours
 
     if (upperCaseButtons == null)
     {
-      upperCaseButtons = new ArrayList<JButton>();
+      upperCaseButtons = new ArrayList<>();
     }
 
     for (int i = 0; i < 20; i++)
@@ -194,7 +194,7 @@ public class UserDefinedColours extends GUserDefinedColours
 
       if (lowerCaseButtons == null)
       {
-        lowerCaseButtons = new ArrayList<JButton>();
+        lowerCaseButtons = new ArrayList<>();
       }
 
       for (int i = 0; i < 20; i++)
@@ -631,8 +631,8 @@ public class UserDefinedColours extends GUserDefinedColours
   @Override
   protected void loadbutton_actionPerformed()
   {
-    upperCaseButtons = new ArrayList<JButton>();
-    lowerCaseButtons = new ArrayList<JButton>();
+    upperCaseButtons = new ArrayList<>();
+    lowerCaseButtons = new ArrayList<>();
 
     JalviewFileChooser chooser = new JalviewFileChooser("jc",
             "Jalview User Colours");
@@ -876,7 +876,7 @@ public class UserDefinedColours extends GUserDefinedColours
   protected void cancelButton_actionPerformed()
   {
     ap.alignFrame.changeColour(oldColourScheme);
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
 
     try
     {
index cdbb4fa..2a7743a 100644 (file)
@@ -60,15 +60,6 @@ public class ViewSelectionMenu extends JMenu
 
   private ItemListener _handler;
 
-  @Override
-  protected void finalize() throws Throwable
-  {
-    _selectedviews = null;
-    _handler = null;
-    _allviews = null;
-    super.finalize();
-  }
-
   /**
    * create a new view selection menu. This menu has some standard entries
    * (select all, invert selection), and a checkbox for every view. Mousing over
index 26641b1..f26d6da 100755 (executable)
@@ -606,18 +606,4 @@ public class FileLoader implements Runnable
     return tempStructFile.toString();
   }
 
-  /*
-   * (non-Javadoc)
-   * 
-   * @see java.lang.Object#finalize()
-   */
-  @Override
-  protected void finalize() throws Throwable
-  {
-    source = null;
-    alignFrame = null;
-    viewport = null;
-    super.finalize();
-  }
-
 }
index d269e97..65ba74a 100644 (file)
@@ -47,11 +47,4 @@ public class InputStreamParser extends FileParse
     error = false;
   }
 
-  @Override
-  protected void finalize() throws Throwable
-  {
-    dataIn = null;
-    super.finalize();
-  }
-
 }
index 6e7df71..d526a31 100755 (executable)
@@ -184,7 +184,7 @@ public class WSWUBlastClient
         }
       }
     }
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, false);
 
   }
 
index 083cd26..29f3fa9 100644 (file)
@@ -39,19 +39,6 @@ public class JSFunctionExec implements Runnable
     jvlite.setExecutor(this);
   }
 
-  @Override
-  protected void finalize() throws Throwable
-  {
-    jvlite = null;
-    executor = null;
-    if (jsExecQueue != null)
-    {
-      jsExecQueue.clear();
-    }
-    jsExecQueue = null;
-    super.finalize();
-  }
-
   private Vector jsExecQueue;
 
   private Thread executor = null;
index 874bfd3..6071933 100644 (file)
@@ -299,13 +299,6 @@ public class MouseOverStructureListener extends JSFunctionExec
   }
 
   @Override
-  public void finalize() throws Throwable
-  {
-    jvlite = null;
-    super.finalize();
-  }
-
-  @Override
   public void releaseReferences(Object svl)
   {
 
index 9fec256..d92608c 100644 (file)
@@ -34,12 +34,24 @@ import java.util.List;
  */
 public class ScaleRenderer
 {
+  /**
+   * Represents one major or minor scale mark
+   */
   public final class ScaleMark
   {
+    /**
+     * true for a major scale mark, false for minor
+     */
     public final boolean major;
 
+    /**
+     * visible column position (0..) e.g. 19
+     */
     public final int column;
 
+    /**
+     * text (if any) to show e.g. "20"
+     */
     public final String text;
 
     ScaleMark(boolean isMajor, int col, String txt)
@@ -48,19 +60,27 @@ public class ScaleRenderer
       column = col;
       text = txt;
     }
+
+    /**
+     * String representation for inspection when debugging only
+     */
+    @Override
+    public String toString()
+    {
+      return String.format("%s:%d:%s", major ? "major" : "minor", column,
+              text);
+    }
   }
 
   /**
-   * calculate positions markers on the alignment ruler
+   * Calculates position markers on the alignment ruler
    * 
    * @param av
    * @param startx
-   *          left-most column in visible view
+   *          left-most column in visible view (0..)
    * @param endx
-   *          - right-most column in visible view
-   * @return List of ScaleMark holding boolean: true/false for major/minor mark,
-   *         marker position in alignment column coords, a String to be rendered
-   *         at the position (or null)
+   *          - right-most column in visible view (0..)
+   * @return
    */
   public List<ScaleMark> calculateMarks(AlignViewportI av, int startx,
           int endx)
@@ -87,41 +107,40 @@ public class ScaleRenderer
       scalestartx += 5;
     }
     List<ScaleMark> marks = new ArrayList<ScaleMark>();
-    String string;
-    int refN, iadj;
     // todo: add a 'reference origin column' to set column number relative to
-    for (int i = scalestartx; i < endx; i += 5)
+    for (int i = scalestartx; i <= endx; i += 5)
     {
       if (((i - refSp) % 10) == 0)
       {
+        String text;
         if (refSeq == null)
         {
-          iadj = av.getAlignment().getHiddenColumns()
+          int iadj = av.getAlignment().getHiddenColumns()
                   .adjustForHiddenColumns(i - 1) + 1;
-          string = String.valueOf(iadj);
+          text = String.valueOf(iadj);
         }
         else
         {
-          iadj = av.getAlignment().getHiddenColumns()
+          int iadj = av.getAlignment().getHiddenColumns()
                   .adjustForHiddenColumns(i - 1);
-          refN = refSeq.findPosition(iadj);
+          int refN = refSeq.findPosition(iadj);
           // TODO show bounds if position is a gap
           // - ie L--R -> "1L|2R" for
           // marker
           if (iadj < refStartI)
           {
-            string = String.valueOf(iadj - refStartI);
+            text = String.valueOf(iadj - refStartI);
           }
           else if (iadj > refEndI)
           {
-            string = "+" + String.valueOf(iadj - refEndI);
+            text = "+" + String.valueOf(iadj - refEndI);
           }
           else
           {
-            string = String.valueOf(refN) + refSeq.getCharAt(iadj);
+            text = String.valueOf(refN) + refSeq.getCharAt(iadj);
           }
         }
-        marks.add(new ScaleMark(true, i - startx - 1, string));
+        marks.add(new ScaleMark(true, i - startx - 1, text));
       }
       else
       {
index f16522f..1f47da3 100644 (file)
@@ -216,7 +216,8 @@ public class FeatureRenderer extends FeatureRendererModel
       return null;
     }
 
-    if (Comparison.isGap(seq.getCharAt(column)))
+    // column is 'base 1' but getCharAt is an array index (ie from 0)
+    if (Comparison.isGap(seq.getCharAt(column - 1)))
     {
       /*
        * returning null allows the colour scheme to provide gap colour
index 15cb157..9809fa9 100644 (file)
@@ -58,7 +58,7 @@ public class RNAHelicesColourChooser
     oldcs = av.getGlobalColourScheme();
     if (av.getAlignment().getGroups() != null)
     {
-      oldgroupColours = new Hashtable<SequenceGroup, ColourSchemeI>();
+      oldgroupColours = new Hashtable<>();
       for (SequenceGroup sg : ap.getAlignment().getGroups())
       {
         if (sg.getColourScheme() != null)
@@ -71,7 +71,7 @@ public class RNAHelicesColourChooser
     this.ap = ap;
 
     adjusting = true;
-    Vector<String> list = new Vector<String>();
+    Vector<String> list = new Vector<>();
     int index = 1;
     AlignmentAnnotation[] anns = av.getAlignment().getAlignmentAnnotation();
     if (anns != null)
@@ -105,6 +105,6 @@ public class RNAHelicesColourChooser
 
     av.setGlobalColourScheme(rhc);
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 }
index b973f45..35e2536 100644 (file)
@@ -66,7 +66,7 @@ public class StructureSelectionManager
 
   static IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> instances;
 
-  private List<StructureMapping> mappings = new ArrayList<StructureMapping>();
+  private List<StructureMapping> mappings = new ArrayList<>();
 
   private boolean processSecondaryStructure = false;
 
@@ -74,20 +74,16 @@ public class StructureSelectionManager
 
   private boolean addTempFacAnnot = false;
 
-  private IProgressIndicator progressIndicator;
-
   private SiftsClient siftsClient = null;
 
-  private long progressSessionId;
-
   /*
    * Set of any registered mappings between (dataset) sequences.
    */
-  private List<AlignedCodonFrame> seqmappings = new ArrayList<AlignedCodonFrame>();
+  private List<AlignedCodonFrame> seqmappings = new ArrayList<>();
 
-  private List<CommandListener> commandListeners = new ArrayList<CommandListener>();
+  private List<CommandListener> commandListeners = new ArrayList<>();
 
-  private List<SelectionListener> sel_listeners = new ArrayList<SelectionListener>();
+  private List<SelectionListener> sel_listeners = new ArrayList<>();
 
   /**
    * @return true if will try to use external services for processing secondary
@@ -175,9 +171,9 @@ public class StructureSelectionManager
    * map between the PDB IDs (or structure identifiers) used by Jalview and the
    * absolute filenames for PDB data that corresponds to it
    */
-  Map<String, String> pdbIdFileName = new HashMap<String, String>();
+  Map<String, String> pdbIdFileName = new HashMap<>();
 
-  Map<String, String> pdbFileNameId = new HashMap<String, String>();
+  Map<String, String> pdbFileNameId = new HashMap<>();
 
   public void registerPDBFile(String idForFile, String absoluteFile)
   {
@@ -228,7 +224,7 @@ public class StructureSelectionManager
     }
     if (instances == null)
     {
-      instances = new java.util.IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager>();
+      instances = new java.util.IdentityHashMap<>();
     }
     StructureSelectionManager instance = instances.get(context);
     if (instance == null)
@@ -324,9 +320,11 @@ public class StructureSelectionManager
    * @return null or the structure data parsed as a pdb file
    */
   synchronized public StructureFile setMapping(SequenceI[] sequence,
-          String[] targetChains, String pdbFile, DataSourceType protocol)
+          String[] targetChains, String pdbFile, DataSourceType protocol, 
+          IProgressIndicator progress)
   {
-    return setMapping(true, sequence, targetChains, pdbFile, protocol);
+    return computeMapping(true, sequence, targetChains, pdbFile, protocol,
+            progress);
   }
 
   /**
@@ -353,6 +351,16 @@ public class StructureSelectionManager
           SequenceI[] sequenceArray, String[] targetChainIds,
           String pdbFile, DataSourceType sourceType)
   {
+    return computeMapping(forStructureView, sequenceArray, targetChainIds,
+            pdbFile, sourceType, null);
+  }
+
+  synchronized public StructureFile computeMapping(
+          boolean forStructureView, SequenceI[] sequenceArray,
+          String[] targetChainIds, String pdbFile, DataSourceType sourceType,
+          IProgressIndicator progress)
+  {
+    long progressSessionId = System.currentTimeMillis() * 3;
     /*
      * There will be better ways of doing this in the future, for now we'll use
      * the tried and tested MCview pdb mapping
@@ -500,12 +508,14 @@ public class StructureSelectionManager
         pdbFile = "INLINE" + pdb.getId();
       }
 
-      List<StructureMapping> seqToStrucMapping = new ArrayList<StructureMapping>();
+      List<StructureMapping> seqToStrucMapping = new ArrayList<>();
       if (isMapUsingSIFTs && seq.isProtein())
       {
-        setProgressBar(null);
-        setProgressBar(MessageManager
-                .getString("status.obtaining_mapping_with_sifts"));
+        if (progress!=null) {
+          progress.setProgressBar(MessageManager
+                .getString("status.obtaining_mapping_with_sifts"),
+                  progressSessionId);
+        }
         jalview.datamodel.Mapping sqmpping = maxAlignseq
                 .getMappingFromS1(false);
         if (targetChainId != null && !targetChainId.trim().isEmpty())
@@ -538,7 +548,7 @@ public class StructureSelectionManager
         }
         else
         {
-          List<StructureMapping> foundSiftsMappings = new ArrayList<StructureMapping>();
+          List<StructureMapping> foundSiftsMappings = new ArrayList<>();
           for (PDBChain chain : pdb.getChains())
           {
             try
@@ -575,20 +585,25 @@ public class StructureSelectionManager
       }
       else
       {
-        setProgressBar(null);
-        setProgressBar(MessageManager
-                .getString("status.obtaining_mapping_with_nw_alignment"));
+        if (progress != null)
+        {
+          progress.setProgressBar(MessageManager
+                                 .getString("status.obtaining_mapping_with_nw_alignment"),
+                  progressSessionId);
+        }
         StructureMapping nwMapping = getNWMappings(seq, pdbFile, maxChainId,
                 maxChain, pdb, maxAlignseq);
         seqToStrucMapping.add(nwMapping);
         ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
-
       }
-
       if (forStructureView)
       {
         mappings.addAll(seqToStrucMapping);
       }
+      if (progress != null)
+      {
+        progress.setProgressBar(null, progressSessionId);
+      }
     }
     return pdb;
   }
@@ -683,7 +698,7 @@ public class StructureSelectionManager
             .getMappingFromS1(false);
     maxChain.transferRESNUMFeatures(seq, null);
 
-    HashMap<Integer, int[]> mapping = new HashMap<Integer, int[]>();
+    HashMap<Integer, int[]> mapping = new HashMap<>();
     int resNum = -10000;
     int index = 0;
     char insCode = ' ';
@@ -737,7 +752,7 @@ public class StructureSelectionManager
      * Remove mappings to the closed listener's PDB files, but first check if
      * another listener is still interested
      */
-    List<String> pdbs = new ArrayList<String>(Arrays.asList(pdbfiles));
+    List<String> pdbs = new ArrayList<>(Arrays.asList(pdbfiles));
 
     StructureListener sl;
     for (int i = 0; i < listeners.size(); i++)
@@ -758,7 +773,7 @@ public class StructureSelectionManager
      */
     if (pdbs.size() > 0)
     {
-      List<StructureMapping> tmp = new ArrayList<StructureMapping>();
+      List<StructureMapping> tmp = new ArrayList<>();
       for (StructureMapping sm : mappings)
       {
         if (!pdbs.contains(sm.pdbfile))
@@ -844,7 +859,7 @@ public class StructureSelectionManager
                 && sm.pdbchain.equals(atom.getChain()))
         {
           int indexpos = sm.getSeqPos(atom.getPdbResNum());
-          if (lastipos != indexpos && lastseq != sm.sequence)
+          if (lastipos != indexpos || lastseq != sm.sequence)
           {
             results.addResult(sm.sequence, indexpos, indexpos);
             lastipos = indexpos;
@@ -952,7 +967,7 @@ public class StructureSelectionManager
       return;
     }
     int atomNo;
-    List<AtomSpec> atoms = new ArrayList<AtomSpec>();
+    List<AtomSpec> atoms = new ArrayList<>();
     for (StructureMapping sm : mappings)
     {
       if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()
@@ -1060,7 +1075,7 @@ public class StructureSelectionManager
 
   public StructureMapping[] getMapping(String pdbfile)
   {
-    List<StructureMapping> tmp = new ArrayList<StructureMapping>();
+    List<StructureMapping> tmp = new ArrayList<>();
     for (StructureMapping sm : mappings)
     {
       if (sm.pdbfile.equals(pdbfile))
@@ -1220,7 +1235,7 @@ public class StructureSelectionManager
     }
   }
 
-  Vector<AlignmentViewPanelListener> view_listeners = new Vector<AlignmentViewPanelListener>();
+  Vector<AlignmentViewPanelListener> view_listeners = new Vector<>();
 
   public synchronized void sendViewPosition(
           jalview.api.AlignmentViewPanel source, int startRes, int endRes,
@@ -1343,35 +1358,6 @@ public class StructureSelectionManager
     return null;
   }
 
-  public IProgressIndicator getProgressIndicator()
-  {
-    return progressIndicator;
-  }
-
-  public void setProgressIndicator(IProgressIndicator progressIndicator)
-  {
-    this.progressIndicator = progressIndicator;
-  }
-
-  public long getProgressSessionId()
-  {
-    return progressSessionId;
-  }
-
-  public void setProgressSessionId(long progressSessionId)
-  {
-    this.progressSessionId = progressSessionId;
-  }
-
-  public void setProgressBar(String message)
-  {
-    if (progressIndicator == null)
-    {
-      return;
-    }
-    progressIndicator.setProgressBar(message, progressSessionId);
-  }
-
   public List<AlignedCodonFrame> getSequenceMappings()
   {
     return seqmappings;
index 3682239..9c5c109 100644 (file)
@@ -939,4 +939,55 @@ public final class MappingUtils
     }
     return copy;
   }
+
+  /**
+   * Removes the specified number of positions from the given ranges. Provided
+   * to allow a stop codon to be stripped from a CDS sequence so that it matches
+   * the peptide translation length.
+   * 
+   * @param positions
+   * @param ranges
+   *          a list of (single) [start, end] ranges
+   * @return
+   */
+  public static void removeEndPositions(int positions,
+          List<int[]> ranges)
+  {
+    int toRemove = positions;
+    Iterator<int[]> it = new ReverseListIterator<>(ranges);
+    while (toRemove > 0)
+    {
+      int[] endRange = it.next();
+      if (endRange.length != 2)
+      {
+        /*
+         * not coded for [start1, end1, start2, end2, ...]
+         */
+        System.err
+                .println("MappingUtils.removeEndPositions doesn't handle multiple  ranges");
+        return;
+      }
+
+      int length = endRange[1] - endRange[0] + 1;
+      if (length <= 0)
+      {
+        /*
+         * not coded for a reverse strand range (end < start)
+         */
+        System.err
+                .println("MappingUtils.removeEndPositions doesn't handle reverse strand");
+        return;
+      }
+      if (length > toRemove)
+      {
+        endRange[1] -= toRemove;
+        toRemove = 0;
+      }
+      else
+      {
+        toRemove -= length;
+        it.remove();
+      }
+    }
+  }
 }
index b260cab..a0cbff4 100644 (file)
@@ -22,6 +22,7 @@ package jalview.viewmodel;
 
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.analysis.Conservation;
+import jalview.analysis.TreeModel;
 import jalview.api.AlignCalcManagerI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
@@ -79,7 +80,7 @@ import java.util.Map;
 public abstract class AlignmentViewport
         implements AlignViewportI, CommandListener, VamsasSource
 {
-  final protected ViewportRanges ranges;
+  protected ViewportRanges ranges;
 
   protected ViewStyleI viewStyle = new ViewStyle();
 
@@ -947,11 +948,15 @@ public abstract class AlignmentViewport
     groupConsensus = null;
     groupConservation = null;
     hconsensus = null;
+    hconservation = null;
     hcomplementConsensus = null;
-    // colour scheme may hold reference to consensus
-    residueShading = null;
-    // TODO remove listeners from changeSupport?
+    gapcounts = null;
+    calculator = null;
+    residueShading = null; // may hold a reference to Consensus
     changeSupport = null;
+    ranges = null;
+    currentTree = null;
+    selectionGroup = null;
     setAlignment(null);
   }
 
@@ -1333,7 +1338,10 @@ public abstract class AlignmentViewport
   public void removePropertyChangeListener(
           java.beans.PropertyChangeListener listener)
   {
-    changeSupport.removePropertyChangeListener(listener);
+    if (changeSupport != null)
+    {
+      changeSupport.removePropertyChangeListener(listener);
+    }
   }
 
   /**
@@ -2869,6 +2877,8 @@ public abstract class AlignmentViewport
    */
   private SearchResultsI searchResults = null;
 
+  protected TreeModel currentTree = null;
+
   @Override
   public boolean hasSearchResults()
   {
@@ -2927,4 +2937,16 @@ public abstract class AlignmentViewport
             + ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
     return sq;
   }
+
+  @Override
+  public void setCurrentTree(TreeModel tree)
+  {
+    currentTree = tree;
+  }
+
+  @Override
+  public TreeModel getCurrentTree()
+  {
+    return currentTree;
+  }
 }
index b1d2c02..6331ffb 100644 (file)
@@ -465,23 +465,39 @@ public class ViewportRanges extends ViewportProperties
    */
   public boolean scrollUp(boolean up)
   {
+    /*
+     * if in unwrapped mode, scroll up or down one sequence row;
+     * if in wrapped mode, scroll by one visible width of columns
+     */
     if (up)
     {
-      if (startSeq < 1)
+      if (wrappedMode)
       {
-        return false;
+        pageUp();
+      }
+      else
+      {
+        if (startSeq < 1)
+        {
+          return false;
+        }
+        setStartSeq(startSeq - 1);
       }
-
-      setStartSeq(startSeq - 1);
     }
     else
     {
-      if (endSeq >= getVisibleAlignmentHeight() - 1)
+      if (wrappedMode)
       {
-        return false;
+        pageDown();
+      }
+      else
+      {
+        if (endSeq >= getVisibleAlignmentHeight() - 1)
+        {
+          return false;
+        }
+        setStartSeq(startSeq + 1);
       }
-
-      setStartSeq(startSeq + 1);
     }
     return true;
   }
index 8569039..8f37f15 100644 (file)
@@ -51,7 +51,7 @@ class AnnotationWorker extends AlignCalcWorker
           AnnotationProviderI counter)
   {
     super(viewport, panel);
-    ourAnnots = new ArrayList<AlignmentAnnotation>();
+    ourAnnots = new ArrayList<>();
     this.counter = counter;
     calcMan.registerWorker(this);
   }
@@ -121,7 +121,10 @@ class AnnotationWorker extends AlignCalcWorker
     if (ap != null)
     {
       ap.adjustAnnotationHeight();
-      ap.paintAlignment(true);
+      // TODO: only need to update colour and geometry if panel height changes
+      // and view is coloured by annotation, and the annotation is actually
+      // changed!
+      ap.paintAlignment(true, true);
     }
   }
 
index 24cb717..74695fe 100644 (file)
@@ -57,7 +57,7 @@ class ColumnCounterSetWorker extends AlignCalcWorker
           AlignmentViewPanel panel, FeatureSetCounterI counter)
   {
     super(viewport, panel);
-    ourAnnots = new ArrayList<AlignmentAnnotation>();
+    ourAnnots = new ArrayList<>();
     this.counter = counter;
     calcMan.registerWorker(this);
   }
@@ -116,7 +116,7 @@ class ColumnCounterSetWorker extends AlignCalcWorker
       {
         ap.adjustAnnotationHeight();
       }
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
     }
 
   }
index 4242b2a..335529c 100644 (file)
@@ -64,7 +64,7 @@ public class ConsensusThread extends AlignCalcWorker
         {
           if (ap != null)
           {
-            ap.paintAlignment(false);
+            ap.paintAlignment(false, false);
           }
           Thread.sleep(200);
         } catch (Exception ex)
@@ -93,7 +93,7 @@ public class ConsensusThread extends AlignCalcWorker
 
       if (ap != null)
       {
-        ap.paintAlignment(true);
+        ap.paintAlignment(true, true);
       }
     } catch (OutOfMemoryError error)
     {
index 571234c..54b0191 100644 (file)
@@ -75,7 +75,7 @@ public class ConservationThread extends AlignCalcWorker
         abortAndDestroy();
         return;
       }
-      List<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
+      List<AlignmentAnnotation> ourAnnot = new ArrayList<>();
       AlignmentI alignment = alignViewport.getAlignment();
       conservation = alignViewport.getAlignmentConservationAnnotation();
       quality = alignViewport.getAlignmentQualityAnnot();
@@ -123,7 +123,7 @@ public class ConservationThread extends AlignCalcWorker
     }
     if (ap != null)
     {
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
     }
 
   }
index 5ed2885..61ec3d0 100644 (file)
@@ -139,7 +139,7 @@ public class StrucConsensusThread extends AlignCalcWorker
       calcMan.workerComplete(this);
       if (ap != null)
       {
-        ap.paintAlignment(true);
+        ap.paintAlignment(true, true);
       }
     }
 
index 0a61dff..c661e2c 100644 (file)
@@ -135,7 +135,7 @@ public class DasSequenceFeatureFetcher
           boolean useJDasMultiThread)
   {
     this.useJDASMultiThread = useJDasMultiThread;
-    this.selectedSources = new ArrayList<jalviewSourceI>();
+    this.selectedSources = new ArrayList<>();
     // filter both sequences and sources to eliminate duplicates
     for (jalviewSourceI src : selectedSources2)
     {
@@ -316,17 +316,17 @@ public class DasSequenceFeatureFetcher
     FeaturesClientMultipleSources fc = new FeaturesClientMultipleSources();
     fc.setConnProps(sourceRegistry.getSessionHandler());
     // Now sending requests one at a time to each server
-    ArrayList<jalviewSourceI> srcobj = new ArrayList<jalviewSourceI>();
-    ArrayList<String> src = new ArrayList<String>();
-    List<List<String>> ids = new ArrayList<List<String>>();
-    List<List<DBRefEntry>> idobj = new ArrayList<List<DBRefEntry>>();
-    List<Map<String, SequenceI>> sqset = new ArrayList<Map<String, SequenceI>>();
+    ArrayList<jalviewSourceI> srcobj = new ArrayList<>();
+    ArrayList<String> src = new ArrayList<>();
+    List<List<String>> ids = new ArrayList<>();
+    List<List<DBRefEntry>> idobj = new ArrayList<>();
+    List<Map<String, SequenceI>> sqset = new ArrayList<>();
     for (jalviewSourceI _sr : selectedSources)
     {
 
-      Map<String, SequenceI> slist = new HashMap<String, SequenceI>();
-      List<DBRefEntry> idob = new ArrayList<DBRefEntry>();
-      List<String> qset = new ArrayList<String>();
+      Map<String, SequenceI> slist = new HashMap<>();
+      List<DBRefEntry> idob = new ArrayList<>();
+      List<String> qset = new ArrayList<>();
 
       for (SequenceI seq : sequences)
       {
@@ -368,8 +368,8 @@ public class DasSequenceFeatureFetcher
         sqset.add(slist);
       }
     }
-    Map<String, Map<List<String>, Exception>> errors = new HashMap<String, Map<List<String>, Exception>>();
-    Map<String, Map<List<String>, DasGFFAdapter>> results = new HashMap<String, Map<List<String>, DasGFFAdapter>>();
+    Map<String, Map<List<String>, Exception>> errors = new HashMap<>();
+    Map<String, Map<List<String>, DasGFFAdapter>> results = new HashMap<>();
     if (!useJDASMultiThread)
     {
       Iterator<String> sources = src.iterator();
@@ -390,7 +390,7 @@ public class DasSequenceFeatureFetcher
             if (ers == null)
             {
               results.put(source,
-                      ers = new HashMap<List<String>, DasGFFAdapter>());
+                      ers = new HashMap<>());
             }
             ers.put(qid, dga);
           } catch (Exception ex)
@@ -399,7 +399,7 @@ public class DasSequenceFeatureFetcher
             if (ers == null)
             {
               errors.put(source,
-                      ers = new HashMap<List<String>, Exception>());
+                      ers = new HashMap<>());
             }
             ers.put(qid, ex);
           }
@@ -438,7 +438,7 @@ public class DasSequenceFeatureFetcher
           Map<List<String>, DasGFFAdapter> results,
           Map<List<String>, Exception> errors)
   {
-    Set<SequenceI> sequences = new HashSet<SequenceI>();
+    Set<SequenceI> sequences = new HashSet<>();
     String source = jvsource.getSourceURL();
     // process features
     DasGFFAdapter result = (results == null) ? null : results.get(ids);
@@ -622,7 +622,7 @@ public class DasSequenceFeatureFetcher
         if (seq == af.getViewport().getAlignment().getSequenceAt(index)
                 .getDatasetSequence())
         {
-          af.alignPanel.paintAlignment(true);
+          af.alignPanel.paintAlignment(true, true);
           index = end;
           break;
         }
@@ -647,8 +647,8 @@ public class DasSequenceFeatureFetcher
     // TODO: minimal list of DAS queries to make by querying with untyped ID if
     // distinct from any typed IDs
 
-    List<DBRefEntry> ids = new ArrayList<DBRefEntry>();
-    List<String> qstring = new ArrayList<String>();
+    List<DBRefEntry> ids = new ArrayList<>();
+    List<String> qstring = new ArrayList<>();
     boolean dasCoordSysFound = false;
 
     if (uprefs != null)
index c24ea05..9a2316c 100644 (file)
@@ -99,22 +99,22 @@ public class AADisorderClient extends JabawsCalcWorker
   {
     // TODO: turn this into some kind of configuration file that's a bit easier
     // to edit
-    featureMap = new HashMap<String, Map<String, String[]>>();
+    featureMap = new HashMap<>();
     Map<String, String[]> fmap;
     featureMap.put(compbio.ws.client.Services.IUPredWS.toString(),
-            fmap = new HashMap<String, String[]>());
+            fmap = new HashMap<>());
     fmap.put("Glob",
             new String[]
             { "Globular Domain", "Predicted globular domain" });
     featureMap.put(compbio.ws.client.Services.JronnWS.toString(),
-            fmap = new HashMap<String, String[]>());
+            fmap = new HashMap<>());
     featureMap.put(compbio.ws.client.Services.DisemblWS.toString(),
-            fmap = new HashMap<String, String[]>());
+            fmap = new HashMap<>());
     fmap.put("REM465", new String[] { "REM465", "Missing density" });
     fmap.put("HOTLOOPS", new String[] { "HOTLOOPS", "Flexible loops" });
     fmap.put("COILS", new String[] { "COILS", "Random coil" });
     featureMap.put(compbio.ws.client.Services.GlobPlotWS.toString(),
-            fmap = new HashMap<String, String[]>());
+            fmap = new HashMap<>());
     fmap.put("GlobDoms",
             new String[]
             { "Globular Domain", "Predicted globular domain" });
@@ -122,9 +122,9 @@ public class AADisorderClient extends JabawsCalcWorker
             new String[]
             { "Protein Disorder", "Probable unstructured peptide region" });
     Map<String, Map<String, Object>> amap;
-    annotMap = new HashMap<String, Map<String, Map<String, Object>>>();
+    annotMap = new HashMap<>();
     annotMap.put(compbio.ws.client.Services.GlobPlotWS.toString(),
-            amap = new HashMap<String, Map<String, Object>>());
+            amap = new HashMap<>());
     amap.put("Dydx", new HashMap<String, Object>());
     amap.get("Dydx").put(DONTCOMBINE, DONTCOMBINE);
     amap.get("Dydx").put(THRESHOLD, new double[] { 1, 0 });
@@ -135,7 +135,7 @@ public class AADisorderClient extends JabawsCalcWorker
     amap.put("RawScore", new HashMap<String, Object>());
     amap.get("RawScore").put(INVISIBLE, INVISIBLE);
     annotMap.put(compbio.ws.client.Services.DisemblWS.toString(),
-            amap = new HashMap<String, Map<String, Object>>());
+            amap = new HashMap<>());
     amap.put("COILS", new HashMap<String, Object>());
     amap.put("HOTLOOPS", new HashMap<String, Object>());
     amap.put("REM465", new HashMap<String, Object>());
@@ -148,7 +148,7 @@ public class AADisorderClient extends JabawsCalcWorker
     amap.get("REM465").put(RANGE, new float[] { 0, 1 });
 
     annotMap.put(compbio.ws.client.Services.IUPredWS.toString(),
-            amap = new HashMap<String, Map<String, Object>>());
+            amap = new HashMap<>());
     amap.put("Long", new HashMap<String, Object>());
     amap.put("Short", new HashMap<String, Object>());
     amap.get("Long").put(THRESHOLD, new double[] { 1, 0.5 });
@@ -156,7 +156,7 @@ public class AADisorderClient extends JabawsCalcWorker
     amap.get("Short").put(THRESHOLD, new double[] { 1, 0.5 });
     amap.get("Short").put(RANGE, new float[] { 0, 1 });
     annotMap.put(compbio.ws.client.Services.JronnWS.toString(),
-            amap = new HashMap<String, Map<String, Object>>());
+            amap = new HashMap<>());
     amap.put("JRonn", new HashMap<String, Object>());
     amap.get("JRonn").put(THRESHOLD, new double[] { 1, 0.5 });
     amap.get("JRonn").put(RANGE, new float[] { 0, 1 });
@@ -173,8 +173,8 @@ public class AADisorderClient extends JabawsCalcWorker
       Map<String, Map<String, Object>> annotTypeMap = annotMap
               .get(service.serviceType);
       boolean dispFeatures = false;
-      Map<String, Object> fc = new Hashtable<String, Object>();
-      List<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
+      Map<String, Object> fc = new Hashtable<>();
+      List<AlignmentAnnotation> ourAnnot = new ArrayList<>();
       /**
        * grouping for any annotation rows created
        */
@@ -358,7 +358,6 @@ public class AADisorderClient extends JabawsCalcWorker
             // only do this if the alignFrame is currently showing this view.
             af.setShowSeqFeatures(true);
           }
-          ap.paintAlignment(true);
         }
         if (ourAnnot.size() > 0)
         {
@@ -366,6 +365,7 @@ public class AADisorderClient extends JabawsCalcWorker
           // new alignment annotation rows created.
           updateOurAnnots(ourAnnot);
           ap.adjustAnnotationHeight();
+          ap.paintAlignment(true, true);
         }
       }
     }
index 26fe0a2..dd64e77 100644 (file)
@@ -30,6 +30,7 @@ import jalview.datamodel.AnnotatedCollectionI;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.IProgressIndicator;
+import jalview.gui.IProgressIndicatorHandler;
 import jalview.schemes.ResidueProperties;
 import jalview.workers.AlignCalcWorker;
 import jalview.ws.jws2.dm.AAConSettings;
@@ -220,7 +221,26 @@ public abstract class AbstractJabaCalcWorker extends AlignCalcWorker
                 progressId = System.currentTimeMillis());
       }
       rslt = submitToService(seqs);
+      if (guiProgress != null)
+      {
+        guiProgress.registerHandler(progressId,
+                new IProgressIndicatorHandler()
+                {
 
+                  @Override
+                  public boolean cancelActivity(long id)
+                  {
+                    cancelCurrentJob();
+                    return true;
+                  }
+
+                  @Override
+                  public boolean canCancel()
+                  {
+                    return true;
+                  }
+                });
+      }
       boolean finished = false;
       long rpos = 0;
       do
@@ -372,7 +392,8 @@ public abstract class AbstractJabaCalcWorker extends AlignCalcWorker
         {
           guiProgress.setProgressBar("", progressId);
         }
-        ap.paintAlignment(true);
+        // TODO: may not need to paintAlignment again !
+        ap.paintAlignment(false, false);
       }
       if (msg.length() > 0)
       {
@@ -582,7 +603,7 @@ public abstract class AbstractJabaCalcWorker extends AlignCalcWorker
   protected boolean checkDone()
   {
     calcMan.notifyStart(this);
-    ap.paintAlignment(false);
+    ap.paintAlignment(false, false);
     while (!calcMan.notifyWorking(this))
     {
       if (calcMan.isWorking(this))
@@ -593,7 +614,7 @@ public abstract class AbstractJabaCalcWorker extends AlignCalcWorker
       {
         if (ap != null)
         {
-          ap.paintAlignment(false);
+          ap.paintAlignment(false, false);
         }
 
         Thread.sleep(200);
index cb8f75a..2f3c298 100644 (file)
@@ -170,13 +170,11 @@ public class Jws2Instance
     {
       try
       {
-        Closeable svc = (Closeable) service;
-        service = null;
-        svc.close();
-      } catch (Exception e)
+        ((Closeable) service).close();
+      } catch (Throwable t)
       {
+        // ignore
       }
-      ;
     }
     super.finalize();
   }
index 3187fd9..9d3877c 100644 (file)
@@ -27,39 +27,25 @@ import jalview.datamodel.SequenceI;
 import jalview.gui.JvOptionPane;
 import jalview.io.FastaFile;
 
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
 import java.util.Arrays;
 import java.util.Random;
 
 import org.testng.annotations.BeforeClass;
 
 /**
- * Generates, and outputs in Fasta format, a random DNA alignment for given
+ * Generates, and outputs in Fasta format, a random peptide or nucleotide alignment for given
  * sequence length and count. Will regenerate the same alignment each time if
  * the same random seed is used (so may be used for reproducible unit tests).
  * Not guaranteed to reproduce the same results between versions, as the rules
  * may get tweaked to produce more 'realistic' results.
  * 
- * Arguments:
- * <ul>
- * <li>length (number of bases in each sequence)</li>
- * <li>height (number of sequences)</li>
- * <li>a whole number random seed</li>
- * <li>percentage of gaps to include (0-100)</li>
- * <li>percentage chance of variation of each position (0-100)</li>
- * </ul>
- * 
  * @author gmcarstairs
- *
  */
 public class AlignmentGenerator
 {
-  @BeforeClass(alwaysRun = true)
-  public void setUpJvOptionPane()
-  {
-    JvOptionPane.setInteractiveMode(false);
-    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
-  }
-
   private static final char GAP = '-';
 
   private static final char ZERO = '0';
@@ -72,51 +58,76 @@ public class AlignmentGenerator
 
   private Random random;
 
+  private PrintStream ps;
 
   /**
-   * Outputs a DNA 'alignment' where each position is a random choice from
-   * 'GTCA-'.
+   * Outputs a pseudo-randomly generated nucleotide or peptide alignment
+   * Arguments:
+   * <ul>
+   * <li>n (for nucleotide) or p (for peptide)</li>
+   * <li>length (number of bases in each sequence)</li>
+   * <li>height (number of sequences)</li>
+   * <li>a whole number random seed</li>
+   * <li>percentage of gaps to include (0-100)</li>
+   * <li>percentage chance of variation of each position (0-100)</li>
+   * <li>(optional) path to a file to write the alignment to</li>
+   * </ul>
+   * 
    * 
    * @param args
+   * @throws FileNotFoundException
    */
-  public static void main(String[] args)
+  public static void main(String[] args) throws FileNotFoundException
   {
-    if (args.length != 6)
+    if (args.length != 6 && args.length != 7)
     {
       usage();
       return;
     }
+
+    PrintStream ps = System.out;
+    if (args.length == 7)
+    {
+      ps = new PrintStream(new File(args[6]));
+    }
+
     boolean nucleotide = args[0].toLowerCase().startsWith("n");
     int width = Integer.parseInt(args[1]);
     int height = Integer.parseInt(args[2]);
     long randomSeed = Long.valueOf(args[3]);
     int gapPercentage = Integer.valueOf(args[4]);
     int changePercentage = Integer.valueOf(args[5]);
-    AlignmentI al = new AlignmentGenerator(nucleotide).generate(width,
-            height,
-            randomSeed, gapPercentage, changePercentage);
 
-    System.out.println("; " + height + " sequences of " + width
+    ps.println("; " + height + " sequences of " + width
             + " bases with " + gapPercentage + "% gaps and "
             + changePercentage + "% mutations (random seed = " + randomSeed
             + ")");
-    System.out.println(new FastaFile().print(al.getSequencesArray(), true));
+
+    new AlignmentGenerator(nucleotide, ps).generate(width, height,
+            randomSeed, gapPercentage, changePercentage);
+
+    if (ps != System.out)
+    {
+      ps.close();
+    }
   }
 
   /**
-   * Print parameter help.
+   * Prints parameter help
    */
   private static void usage()
   {
     System.out.println("Usage:");
     System.out.println("arg0: n (for nucleotide) or p (for peptide)");
     System.out.println("arg1: number of (non-gap) bases per sequence");
-    System.out.println("arg2: number sequences");
+    System.out.println("arg2: number of sequences");
     System.out
             .println("arg3: an integer as random seed (same seed = same results)");
     System.out.println("arg4: percentage of gaps to (randomly) generate");
     System.out
             .println("arg5: percentage of 'mutations' to (randomly) generate");
+    System.out
+            .println("arg6: (optional) path to output file (default is sysout)");
     System.out.println("Example: AlignmentGenerator n 12 15 387 10 5");
     System.out
             .println("- 15 nucleotide sequences of 12 bases each, approx 10% gaps and 5% mutations, random seed = 387");
@@ -124,16 +135,28 @@ public class AlignmentGenerator
   }
 
   /**
-   * Constructor that sets nucleotide or peptide symbol set
+   * Constructor that sets nucleotide or peptide symbol set, and also writes the
+   * generated alignment to sysout
    */
   public AlignmentGenerator(boolean nuc)
   {
-    BASES = nuc ? NUCS : PEPS;
+    this(nuc, System.out);
+  }
+
+  /**
+   * Constructor that sets nucleotide or peptide symbol set, and also writes the
+   * generated alignment to the specified output stream (if not null). This can
+   * be used to write the alignment to a file or sysout.
+   */
+  public AlignmentGenerator(boolean nucleotide, PrintStream printStream)
+  {
+    BASES = nucleotide ? NUCS : PEPS;
+    ps = printStream;
   }
 
   /**
-   * Outputs a DNA 'alignment' of given width and height, where each position is
-   * a random choice from 'GTCA-'.
+   * Outputs an 'alignment' of given width and height, where each position is a
+   * random choice from the symbol alphabet, or - for gap
    * 
    * @param width
    * @param height
@@ -153,6 +176,12 @@ public class AlignmentGenerator
               seqno + 1, width, changePercentage);
     }
     AlignmentI al = new Alignment(seqs);
+
+    if (ps != null)
+    {
+      ps.println(new FastaFile().print(al.getSequencesArray(), true));
+    }
+
     return al;
   }
 
index 4439bb9..06b51e6 100644 (file)
@@ -2533,4 +2533,71 @@ public class AlignmentUtilsTests
     assertEquals(s_as3, uas3.getSequenceAsString());
   }
 
+  /**
+   * Tests for the method that maps nucleotide to protein based on CDS features
+   */
+  @Test(groups = "Functional")
+  public void testMapCdsToProtein()
+  {
+    SequenceI peptide = new Sequence("pep", "KLQ");
+
+    /*
+     * Case 1: CDS 3 times length of peptide
+     * NB method only checks lengths match, not translation
+     */
+    SequenceI dna = new Sequence("dna", "AACGacgtCTCCT");
+    dna.createDatasetSequence();
+    dna.addSequenceFeature(new SequenceFeature("CDS", "", 1, 4, null));
+    dna.addSequenceFeature(new SequenceFeature("CDS", "", 9, 13, null));
+    MapList ml = AlignmentUtils.mapCdsToProtein(dna, peptide);
+    assertEquals(3, ml.getFromRatio());
+    assertEquals(1, ml.getToRatio());
+    assertEquals("[[1, 3]]",
+            Arrays.deepToString(ml.getToRanges().toArray()));
+    assertEquals("[[1, 4], [9, 13]]",
+            Arrays.deepToString(ml.getFromRanges().toArray()));
+
+    /*
+     * Case 2: CDS 3 times length of peptide + stop codon
+     * (note code does not currently check trailing codon is a stop codon)
+     */
+    dna = new Sequence("dna", "AACGacgtCTCCTTGA");
+    dna.createDatasetSequence();
+    dna.addSequenceFeature(new SequenceFeature("CDS", "", 1, 4, null));
+    dna.addSequenceFeature(new SequenceFeature("CDS", "", 9, 16, null));
+    ml = AlignmentUtils.mapCdsToProtein(dna, peptide);
+    assertEquals(3, ml.getFromRatio());
+    assertEquals(1, ml.getToRatio());
+    assertEquals("[[1, 3]]",
+            Arrays.deepToString(ml.getToRanges().toArray()));
+    assertEquals("[[1, 4], [9, 13]]",
+            Arrays.deepToString(ml.getFromRanges().toArray()));
+
+    /*
+     * Case 3: CDS not 3 times length of peptide - no mapping is made
+     */
+    dna = new Sequence("dna", "AACGacgtCTCCTTG");
+    dna.createDatasetSequence();
+    dna.addSequenceFeature(new SequenceFeature("CDS", "", 1, 4, null));
+    dna.addSequenceFeature(new SequenceFeature("CDS", "", 9, 15, null));
+    ml = AlignmentUtils.mapCdsToProtein(dna, peptide);
+    assertNull(ml);
+
+    /*
+     * Case 4: incomplete start codon corresponding to X in peptide
+     */
+    dna = new Sequence("dna", "ACGacgtCTCCTTGG");
+    dna.createDatasetSequence();
+    SequenceFeature sf = new SequenceFeature("CDS", "", 1, 3, null);
+    sf.setPhase("2"); // skip 2 positions (AC) to start of next codon (GCT)
+    dna.addSequenceFeature(sf);
+    dna.addSequenceFeature(new SequenceFeature("CDS", "", 8, 15, null));
+    peptide = new Sequence("pep", "XLQ");
+    ml = AlignmentUtils.mapCdsToProtein(dna, peptide);
+    assertEquals("[[2, 3]]",
+            Arrays.deepToString(ml.getToRanges().toArray()));
+    assertEquals("[[3, 3], [8, 12]]",
+            Arrays.deepToString(ml.getFromRanges().toArray()));
+  }
+
 }
index 70e59c5..e2e5594 100644 (file)
@@ -64,7 +64,7 @@ public class TestAlignSeq
     s2 = new Sequence("Seq2", "ASDFA");
     s2.setStart(5);
     s2.setEnd(9);
-    s3 = new Sequence("Seq1", "SDFAQQQSSS");
+    s3 = new Sequence("Seq3", "SDFAQQQSSS");
 
   }
 
@@ -125,10 +125,10 @@ public class TestAlignSeq
     };
 
     as.printAlignment(ps);
-    String expected = "Score = 320.0\nLength of alignment = 10\nSequence Seq1 :  3 - 18 (Sequence length = 14)\nSequence Seq1 :  1 - 10 (Sequence length = 10)\n\n"
-            + "Seq1 SDFAQQQRRR\n"
-            + "     |||||||   \n"
-            + "Seq1 SDFAQQQSSS\n\n" + "Percentage ID = 70.00\n";
+    String expected = "Score = 320.0\nLength of alignment = 10\nSequence Seq1/4-13 (Sequence length = 14)\nSequence Seq3/1-10 (Sequence length = 10)\n\n"
+            + "Seq1/4-13 SDFAQQQRRR\n"
+            + "          |||||||   \n"
+            + "Seq3/1-10 SDFAQQQSSS\n\n" + "Percentage ID = 70.00\n\n";
     assertEquals(expected, baos.toString());
   }
 }
index 6844072..c0cb09c 100644 (file)
@@ -1672,4 +1672,135 @@ public class SequenceTest
     assertEquals(new Range(8, 13), sq.findPositions(1, 13)); // the lot
     assertEquals(new Range(8, 13), sq.findPositions(1, 99));
   }
+
+  @Test(groups = { "Functional" })
+  public void testFindFeatures_largeEndPos()
+  {
+    /*
+     * imitate a PDB sequence where end is larger than end position
+     */
+    SequenceI sq = new Sequence("test", "-ABC--DEF--", 1, 20);
+    sq.createDatasetSequence();
+  
+    assertTrue(sq.findFeatures(1, 9).isEmpty());
+    // should be no array bounds exception - JAL-2772
+    assertTrue(sq.findFeatures(1, 15).isEmpty());
+  
+    // add feature on BCD
+    SequenceFeature sfBCD = new SequenceFeature("Cath", "desc", 2, 4, 2f,
+            null);
+    sq.addSequenceFeature(sfBCD);
+  
+    // no features in columns 1-2 (-A)
+    List<SequenceFeature> found = sq.findFeatures(1, 2);
+    assertTrue(found.isEmpty());
+  
+    // columns 1-6 (-ABC--) includes BCD
+    found = sq.findFeatures(1, 6);
+    assertEquals(1, found.size());
+    assertTrue(found.contains(sfBCD));
+
+    // columns 10-11 (--) should find nothing
+    found = sq.findFeatures(10, 11);
+    assertEquals(0, found.size());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetName()
+  {
+    SequenceI sq = new Sequence("test", "-ABC---DE-F--");
+    assertEquals("test", sq.getName());
+    assertEquals(1, sq.getStart());
+    assertEquals(6, sq.getEnd());
+
+    sq.setName("testing");
+    assertEquals("testing", sq.getName());
+
+    sq.setName("test/8-10");
+    assertEquals("test", sq.getName());
+    assertEquals(8, sq.getStart());
+    assertEquals(13, sq.getEnd()); // note end is recomputed
+
+    sq.setName("testing/7-99");
+    assertEquals("testing", sq.getName());
+    assertEquals(7, sq.getStart());
+    assertEquals(99, sq.getEnd()); // end may be beyond physical end
+
+    sq.setName("/2-3");
+    assertEquals("", sq.getName());
+    assertEquals(2, sq.getStart());
+    assertEquals(7, sq.getEnd());
+
+    sq.setName("test/"); // invalid
+    assertEquals("test/", sq.getName());
+    assertEquals(2, sq.getStart());
+    assertEquals(7, sq.getEnd());
+
+    sq.setName("test/6-13/7-99");
+    assertEquals("test/6-13", sq.getName());
+    assertEquals(7, sq.getStart());
+    assertEquals(99, sq.getEnd());
+
+    sq.setName("test/0-5"); // 0 is invalid - ignored
+    assertEquals("test/0-5", sq.getName());
+    assertEquals(7, sq.getStart());
+    assertEquals(99, sq.getEnd());
+
+    sq.setName("test/a-5"); // a is invalid - ignored
+    assertEquals("test/a-5", sq.getName());
+    assertEquals(7, sq.getStart());
+    assertEquals(99, sq.getEnd());
+
+    sq.setName("test/6-5"); // start > end is invalid - ignored
+    assertEquals("test/6-5", sq.getName());
+    assertEquals(7, sq.getStart());
+    assertEquals(99, sq.getEnd());
+
+    sq.setName("test/5"); // invalid - ignored
+    assertEquals("test/5", sq.getName());
+    assertEquals(7, sq.getStart());
+    assertEquals(99, sq.getEnd());
+
+    sq.setName("test/-5"); // invalid - ignored
+    assertEquals("test/-5", sq.getName());
+    assertEquals(7, sq.getStart());
+    assertEquals(99, sq.getEnd());
+
+    sq.setName("test/5-"); // invalid - ignored
+    assertEquals("test/5-", sq.getName());
+    assertEquals(7, sq.getStart());
+    assertEquals(99, sq.getEnd());
+
+    sq.setName("test/5-6-7"); // invalid - ignored
+    assertEquals("test/5-6-7", sq.getName());
+    assertEquals(7, sq.getStart());
+    assertEquals(99, sq.getEnd());
+
+    sq.setName(null); // invalid, gets converted to space
+    assertEquals("", sq.getName());
+    assertEquals(7, sq.getStart());
+    assertEquals(99, sq.getEnd());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testCheckValidRange()
+  {
+    Sequence sq = new Sequence("test/7-12", "-ABC---DE-F--");
+    assertEquals(7, sq.getStart());
+    assertEquals(12, sq.getEnd());
+
+    /*
+     * checkValidRange ensures end is at least the last residue position
+     */
+    PA.setValue(sq, "end", 2);
+    sq.checkValidRange();
+    assertEquals(12, sq.getEnd());
+
+    /*
+     * end may be beyond the last residue position
+     */
+    PA.setValue(sq, "end", 22);
+    sq.checkValidRange();
+    assertEquals(22, sq.getEnd());
+  }
 }
index a8c491c..5920b89 100644 (file)
@@ -296,4 +296,28 @@ public class EnsemblGeneTest
     assertEquals(-1, fc.compare("coding_exon", "feature_variant"));
     assertEquals(1f, fc.getTransparency());
   }
+
+  @Test(groups = "Network")
+  public void testGetGeneIds()
+  {
+    /*
+     * ENSG00000158828 gene id PINK1 human
+     * ENST00000321556 transcript for the same gene - should not be duplicated
+     * P30419 Uniprot identifier for ENSG00000136448
+     * ENST00000592782 transcript for Uniprot gene - should not be duplicated
+     * BRAF - gene name resolvabe (at time of writing) for 6 model species
+     */
+    String ids = "ENSG00000158828 ENST00000321556 P30419 ENST00000592782 BRAF";
+    EnsemblGene testee = new EnsemblGene();
+    List<String> geneIds = testee.getGeneIds(ids);
+    assertEquals(8, geneIds.size());
+    assertTrue(geneIds.contains("ENSG00000158828"));
+    assertTrue(geneIds.contains("ENSG00000136448"));
+    assertTrue(geneIds.contains("ENSG00000157764")); // BRAF human
+    assertTrue(geneIds.contains("ENSMUSG00000002413")); // mouse
+    assertTrue(geneIds.contains("ENSRNOG00000010957")); // rat
+    assertTrue(geneIds.contains("ENSXETG00000004845")); // xenopus
+    assertTrue(geneIds.contains("ENSDARG00000017661")); // zebrafish
+    assertTrue(geneIds.contains("ENSGALG00000012865")); // chicken
+  }
 }
index aa2c315..e2af26b 100644 (file)
@@ -191,34 +191,6 @@ public class EnsemblSeqProxyTest
 
   }
 
-  @Test(groups = "Functional")
-  public void testIsTranscriptIdentifier()
-  {
-    EnsemblSeqProxy testee = new EnsemblGene();
-    assertFalse(testee.isTranscriptIdentifier(null));
-    assertFalse(testee.isTranscriptIdentifier(""));
-    assertFalse(testee.isTranscriptIdentifier("ENSG00000012345"));
-    assertTrue(testee.isTranscriptIdentifier("ENST00000012345"));
-    assertTrue(testee.isTranscriptIdentifier("ENSMUST00000012345"));
-    assertFalse(testee.isTranscriptIdentifier("enst00000012345"));
-    assertFalse(testee.isTranscriptIdentifier("ENST000000123456"));
-    assertFalse(testee.isTranscriptIdentifier("ENST0000001234"));
-  }
-
-  @Test(groups = "Functional")
-  public void testIsGeneIdentifier()
-  {
-    EnsemblSeqProxy testee = new EnsemblGene();
-    assertFalse(testee.isGeneIdentifier(null));
-    assertFalse(testee.isGeneIdentifier(""));
-    assertFalse(testee.isGeneIdentifier("ENST00000012345"));
-    assertTrue(testee.isGeneIdentifier("ENSG00000012345"));
-    assertTrue(testee.isGeneIdentifier("ENSMUSG00000012345"));
-    assertFalse(testee.isGeneIdentifier("ensg00000012345"));
-    assertFalse(testee.isGeneIdentifier("ENSG000000123456"));
-    assertFalse(testee.isGeneIdentifier("ENSG0000001234"));
-  }
-
   /**
    * Test the method that appends a single allele's reverse complement to a
    * string buffer
index c9e1cad..63d5e4e 100644 (file)
@@ -29,6 +29,11 @@ public class AtomSpecModelTest
     assertEquals(model.getAtomSpec(), "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
     model.addRange(0, 3, 10, "C"); // subsumes 5-9
     assertEquals(model.getAtomSpec(), "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B");
+    model.addRange(5, 25, 35, " "); // empty chain code - e.g. from homology
+                                    // modelling
+    assertEquals(model.getAtomSpec(),
+            "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B|#5:25-35.");
+
   }
 
 }
index b228ba1..2819dbf 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.gui;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotEquals;
 
 import jalview.bin.Cache;
 import jalview.bin.Jalview;
@@ -218,4 +219,31 @@ public class AlignmentPanelTest
             .getAlignment().getWidth() - 1 - 21); // 21 is the number of hidden
                                                   // columns
   }
+
+  /**
+   * Test that update layout reverts to original (unwrapped) values for endRes
+   * and endSeq when switching from wrapped to unwrapped mode (JAL-2739)
+   */
+  @Test(groups = "Functional")
+  public void TestUpdateLayout_endRes()
+  {
+    // get details of original alignment dimensions
+    ViewportRanges ranges = af.getViewport().getRanges();
+    int endres = ranges.getEndRes();
+
+    // wrap
+    af.alignPanel.getAlignViewport().setWrapAlignment(true);
+    af.alignPanel.updateLayout();
+
+    // endRes changes
+    assertNotEquals(ranges.getEndRes(), endres);
+
+    // unwrap
+    af.alignPanel.getAlignViewport().setWrapAlignment(false);
+    af.alignPanel.updateLayout();
+
+    // endRes and endSeq back to original values
+    assertEquals(ranges.getEndRes(), endres);
+
+  }
 }
diff --git a/test/jalview/gui/FreeUpMemoryTest.java b/test/jalview/gui/FreeUpMemoryTest.java
new file mode 100644 (file)
index 0000000..e93bfac
--- /dev/null
@@ -0,0 +1,216 @@
+package jalview.gui;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import jalview.analysis.AlignmentGenerator;
+import jalview.bin.Cache;
+import jalview.bin.Jalview;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceGroup;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class FreeUpMemoryTest
+{
+  private static final int ONE_MB = 1000 * 1000;
+
+  /**
+   * Configure (read-only) Jalview property settings for test
+   */
+  @BeforeClass(alwaysRun = true)
+  public void setUp()
+  {
+    Jalview.main(new String[] { "-nonews", "-props",
+        "test/jalview/testProps.jvprops" });
+    Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS",
+            Boolean.TRUE.toString());
+    Cache.applicationProperties.setProperty("SHOW_QUALITY",
+            Boolean.TRUE.toString());
+    Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
+            Boolean.TRUE.toString());
+    Cache.applicationProperties.setProperty("SHOW_OCCUPANCY",
+            Boolean.TRUE.toString());
+    Cache.applicationProperties.setProperty("SHOW_IDENTITY",
+            Boolean.TRUE.toString());
+  }
+
+  /**
+   * A simple test that memory is released when all windows are closed.
+   * <ul>
+   * <li>generates a reasonably large alignment and loads it</li>
+   * <li>performs various operations on the alignment</li>
+   * <li>closes all windows</li>
+   * <li>requests garbage collection</li>
+   * <li>asserts that the remaining memory footprint (heap usage) is 'not large'
+   * </li>
+   * </ul>
+   * If the test fails, this suggests that a reference to some large object
+   * (perhaps the alignment data, or some annotation / Tree / PCA data) has
+   * failed to be garbage collected. If this is the case, the heap will need to
+   * be inspected manually (suggest using jvisualvm) in order to track down
+   * where large objects are still referenced. The code (for example
+   * AlignmentViewport.dispose()) should then be updated to ensure references to
+   * large objects are set to null when they are no longer required.
+   * 
+   * @throws IOException
+   */
+  @Test(groups = "Memory")
+  public void testFreeMemoryOnClose() throws IOException
+  {
+    File f = generateAlignment();
+    f.deleteOnExit();
+
+    doStuffInJalview(f);
+
+    Desktop.instance.closeAll_actionPerformed(null);
+
+    checkUsedMemory(35L);
+  }
+
+  /**
+   * Requests garbage collection and then checks whether remaining memory in use
+   * is less than the expected value (in Megabytes)
+   * 
+   * @param expectedMax
+   */
+  protected void checkUsedMemory(long expectedMax)
+  {
+    /*
+     * request garbage collection and wait briefly for it to run;
+     * NB there is no guarantee when, or whether, it will do so
+     */
+    System.gc();
+    waitFor(100);
+
+    /*
+     * a second gc() call should not be necessary - but it is!
+     * the test passes with it, and fails without it
+     */
+    System.gc();
+    waitFor(100);
+
+    /*
+     * check used memory is 'reasonably low'
+     */
+    long availableMemory = Runtime.getRuntime().totalMemory() / ONE_MB;
+    long freeMemory = Runtime.getRuntime().freeMemory() / ONE_MB;
+    long usedMemory = availableMemory - freeMemory;
+
+    /*
+     * sanity check - fails if any frame was added after
+     * closeAll_actionPerformed
+     */
+    assertEquals(Desktop.instance.getAllFrames().length, 0);
+
+    /*
+     * if this assertion fails
+     * - set a breakpoint here
+     * - run jvisualvm to inspect a heap dump of Jalview
+     * - identify large objects in the heap and their referers
+     * - fix code as necessary to null the references on close
+     */
+    System.out.println("Used memory after gc = " + usedMemory + "MB");
+    assertTrue(usedMemory < expectedMax, String.format(
+            "Used memory %d should be less than %d (Recommend running test manually to verify)",
+            usedMemory,
+            expectedMax));
+  }
+
+  /**
+   * Loads an alignment from file and exercises various operations in Jalview
+   * 
+   * @param f
+   */
+  protected void doStuffInJalview(File f)
+  {
+    /*
+     * load alignment, wait for consensus and other threads to complete
+     */
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(f.getPath(),
+            DataSourceType.FILE);
+    while (af.getViewport().isCalcInProgress())
+    {
+      waitFor(200);
+    }
+
+    /*
+     * set a selection group - potential memory leak if it retains
+     * a reference to the alignment
+     */
+    SequenceGroup sg = new SequenceGroup();
+    sg.setStartRes(0);
+    sg.setEndRes(100);
+    AlignmentI al = af.viewport.getAlignment();
+    for (int i = 0; i < al.getHeight(); i++)
+    {
+      sg.addSequence(al.getSequenceAt(i), false);
+    }
+    af.viewport.setSelectionGroup(sg);
+
+    /*
+     * compute Tree and PCA (on all sequences, 100 columns)
+     */
+    af.openTreePcaDialog();
+    CalculationChooser dialog = af.alignPanel.getCalculationDialog();
+    dialog.openPcaPanel("BLOSUM62", dialog.getSimilarityParameters(true));
+    dialog.openTreePanel("BLOSUM62", dialog.getSimilarityParameters(false));
+
+    /*
+     * wait until Tree and PCA have been computed
+     */
+    while (af.viewport.getCurrentTree() == null
+            && dialog.getPcaPanel().isWorking())
+    {
+      waitFor(10);
+    }
+
+    /*
+     * give Swing time to add the PCA panel (?!?)
+     */
+    waitFor(100);
+  }
+
+  /**
+   * Wait for waitMs miliseconds
+   * 
+   * @param waitMs
+   */
+  protected void waitFor(int waitMs)
+  {
+    try
+    {
+      Thread.sleep(waitMs);
+    } catch (InterruptedException e)
+    {
+    }
+  }
+
+  /**
+   * Generates an alignment and saves it in a temporary file, to be loaded by
+   * Jalview. We use a peptide alignment (so Conservation and Quality are
+   * calculated), which is wide enough to ensure Consensus, Conservation and
+   * Occupancy have a significant memory footprint (if not removed from the
+   * heap).
+   * 
+   * @return
+   * @throws IOException
+   */
+  private File generateAlignment() throws IOException
+  {
+    File f = File.createTempFile("MemoryTest", "fa");
+    PrintStream ps = new PrintStream(f);
+    AlignmentGenerator ag = new AlignmentGenerator(false, ps);
+    int width = 100000;
+    int height = 100;
+    ag.generate(width, height, 0, 10, 15);
+    return f;
+  }
+}
diff --git a/test/jalview/gui/PairwiseAlignmentPanelTest.java b/test/jalview/gui/PairwiseAlignmentPanelTest.java
new file mode 100644 (file)
index 0000000..3322ee8
--- /dev/null
@@ -0,0 +1,73 @@
+package jalview.gui;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceGroup;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+
+import javax.swing.JTextArea;
+
+import junit.extensions.PA;
+
+import org.testng.annotations.Test;
+
+public class PairwiseAlignmentPanelTest
+{
+  @Test(groups = "Functional")
+  public void testConstructor_withSelectionGroup()
+  {
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/uniref50.fa", DataSourceType.FILE);
+    AlignViewport viewport = af.getViewport();
+    AlignmentI al = viewport.getAlignment();
+
+    /*
+     * select columns 29-36 of sequences 4 and 5 for alignment
+     * Q93XJ9_SOLTU/23-29 L-KAISNV
+     * FER1_PEA/26-32     V-TTTKAF
+     */
+    SequenceGroup sg = new SequenceGroup();
+    sg.addSequence(al.getSequenceAt(3), false);
+    sg.addSequence(al.getSequenceAt(4), false);
+    sg.setStartRes(28);
+    sg.setEndRes(35);
+    viewport.setSelectionGroup(sg);
+
+    PairwiseAlignPanel testee = new PairwiseAlignPanel(viewport);
+
+    String text = ((JTextArea) PA.getValue(testee, "textarea")).getText();
+    String expected = "Score = 80.0\n" + "Length of alignment = 4\n"
+            + "Sequence     FER1_PEA/29-32 (Sequence length = 7)\n"
+            + "Sequence Q93XJ9_SOLTU/23-26 (Sequence length = 7)\n\n"
+            + "    FER1_PEA/29-32 TKAF\n" + "                    ||.\n"
+            + "Q93XJ9_SOLTU/23-26 LKAI\n\n" + "Percentage ID = 50.00\n\n";
+    assertEquals(text, expected);
+  }
+
+  /**
+   * This test aligns the same sequences as testConstructor_withSelectionGroup
+   * but as a complete alignment (no selection). Note that in fact the user is
+   * currently required to make a selection in order to calculate pairwise
+   * alignments, so this case does not arise.
+   */
+  @Test(groups = "Functional")
+  public void testConstructor_noSelectionGroup()
+  {
+    String seqs = ">Q93XJ9_SOLTU/23-29\nL-KAISNV\n>FER1_PEA/26-32\nV-TTTKAF\n";
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqs,
+            DataSourceType.PASTE);
+    AlignViewport viewport = af.getViewport();
+
+    PairwiseAlignPanel testee = new PairwiseAlignPanel(viewport);
+
+    String text = ((JTextArea) PA.getValue(testee, "textarea")).getText();
+    String expected = "Score = 80.0\n" + "Length of alignment = 4\n"
+            + "Sequence     FER1_PEA/29-32 (Sequence length = 7)\n"
+            + "Sequence Q93XJ9_SOLTU/23-26 (Sequence length = 7)\n\n"
+            + "    FER1_PEA/29-32 TKAF\n" + "                    ||.\n"
+            + "Q93XJ9_SOLTU/23-26 LKAI\n\n" + "Percentage ID = 50.00\n\n";
+    assertEquals(text, expected);
+  }
+}
index a1715e9..72a288b 100644 (file)
@@ -29,6 +29,7 @@ import java.awt.GridLayout;
 
 import javax.swing.JLabel;
 import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
 
 import org.testng.Assert;
 import org.testng.annotations.BeforeClass;
@@ -119,8 +120,15 @@ public class ProgressBarTest
    * @param layout
    * @param msgs
    */
-  private void verifyProgress(GridLayout layout, String[] msgs)
+  private void verifyProgress(final GridLayout layout, final String[] msgs)
   {
+    try
+    {
+    SwingUtilities.invokeAndWait(new Runnable()
+    {
+      @Override
+      public void run()
+      {
     int msgCount = msgs.length;
     assertEquals(1 + msgCount, layout.getRows());
     assertEquals(msgCount, statusPanel.getComponentCount());
@@ -132,5 +140,13 @@ public class ProgressBarTest
       assertEquals(msgs[i++],
               ((JLabel) ((JPanel) c).getComponent(0)).getText());
     }
+      }
+    });
+    } catch (Exception e)
+    {
+      throw new AssertionError(
+              "Unexpected exception waiting for progress bar validation",
+              e);
+    }
   }
 }
diff --git a/test/jalview/gui/SeqCanvasTest.java b/test/jalview/gui/SeqCanvasTest.java
new file mode 100644 (file)
index 0000000..a27bc3f
--- /dev/null
@@ -0,0 +1,283 @@
+package jalview.gui;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.datamodel.AlignmentI;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+
+import junit.extensions.PA;
+
+import org.testng.annotations.Test;
+
+import sun.swing.SwingUtilities2;
+
+public class SeqCanvasTest
+{
+  /**
+   * Test the method that computes wrapped width in residues, height of wrapped
+   * widths in pixels, and the number of widths visible
+   */
+  @Test(groups = "Functional")
+  public void testCalculateWrappedGeometry_noAnnotations()
+  {
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/uniref50.fa", DataSourceType.FILE);
+    AlignViewport av = af.getViewport();
+    AlignmentI al = av.getAlignment();
+    assertEquals(al.getWidth(), 157);
+    assertEquals(al.getHeight(), 15);
+
+    av.setWrapAlignment(true);
+    av.getRanges().setStartEndSeq(0, 14);
+    av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
+    int charHeight = av.getCharHeight();
+    int charWidth = av.getCharWidth();
+    assertEquals(charHeight, 17);
+    assertEquals(charWidth, 12);
+
+    SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
+
+    /*
+     * first with scales above, left, right
+     */
+    av.setShowAnnotation(false);
+    av.setScaleAboveWrapped(true);
+    av.setScaleLeftWrapped(true);
+    av.setScaleRightWrapped(true);
+    FontMetrics fm = SwingUtilities2.getFontMetrics(testee, av.getFont());
+    int labelWidth = fm.stringWidth("000") + charWidth;
+    assertEquals(labelWidth, 39); // 3 x 9 + charWidth
+
+    /*
+     * width 400 pixels leaves (400 - 2*labelWidth) for residue columns
+     * take the whole multiple of character widths
+     */
+    int canvasWidth = 400;
+    int canvasHeight = 300;
+    int residueColumns = (canvasWidth - 2 * labelWidth) / charWidth;
+    int wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+    assertEquals(wrappedWidth, residueColumns);
+    assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
+    assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
+    assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
+            2 * charHeight);
+    int repeatingHeight = (int) PA.getValue(testee, "wrappedRepeatHeightPx");
+    assertEquals(repeatingHeight, charHeight * (2 + al.getHeight()));
+    assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
+
+    /*
+     * repeat height is 17 * (2 + 15) = 289
+     * make canvas height 2 * 289 + 3 * charHeight so just enough to
+     * draw 2 widths and the first sequence of a third
+     */
+    canvasHeight = charHeight * (17 * 2 + 3);
+    testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+    assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
+
+    /*
+     * reduce canvas height by 1 pixel - should not be enough height
+     * to draw 3 widths
+     */
+    canvasHeight -= 1;
+    testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+    assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
+
+    /*
+     * turn off scale above - can now fit in 2 and a bit widths
+     */
+    av.setScaleAboveWrapped(false);
+    testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+    assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
+
+    /*
+     * reduce height to enough for 2 widths and not quite a third
+     * i.e. two repeating heights + spacer + sequence - 1 pixel
+     */
+    canvasHeight = charHeight * (16 * 2 + 2) - 1;
+    testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+    assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
+
+    /*
+     * make canvas width enough for scales and 20 residues
+     */
+    canvasWidth = 2 * labelWidth + 20 * charWidth;
+    wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+            canvasHeight);
+    assertEquals(wrappedWidth, 20);
+
+    /*
+     * reduce width by 1 pixel - rounds down to 19 residues
+     */
+    canvasWidth -= 1;
+    wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+            canvasHeight);
+    assertEquals(wrappedWidth, 19);
+
+    /*
+     * turn off West scale - adds labelWidth (39) to available for residues
+     * which with the 11 remainder makes 50 which is 4 more charWidths rem 2
+     */
+    av.setScaleLeftWrapped(false);
+    wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+            canvasHeight);
+    assertEquals(wrappedWidth, 23);
+
+    /*
+     * add 10 pixels to width to fit in another whole residue column
+     */
+    canvasWidth += 9;
+    wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+            canvasHeight);
+    assertEquals(wrappedWidth, 23);
+    canvasWidth += 1;
+    wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+            canvasHeight);
+    assertEquals(wrappedWidth, 24);
+
+    /*
+     * turn off East scale to gain 39 more pixels (3 columns remainder 3)
+     */
+    av.setScaleRightWrapped(false);
+    wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+            canvasHeight);
+    assertEquals(wrappedWidth, 27);
+
+    /*
+     * add 9 pixels to width to gain a residue column
+     */
+    canvasWidth += 8;
+    wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+            canvasHeight);
+    assertEquals(wrappedWidth, 27);
+    canvasWidth += 1;
+    wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+            canvasHeight);
+    assertEquals(wrappedWidth, 28);
+
+    /*
+     * now West but not East scale - lose 39 pixels or 4 columns
+     */
+    av.setScaleLeftWrapped(true);
+    wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+            canvasHeight);
+    assertEquals(wrappedWidth, 24);
+
+    /*
+     * adding 3 pixels to width regains one column
+     */
+    canvasWidth += 2;
+    wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+            canvasHeight);
+    assertEquals(wrappedWidth, 24);
+    canvasWidth += 1;
+    wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+            canvasHeight);
+    assertEquals(wrappedWidth, 25);
+
+    /*
+     * turn off scales left and right, make width exactly 157 columns
+     */
+    av.setScaleLeftWrapped(false);
+    canvasWidth = al.getWidth() * charWidth;
+    testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+    assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
+  }
+
+  /**
+   * Test the method that computes wrapped width in residues, height of wrapped
+   * widths in pixels, and the number of widths visible
+   */
+  @Test(groups = "Functional")
+  public void testCalculateWrappedGeometry_withAnnotations()
+  {
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/uniref50.fa", DataSourceType.FILE);
+    AlignViewport av = af.getViewport();
+    AlignmentI al = av.getAlignment();
+    assertEquals(al.getWidth(), 157);
+    assertEquals(al.getHeight(), 15);
+  
+    av.setWrapAlignment(true);
+    av.getRanges().setStartEndSeq(0, 14);
+    av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
+    int charHeight = av.getCharHeight();
+    int charWidth = av.getCharWidth();
+    assertEquals(charHeight, 17);
+    assertEquals(charWidth, 12);
+  
+    SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
+  
+    /*
+     * first with scales above, left, right
+     */
+    av.setShowAnnotation(true);
+    av.setScaleAboveWrapped(true);
+    av.setScaleLeftWrapped(true);
+    av.setScaleRightWrapped(true);
+    FontMetrics fm = SwingUtilities2.getFontMetrics(testee, av.getFont());
+    int labelWidth = fm.stringWidth("000") + charWidth;
+    assertEquals(labelWidth, 39); // 3 x 9 + charWidth
+    int annotationHeight = testee.getAnnotationHeight();
+
+    /*
+     * width 400 pixels leaves (400 - 2*labelWidth) for residue columns
+     * take the whole multiple of character widths
+     */
+    int canvasWidth = 400;
+    int canvasHeight = 300;
+    int residueColumns = (canvasWidth - 2 * labelWidth) / charWidth;
+    int wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+    assertEquals(wrappedWidth, residueColumns);
+    assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
+    assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
+    assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
+            2 * charHeight);
+    int repeatingHeight = (int) PA.getValue(testee, "wrappedRepeatHeightPx");
+    assertEquals(repeatingHeight, charHeight * (2 + al.getHeight())
+            + annotationHeight);
+    assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
+  
+    /*
+     * repeat height is 17 * (2 + 15) = 289 + annotationHeight = 507
+     * make canvas height 2 * 289 + 3 * charHeight so just enough to
+     * draw 2 widths and the first sequence of a third
+     */
+    canvasHeight = charHeight * (17 * 2 + 3) + 2 * annotationHeight;
+    testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+    assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
+  
+    /*
+     * reduce canvas height by 1 pixel - should not be enough height
+     * to draw 3 widths
+     */
+    canvasHeight -= 1;
+    testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+    assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
+  
+    /*
+     * turn off scale above - can now fit in 2 and a bit widths
+     */
+    av.setScaleAboveWrapped(false);
+    testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+    assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
+  
+    /*
+     * reduce height to enough for 2 widths and not quite a third
+     * i.e. two repeating heights + spacer + sequence - 1 pixel
+     */
+    canvasHeight = charHeight * (16 * 2 + 2) + 2 * annotationHeight - 1;
+    testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+    assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
+
+    /*
+     * add 1 pixel to height - should now get 3 widths drawn
+     */
+    canvasHeight += 1;
+    testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+    assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
+  }
+}
index cf1039f..0af67cd 100644 (file)
@@ -26,11 +26,11 @@ public class ScaleRendererTest
     AlignViewport av = af.getViewport();
 
     /*
-     * scale has minor ticks at 5 and 15, major at 10 and 20
+     * scale has minor ticks at 5, 15, 25, major at 10 and 20
      * (these are base 1, ScaleMark holds base 0 values)
      */
     List<ScaleMark> marks = new ScaleRenderer().calculateMarks(av, 0, 25);
-    assertEquals(marks.size(), 4);
+    assertEquals(marks.size(), 5);
 
     assertFalse(marks.get(0).major);
     assertEquals(marks.get(0).column, 4);
@@ -48,6 +48,10 @@ public class ScaleRendererTest
     assertEquals(marks.get(3).column, 19);
     assertEquals(marks.get(3).text, "20");
 
+    assertFalse(marks.get(4).major);
+    assertEquals(marks.get(4).column, 24);
+    assertNull(marks.get(4).text);
+
     /*
      * now hide columns 9-11 and 18-20 (base 1)
      * scale marks are now in the same columns as before, but
@@ -56,7 +60,7 @@ public class ScaleRendererTest
     av.hideColumns(8, 10);
     av.hideColumns(17, 19);
     marks = new ScaleRenderer().calculateMarks(av, 0, 25);
-    assertEquals(marks.size(), 4);
+    assertEquals(marks.size(), 5);
     assertFalse(marks.get(0).major);
     assertEquals(marks.get(0).column, 4);
     assertNull(marks.get(0).text);
@@ -69,5 +73,8 @@ public class ScaleRendererTest
     assertTrue(marks.get(3).major);
     assertEquals(marks.get(3).column, 19);
     assertEquals(marks.get(3).text, "26"); // +6 hidden columns
+    assertFalse(marks.get(4).major);
+    assertEquals(marks.get(4).column, 24);
+    assertNull(marks.get(4).text);
   }
 }
index 7fd7abc..f6dfed6 100644 (file)
@@ -2,6 +2,7 @@ package jalview.renderer.seqfeatures;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
@@ -285,6 +286,28 @@ public class FeatureColourFinderTest
   }
 
   @Test(groups = "Functional")
+  public void testFindFeatureAtEnd()
+  {
+    /*
+     * terminal residue feature
+     */
+    seq.addSequenceFeature(new SequenceFeature("PDBRESNUM", "pdb res 1",
+            seq.getEnd(), seq.getEnd(), Float.NaN, "1seq.pdb"));
+    fr.setColour("PDBRESNUM", new FeatureColour(Color.red));
+    fr.featuresAdded();
+    av.setShowSequenceFeatures(true);
+
+    /*
+     * final column should have PDBRESNUM feature, the others not
+     */
+    Color c = finder.findFeatureColour(Color.blue, seq,
+            seq.getLength() - 2);
+    assertNotEquals(c, Color.red);
+    c = finder.findFeatureColour(Color.blue, seq, seq.getLength() - 1);
+    assertEquals(c, Color.red);
+  }
+
+  @Test(groups = "Functional")
   public void testFindFeatureColour_graduatedFeatureColour()
   {
     seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 2,
index aea3687..af02d5e 100644 (file)
@@ -275,11 +275,11 @@ public class AAStructureBindingModelTest
     StructureSelectionManager ssm = new StructureSelectionManager();
 
     ssm.setMapping(new SequenceI[] { seq1a, seq1b }, null, PDB_1,
-            DataSourceType.PASTE);
+            DataSourceType.PASTE, null);
     ssm.setMapping(new SequenceI[] { seq2 }, null, PDB_2,
-            DataSourceType.PASTE);
+            DataSourceType.PASTE, null);
     ssm.setMapping(new SequenceI[] { seq3 }, null, PDB_3,
-            DataSourceType.PASTE);
+            DataSourceType.PASTE, null);
 
     testee = new AAStructureBindingModel(ssm, pdbFiles, seqs, null)
     {
index d0ec3e8..5226819 100644 (file)
@@ -1149,4 +1149,49 @@ public class MappingUtilsTest
     assertEquals("[12, 11, 8, 4]", Arrays.toString(ranges));
   }
 
+  @Test(groups = "Functional")
+  public void testRemoveEndPositions()
+  {
+    List<int[]> ranges = new ArrayList<>();
+
+    /*
+     * case 1: truncate last range
+     */
+    ranges.add(new int[] { 1, 10 });
+    ranges.add(new int[] { 20, 30 });
+    MappingUtils.removeEndPositions(5, ranges);
+    assertEquals(2, ranges.size());
+    assertEquals(25, ranges.get(1)[1]);
+
+    /*
+     * case 2: remove last range
+     */
+    ranges.clear();
+    ranges.add(new int[] { 1, 10 });
+    ranges.add(new int[] { 20, 22 });
+    MappingUtils.removeEndPositions(3, ranges);
+    assertEquals(1, ranges.size());
+    assertEquals(10, ranges.get(0)[1]);
+
+    /*
+     * case 3: truncate penultimate range
+     */
+    ranges.clear();
+    ranges.add(new int[] { 1, 10 });
+    ranges.add(new int[] { 20, 21 });
+    MappingUtils.removeEndPositions(3, ranges);
+    assertEquals(1, ranges.size());
+    assertEquals(9, ranges.get(0)[1]);
+
+    /*
+     * case 4: remove last two ranges
+     */
+    ranges.clear();
+    ranges.add(new int[] { 1, 10 });
+    ranges.add(new int[] { 20, 20 });
+    ranges.add(new int[] { 30, 30 });
+    MappingUtils.removeEndPositions(3, ranges);
+    assertEquals(1, ranges.size());
+    assertEquals(9, ranges.get(0)[1]);
+  }
 }
index 98b1217..af2424d 100644 (file)
@@ -793,6 +793,66 @@ public class ViewportRangesTest {
       }
     }
   }
+
+  @Test(groups = { "Functional" })
+  public void testScrollUp_wrapped()
+  {
+    /*
+     * alignment 30 tall and 45 wide
+     */
+    AlignmentI al2 = gen.generate(45, 30, 1, 0, 5);
+
+    /*
+     * wrapped view, 5 sequences high, start at sequence offset 1
+     */
+    ViewportRanges vr = new ViewportRanges(al2);
+    vr.setWrappedMode(true);
+    vr.setViewportStartAndHeight(1, 5);
+
+    /*
+     * offset wrapped view to column 3
+     */
+    vr.setStartEndRes(3, 22);
+
+    int startRes = vr.getStartRes();
+    int width = vr.getViewportWidth();
+    assertEquals(startRes, 3);
+    assertEquals(width, 20);
+
+    // in wrapped mode, we change startRes but not startSeq
+    // scroll down:
+    vr.scrollUp(false);
+    assertEquals(vr.getStartSeq(), 1);
+    assertEquals(vr.getStartRes(), 23);
+
+    // scroll up returns to original position
+    vr.scrollUp(true);
+    assertEquals(vr.getStartSeq(), 1);
+    assertEquals(vr.getStartRes(), 3);
+
+    // scroll up again returns to 'origin'
+    vr.scrollUp(true);
+    assertEquals(vr.getStartSeq(), 1);
+    assertEquals(vr.getStartRes(), 0);
+
+    /*
+     * offset 3 columns once more and do some scroll downs
+     */
+    vr.setStartEndRes(3, 22);
+    vr.scrollUp(false);
+    assertEquals(vr.getStartSeq(), 1);
+    assertEquals(vr.getStartRes(), 23);
+    vr.scrollUp(false);
+    assertEquals(vr.getStartSeq(), 1);
+    assertEquals(vr.getStartRes(), 43);
+
+    /*
+     * scroll down beyond end of alignment does nothing
+     */
+    vr.scrollUp(false);
+    assertEquals(vr.getStartSeq(), 1);
+    assertEquals(vr.getStartRes(), 43);
+  }
 }
 
 // mock listener for property change events
index ac9e260..122b8d0 100644 (file)
     <!-- 
        Suppress check of externally sourced code 
     --> 
-    <suppress checks="[a-zA-Z0-9]*" files="com[\\/]*"/>
-    <suppress checks="[a-zA-Z0-9]*" files="ext[\\/]*"/>
-    <suppress checks="[a-zA-Z0-9]*" files="org[\\/]*"/>
-    <suppress checks="[a-zA-Z0-9]*" files="uk[\\/]*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="[\\/]com[\\/]github*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="[\\/]com[\\/]stevesoft*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="[\\/]ext[\\/]edu*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="[\\/]ext[\\/]vamsas*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="[\\/]org[\\/]jibble*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="[\\/]uk[\\/]ac*"/>
     
     <!-- 
        ImportControl can only handle one top level package
index 946f71c..c47aaec 100644 (file)
                <subpackage name="datamodel">
                <disallow pkg="jalview.gui"/>
                <allow pkg="fr.orsay.lri.varna"/>
-                       <subpackage name="xdb">
-                               <subpackage name="embl">
-                               <allow pkg="org.exolab.castor"/>
-                           </subpackage>
+                       <subpackage name="xdb.embl">
+                       <allow pkg="org.exolab.castor"/>
                    </subpackage>
            </subpackage>
                
+               <subpackage name="ext">
+                       <subpackage name="ensembl">
+                       <allow pkg="javax.ws"/>
+                       <allow pkg="org.json"/>
+                       </subpackage>
+                       <subpackage name="htsjdk">
+                       <allow pkg="htsjdk"/>
+                       </subpackage>
+                       <subpackage name="jmol">
+                       <allow pkg="MCview"/>
+                       <allow pkg="org.jmol"/>
+                       </subpackage>
+                       <subpackage name="paradise">
+                       <allow pkg="org.apache"/>
+                       <allow pkg="org.json"/>
+                       </subpackage>
+                       <subpackage name="rbvi">
+                       <allow pkg="ext.edu.ucsf"/>
+                       <allow pkg="javax.servlet"/>
+                       </subpackage>
+                       <subpackage name="so">
+                       <allow pkg="org.biojava"/>
+                       </subpackage>
+                       <subpackage name="varna">
+                       <allow pkg="fr.orsay"/>
+                       </subpackage>
+           </subpackage>
+               
                <subpackage name="fts">
                <allow pkg="javax.swing"/>
                <allow pkg="javax.ws"/>
                </subpackage>
 
                <subpackage name="schemes">
-                       <allow pkg="org.exolab.castor"/>
+                       <allow pkg="org.exolab.castor" class="jalview.schemes.ColourSchemeLoader"/>
                </subpackage>
 
                <subpackage name="structure">