Merge branch 'develop' into features/mchmmer
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 8 May 2018 09:33:48 +0000 (10:33 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 8 May 2018 09:33:48 +0000 (10:33 +0100)
47 files changed:
.classpath
THIRDPARTYLIBS
help/help.jhm
help/helpTOC.xml
help/html/features/chimera.html
help/html/features/jmol.html
help/html/features/preferences.html
help/html/features/schooser_enter-id.png
help/html/features/schooser_main.png
help/html/features/structurechooser.html
help/html/features/viewingpdbs.html
help/html/menus/desktopMenu.html
help/html/releases.html
help/html/whatsNew.html
lib/VAqua4.jar [new file with mode: 0644]
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/MCview/PDBChain.java
src/jalview/api/structures/JalviewStructureDisplayI.java
src/jalview/bin/Jalview.java
src/jalview/datamodel/SearchResults.java
src/jalview/ext/jmol/JalviewJmolBinding.java
src/jalview/fts/core/FTSRestClient.java
src/jalview/gui/AnnotationColourChooser.java
src/jalview/gui/AnnotationRowFilter.java
src/jalview/gui/AppJmol.java
src/jalview/gui/ChimeraViewFrame.java
src/jalview/gui/Desktop.java
src/jalview/gui/JDatabaseTree.java
src/jalview/gui/PCAPanel.java
src/jalview/gui/SeqPanel.java
src/jalview/gui/SequenceFetcher.java
src/jalview/gui/StructureChooser.java
src/jalview/gui/StructureViewer.java
src/jalview/gui/StructureViewerBase.java
src/jalview/jbgui/GStructureChooser.java
src/jalview/structure/StructureMapping.java
src/jalview/structure/StructureSelectionManager.java
src/jalview/util/MapList.java
test/MCview/PDBChainTest.java
test/jalview/datamodel/features/FeatureAttributesTest.java
test/jalview/ext/jmol/JmolViewerTest.java
test/jalview/gui/StructureChooserTest.java
test/jalview/io/Jalview2xmlTests.java
test/jalview/structure/StructureMappingTest.java
test/jalview/util/MapListTest.java
utils/InstallAnywhere/Jalview.iap_xml

index f4b8cf8..0cdc4b9 100644 (file)
@@ -48,6 +48,7 @@
        <classpathentry kind="lib" path="lib/VARNAv3-93.jar"/>
        <classpathentry kind="lib" path="lib/jfreesvg-2.1.jar"/>
        <classpathentry kind="lib" path="lib/quaqua-filechooser-only-8.0.jar"/>
+       <classpathentry kind="lib" path="lib/VAqua4.jar"/>
        <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/plugin"/>
        <classpathentry kind="lib" path="lib/xml-apis.jar"/>
        <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
index e0be904..e2baa85 100644 (file)
@@ -49,6 +49,8 @@ jfreesvg-2.1.jar : GPL v3 licensed library from the JFree suite: http://www.jfre
 
 quaqua: v.8.0 (latest stable) by Randel S Hofer. LGPL and BSD Modified license: downloaded from http://www.randelshofer.ch/quaqua/ 
 
+vaqua: v4 (latest stable) by Alan Snyder et al. GPLv2 with Classpathe xception, also includes contributions from Quaqua: ownloaded from http://violetlib.org/vaqua/overview.html
+
 lib/htsjdk-1.120-SNAPSHOT.jar: (currently not required for 2.10) built from maven master at https://github.com/samtools/htsjdk MIT License to Broad Institute
 
 lib/biojava-core-4.1.0.jar LGPLv2.1 - latest license at https://github.com/biojava/biojava/blob/master/LICENSE
index 506b3f3..4ea119c 100755 (executable)
@@ -54,6 +54,7 @@
    <mapID target="pdbmcviewer" url="html/features/pdbviewer.html"/>
    <mapID target="pdbjmol" url="html/features/jmol.html"/>
    <mapID target="chimera" url="html/features/chimera.html"/>
+   <mapID target="chimera.annotxfer" url="html/features/chimera.html#annotxfer"/>
    <mapID target="varna" url="html/features/varna.html"/>
    <mapID target="xsspannotation" url="html/features/xsspannotation.html"/>
    <mapID target="preferences" url="html/features/preferences.html"/>     
index 71b7ef9..ca86625 100755 (executable)
@@ -24,6 +24,8 @@
        <tocitem text="Jalview Documentation" target="home" expand="true">
                        <tocitem text="What's new" target="new" expand="true">
                                <tocitem text="Latest Release Notes" target="release"/>
+                               <tocitem text="Structure Chooser" target="pdbchooser"/>
+                               <tocitem text="Chimera Annotation Exchange" target="chimera.annotxfer"/>
                </tocitem>
                
                <tocitem text="Editing Alignments" target="edit" />
index 68ac465..e1227de 100644 (file)
             structure in the alignment. The regions used to calculate
             the superposition will be highlighted using the 'Cartoon'
             rendering style, and the remaining data shown as a chain
-            trace.<br/><br/>
+            trace.<br />
+          <br />
         </em></li>
-        <li><strong><a name="experimental">EXPERIMENTAL FEATURES</a></strong><br/>
-          <em>
-            These are only available if the <strong>Tools&#8594;Enable
-            Experimental Features</strong> option is enabled. (Since Jalview 2.10.2)</em>
-          <ul>
-            <li><strong>Write Jalview features</strong><br /> <em>Selecting
-                this option will create new residue attributes for any
-                features currently visible in the associated alignment
-                views, allowing those positions to be selected and
-                analysed with via Chimera's 'Render by Attribute' tool
-                (found in the Tools submenu called Structure Analysis).<br />
-                <br />If you use this option, please remember to select
-                the <em>Refresh Menus</em> option in Chimera's Render by
-                Attribute dialog box in order to see the attributes
-                derived from Jalview sequence features.
-            </em><br />
-            <a href="https://issues.jalview.org/browse/JAL-2295">View
-                this function's issue in Jalview's bug tracker</a></li>
-            <li><strong>Fetch Chimera Attributes</strong><br /> <em>This
-                submenu lists available Chimera residue attributes that
-                can be imported as Jalview features on associated
-                sequences.<br />This is particularly useful for
-                transferring quantitative positional annotation. For
-                example, structure similarity for an alignment can be
-                visualised by transferring the local RMSD attributes
-                generated by Chimera's Match->Align tool onto aligned
-                sequences and displayed with a <a
-                href="featureschemes.html">Graduated feature colour
-                  scheme</a>.
-            </em><a href="https://issues.jalview.org/browse/JAL-2296">View
-                this function's issue in Jalview's bug tracker</a></li>
-          </ul></li>
-        <li><strong>Help<br>
+        <li><a name="annotxfer"><strong>Write Jalview
+              features</strong></a><br /> <em>Selecting this option will create
+            new residue attributes for any features currently visible in
+            the associated alignment views, allowing those positions to
+            be selected and analysed with via Chimera's 'Render by
+            Attribute' tool (found in the Tools submenu called Structure
+            Analysis).<br /> <br />If you use this option, please
+            remember to select the <em>Refresh Menus</em> option in
+            Chimera's Render by Attribute dialog box in order to see the
+            attributes derived from Jalview sequence features.
+        </em></li>
+        <li><strong>Fetch Chimera Attributes</strong><br /> <em>This
+            submenu lists available Chimera residue attributes that can
+            be imported as Jalview features on associated sequences.<br />This
+            is particularly useful for transferring quantitative
+            positional annotation. For example, structure similarity for
+            an alignment can be visualised by transferring the local
+            RMSD attributes generated by Chimera's Match->Align tool
+            onto aligned sequences and displayed with a <a
+            href="featureschemes.html">Graduated feature colour
+              scheme</a>. </li>
+      </ul></li>
+    <li><strong>Help<br>
     </strong>
       <ul>
         <li><strong>Chimera Help<br>
index 0cd6168..ac2489b 100644 (file)
 </p> -->
   <p>
     <a name="align"><strong>Superposing structures based on
-        their aligned sequences</strong></a><br> If several structures are
-    available on the alignment, you may add additional structures to an
-    existing Jmol view by selecting their entry in the appropriate
-    pop-up menu. Jalview will ask you if you wish to add the structure
-    to the existing alignment, and if you do, it will import and
-    superimpose the new PDB file using the corresponding positions from
-    the alignment. If the alignment is subsequently edited, you can use
-    the <a href="#sAlign"><em>Jmol&#8594;Align</em></a> menu option from
-    the menu bar of the structure view window to superpose the
-    structures using the updated alignment.<br> <em>Sequence
+        their aligned sequences</strong></a><br> If several structures are shown
+    in a view, you can superimpose them using the corresponding
+    positions from the alignment via the <a href="#sAlign"><em>Jmol&#8594;Align</em></a>
+    menu option from the menu bar of the structure view window. <br> <em>Sequence
       based structure superposition was added in Jalview 2.6</em>
   </p>
   <p>
index 533af5c..5bca358 100755 (executable)
     and PDB file association (if available). The Jalview id/start-end
     option is ignored if Modeller output is selected.
   <p>
-    <a name="editing"><strong>e&quot;Editinge&quot; Preferences tab</strong></a>
+    <a name="editing"><strong>&quot;Editing&quot; Preferences tab</strong></a>
   </p>
   <p>There are currently three options available which can be
     selected / deselected.</p>
index f551c50..4af0d53 100644 (file)
Binary files a/help/html/features/schooser_enter-id.png and b/help/html/features/schooser_enter-id.png differ
index ab69427..ca793fd 100644 (file)
Binary files a/help/html/features/schooser_main.png and b/help/html/features/schooser_main.png differ
index fc71826..785c429 100644 (file)
 
 <body>
   <p>
-    <strong>Structure Chooser</strong>
+    <strong>Structure Chooser Dialog Box</strong>
   </p>
 
   <p>
-    The Structure Chooser interface allows you to interactively select
-    which PDB structures to view for the currently selected set of
+    The Structure Chooser allows you to select
+    3D structures to view for the currently selected set of
     sequences. It is opened by selecting the <strong>"3D
-      Structure Data.."</strong> option from the Sequence ID panel's <a
+      Structure Data..."</strong> option from the Sequence ID panel's <a
       href="../menus/popupMenu.html">pop-up menu</a>. The dialog
     provides:
   </p>
   <p>
     <strong>Selecting and Viewing Structures</strong>
   </p>
+  <p>The drop-down menu offers different options for structure
+    discovery; the 'Cached' view is shown automatically if existing
+    structure data has been imported for the selected sequences, and if
+    none is available, the import PDB/mmCIF file options are shown.</p>
   <p>
     Once one or more structures have been selected, pressing the <strong>View</strong>
-    button will import them into <a
+    or <strong>Add</strong> button will import them <a
       href="viewingpdbs.html#afterviewbutton">a new or existing
-      structure view</a>.
+      structure view</a>. When multiple views are available, use the
+    drop-down menu to pick the target viewer for the structures.
   </p>
   <p>
     <strong>Automated discovery of structure data</strong>
     criteria (e.g. worst quality rather than best).</p>
   <p>
 
-    <img src="schooser_main.png" style="width: 464px; height: 369px;">
+    <img src="schooser_main.png" style="width: 499px; height: 437px;">
     <!-- <p><img src="schooser_config.png" style="width: 463px; height: 369px; ">
        <p><img src="schooser_drop-down.png" style="width: 464px; height: 368px; ">
        <p><img src="schooser_enter-id.png" style="width: 467px; height: 373px; ">
        <p><img src="schooser_from-file.png" style="width: 468px; height: 370px; ">
        <p><img src="schooser_cached.png"> -->
-    <br>The screenshot above shows the Structure Chooser interface
-    along with the meta-data of auto-discovered structures for the
-    sample alignment. If no structures were
-    auto-discovered, options for manually associating PDB records will be shown (see below).
-  <p>
+    <br>The screenshot above shows the Structure Chooser displayed after
+    selecting all the sequences in the Jalview example project. If no
+    structures were auto-discovered, options for manually associating
+    PDB records will be shown (see below).<p>
     <strong>Exploration of meta-data for available structures</strong>
   </p>
   <p>Information on each structure available is displayed in columns
     Columns' tab and tick the columns which you want to see.</p>
   <p>
     <img src="schooser_enter-id.png"
-      style="width: 464px; height: 369px;">
+      style="width: 464px; height: 173px;">
       <br/>
     <strong>Manual selection/association of PDB files with
       Sequences</strong>
index 45d979f..b1ad4ba 100755 (executable)
@@ -82,6 +82,7 @@
     provided it is installed and can be launched by Jalview. The default
     viewer can be configured in the <a href="preferences.html#structure">Structure
       tab</a> in the <strong>Tools&rarr;Preferences</strong> dialog box.
+  
   <p>
     Structure data imported into Jalview can also be processed to
     display secondary structure and temperature factor annotation. See
     for more information.
   </p>
   <p>
-    <strong><a name="afterviewbutton">After pressing the
-        'View' button in the Structure Chooser</a></strong><br /> The behaviour of
-    the 'View' button depends on the number of structures selected, and
-    whether structure views already exist for the selected structures or
-    aligned sequences.
+    <img src="schooser_viewbutton.png"
+      style="width: 465px; height: 81px" /><br/> <strong><a
+      name="afterviewbutton">Controlling where the new structures
+        will be shown</a></strong>
+        <br />The Structure Chooser offers several options
+    for viewing a structure. <br/><strong>New View</strong> will open a new
+    structure viewer for the selected structures, but if there are views
+    already open, you can select which one to use, and press the <strong>Add</strong>
+    button. Jalview can automatically superimpose new structures based
+    on the linked alignments - but if this is not desirable, simple
+    un-tick the <strong>Superpose Structures</strong> checkbox.
+
   </p>
-  <p>If multiple structures are selected, then Jalview will always
-    create a new structure view. The selected structures will be
-    imported into this view, and superposed with the matched positions
-    from the aligned sequences. A message in the structure viewer's
-    status bar will be shown if not enough aligned columns were
-    available to perform a superposition.</p>
   <p>
-    If a <strong>single</strong> PDB structure is selected, one of the
-    following will happen:
+    <em>Superposing structures</em><br/>Jalview superposes structures using
+    the visible portions of any associated sequence alignments. A
+    message in the structure viewer's status bar will be shown if not
+    enough aligned columns were available to perform a superposition.
   </p>
-
-  <ul>
-    <li>If no structures are open, then an interactive display of
-      the structure will be opened in a new window.</li>
-
-    <li>If another structure is already shown for the current
-      alignment, then you will be asked if you want to add and <a
-      href="jmol.html#align"></a> to the structure in the existing view.
-      (<em>new feature in Jalview 2.6</em>).
-    </li>
-
-    <li>If the structure is already shown, then you will be
-      prompted to associate the sequence with an existing view of the
-      selected structure. This is useful when working with multi-domain
-      or multi-chain PDB files.</li>
-
-    <li style="list-style: none">See the <a href="jmol.html">Jmol
-    </a> and <a href="chimera.html">Chimera</a> PDB viewer help pages for
-      more information about the display.
-    </li>
-  </ul>
-
+  <p>
+  See the <a href="jmol.html">Jmol
+    </a> and <a href="chimera.html">Chimera</a> help pages for
+      more information about their capabilities.</p>
+  
 
   <p>
     <strong>Retrieving sequences from the PDB</strong><br>You can
index a93ce4b..d716e33 100755 (executable)
@@ -86,7 +86,7 @@
             the <a href="../features/groovy.html">Groovy Console</a> for
             interactive scripting.
         </em><strong><br></strong></li>
-        <li><strong>Enable Experimental Features</strong> <em>Enable or disable <a href="../whatsNew.html#experimental">features still under development</a> in Jalview's user interface. This setting is remembered in your preferences.</em>
+        <!--         <li><strong>Enable Experimental Features</strong> <em>Enable or disable <a href="../whatsNew.html#experimental">features still under development</a> in Jalview's user interface. This setting is remembered in your preferences.</em> -->
 
       </ul></li>
     <li><strong>Vamsas</strong> <em>For more details, read the
index 006ee5c..dd2bb62 100755 (executable)
@@ -70,19 +70,33 @@ li:before {
     <tr>
       <td width="60" nowrap>
         <div align="center">
-          <strong><a name="Jalview.2.10.4">2.10.4</a><br /> <em>27/02/2018</em></strong>
+          <strong><a name="Jalview.2.10.4">2.10.4</a><br /> <em>8/05/2018</em></strong>
         </div>
       </td>
       <td><div align="left">
           <em></em>
           <ul>
             <li>
-              <!-- JAL-984 -->Mouse cursor changes to indicate Sequence ID and annotation area margins can be click-dragged to adjust them.</li> 
+              <!-- JAL-1847 JAL-2944 -->New Structure Chooser control
+              for disabling automatic superposition of multiple
+              structures and open structures in existing views
+            </li>
+            <li>
+              <!-- JAL-984 -->Mouse cursor changes to indicate Sequence
+              ID and annotation area margins can be click-dragged to
+              adjust them.
+            </li>
+            <li>
+              <!-- JAL-2885 -->Jalview uses HTTPS for Uniprot, Xfam and
+              Ensembl services
+            </li>
             <li>
-            <!-- JAL-2885 -->Jalview uses HTTPS for Uniprot, Xfam and Ensembl services 
+              <!-- JAL-2759 -->Improved performance for large alignments
+              and lots of hidden columns
             </li>
             <li>
-            <!-- JAL-2759 -->Improved performance for large alignments and lots of hidden columns
+              <!-- JAL-2593 -->Improved performance when rendering lots
+              of features (particularly when transparency is disabled)
             </li>
           </ul>
           </div>
@@ -90,20 +104,111 @@ li:before {
       <td><div align="left">
           <ul>
             <li>
-              <!-- JAL-2778 -->Slow redraw when Overview panel shown overlapping alignment panel
+              <!-- JAL-2899 -->Structure and Overview aren't updated
+              when Colour By Annotation threshold slider is adjusted
+            </li>
+            <li>
+              <!-- JAL-2778 -->Slow redraw when Overview panel shown
+              overlapping alignment panel
+            </li>
+            <li>
+              <!--  JAL-2929 -->overview doesn't show end of unpadded
+              sequence as gaps
+            </li>
+            <li>
+              <!-- JAL-2789, JAL-2893 -->Cross-reference handling improved: CDS not handled correctly if transcript has no UTR
+            </li>
+            <li>
+            
+            </li>
+            <li>
+              <!-- JAL-2666 -->Linked scrolling via protein horizontal
+              scroll bar doesn't work for some CDS/Protein views
+            </li>
+            <li>
+              <!-- JAL-2930 -->Trackpad scrolling is broken on OSX on
+              Java 1.8u153 onwards and Java 1.9u4+.
+            </li>
+            <li>
+              <!-- JAL-2924 -->Tooltip shouldn't be displayed for empty
+              columns in annotation row
+            </li>
+            <li>
+              <!-- JAL-2913 -->Preferences panel's ID Width control is
+              honored in interactive and batch mode
+            </li>
+            <li>
+              <!-- JAL-2945 -->Linked sequence highlighting doesn't work
+              for structures added to existing Jmol view
+            </li>
+            <li>
+              <!-- JAL-2223 -->'View Mappings' includes duplicate
+              entries after importing project with multiple views
+            </li>
+            <li>
+              <!-- JAL-2781 JAL-2780 -->Viewing or annotating Uniprot
+              protein sequences via SIFTS from associated PDB entries
+              with negative residue numbers or missing residues fails
+            </li>
+            <li>
+              <!-- JAL-2952 -->Exception when shading sequence with negative
+              Temperature Factor values from annotated PDB files (e.g.
+              as generated by CONSURF)
             </li>
             <li>
-              <!-- JAL-2666 -->Linked scrolling via protein horizontal scroll bar doesn't work for some CDS/Protein views 
+              <!-- JAL-2922 -->Invert displayed features very slow when
+              structure and/or overview windows are also shown
+            </li>
+            <li>
+              <!-- JAL-2954 -->Selecting columns from highlighted regions
+              very slow for alignments with large numbers of sequences
+            </li>
+            <li>
+              <!-- JAL-2925 -->Copy Consensus fails for group consensus
+              with 'StringIndexOutOfBounds'
+            </li>
+            <li>
+              <!-- JAL-2976 -->VAqua(4) provided as fallback Look and Feel for OSX
+              platforms running Java 10
+            </li>
+            <li>
+              <!-- JAL-2960 -->Adding a structure to existing structure
+              view appears to do nothing because the view is hidden behind the alignment view
             </li>
-            <li><!-- JAL-2930 -->Trackpad scrolling is broken on OSX on Java 1.8u153 onwards and Java 1.9u4+.</li>
-            <li><!-- JAL-2924 -->Tooltip shouldn't be displayed for empty columns in annotation row</li>
-            <li><!-- JAL-2913 -->Preferences panel's ID Width control is honored in interactive and batch mode</li>
-            </ul><em>Applet</em><ul>
-            <li><!-- JAL-2926 -->Copy consensus sequence option in applet should copy the group consensus when popup is opened on it</li>
-             
           </ul>
-      </div>
-      </td>
+          <em>Applet</em>
+          <ul>
+            <li>
+              <!-- JAL-2926 -->Copy consensus sequence option in applet
+              should copy the group consensus when popup is opened on it
+            </li>
+          </ul>
+          <em>Batch Mode</em>
+          <ul>
+          <li>
+            <!-- JAL-2913 -->Fixed ID width preference is not respected
+          </li>
+          </ul>
+          <em>New Known Defects</em>
+          <ul>
+            <li>
+              <!-- JAL-2973 --> Exceptions occasionally raised when
+              editing a large alignment and overview is displayed
+            </li>
+            <li>
+              <!-- JAL-2974 -->'Overview updating' progress bar is shown
+              repeatedly after a series of edits even when the overview
+              is no longer reflecting updates
+            </li>
+            <li>
+              <!-- JAL-2946 -->'SIFTS Mapping Error' when viewing
+              structures for protein subsequence (if 'Trim Retrieved
+              Sequences' enabled) or Ensembl isoforms (Workaround in
+              2.10.4 is to fail back to N&amp;W mapping)
+            </li>
+          </ul>
+        </div>
+          </td>
     </tr>
     <tr>
       <td width="60" nowrap>
index d3972f5..0abd2a7 100755 (executable)
     <strong>What's new in Jalview 2.10.4 ?</strong>
   </p>
   <p>
-    This is the February 2018 release of Jalview, with several minor bug fixes and enhanvements. 
-    The full list bugs fixed in this release can be found in the <a href="releases.html#Jalview.2.10.4">2.10.4
-      Release Notes</a>. In addition, Jalview 2.10.4 provides:
+    This is the May 2018 release of Jalview, and the last in the 2.10.x series. Jalview 2.10.4 includes:
   </p>
   <ul>
-    <li></li>
+    <li>Numerous efficiency improvements in the renderer and overview when working with large alignments with lots of hidden columns</li>
+    <li>Use of HTTPS when connecting to Uniprot, Ensembl and other EBI web services</li>
+    <li>Critical patches for running Jalview on OSX with Java 10</li>
+    <li>Easier adjustment of the Alignment ID panel and Annotation panel</li>
+    <li>Improved support for mapping between 3D Structures and Uniprot Protein Sequences</li>
+    <li>Improved support for discovering CDS and transcripts for Proteins and Ensembl gene IDs</li>
+    <li>New buttons on the Structure Chooser for adding structures
+      to an existing view, and disabling automatic superposition
+      according to linked alignments</li>
+    <li>Annotation transfer between Chimera and Jalview <em>(formerly only
+        available in 'Experimental' mode)</em></li>
   </ul>
   <p>
-    <strong><a name="experimental">Experimental Features</a></strong>
+    The full list of bugs fixed in this release can be found in the <a href="releases.html#Jalview.2.10.4">2.10.4
+      Release Notes</a>. 
   </p>
-  <p>
-    Remember, please enable the <em>Experimental Features</em> option in
-    the Jalview Desktop's <em>Tools</em> menu, and then restart Jalview
-    if you want to try out features below:
-  </p>
-  <ul>
-    <li><em>Annotation transfer between Chimera and Jalview</em><br />Two
-      <a href="features/chimera.html#experimental">new entries in
-        the Chimera viewer's Chimera menu</a> allow positional annotation to
-      be exchanged between Chimera and Jalview.</li>
-  </ul>
-  
 </body>
 </html>
diff --git a/lib/VAqua4.jar b/lib/VAqua4.jar
new file mode 100644 (file)
index 0000000..c1e7cfc
Binary files /dev/null and b/lib/VAqua4.jar differ
index 609c6a8..c5ab140 100644 (file)
@@ -405,10 +405,6 @@ label.view_name_original = Original
 label.enter_view_name = Enter View Name
 label.enter_label = Enter label
 label.enter_label_for_the_structure = Enter a label for the structure
-label.pdb_entry_is_already_displayed = {0} is already displayed.\nDo you want to re-use this viewer ?
-label.map_sequences_to_visible_window = Map Sequences to Visible Window: {0}
-label.add_pdbentry_to_view = Do you want to add {0} to the view called\n{1}\n
-label.align_to_existing_structure_view = Align to existing structure view
 label.pdb_entries_couldnt_be_retrieved = The following pdb entries could not be retrieved from the PDB\:\n{0}\nPlease retry, or try downloading them manually.
 label.couldnt_load_file = Couldn't load file
 label.couldnt_find_pdb_id_in_file = Couldn't find a PDB id in the file supplied. Please enter an Id to identify this structure.
@@ -1222,7 +1218,6 @@ label.pdb_sequence_fetcher = PDB Sequence Fetcher
 label.result = result
 label.results = results
 label.structure_chooser = Structure Chooser
-label.select = Select : 
 label.invert = Invert 
 label.select_pdb_file = Select PDB File
 info.select_filter_option = Select Filter Option/Manual Entry
index 6dfefa3..0144522 100644 (file)
@@ -370,10 +370,6 @@ label.ignore_unmatched_dropped_files = Ignorar los ficheros sin coincidencias?
 label.enter_view_name = Introduzca un nombre para la vista
 label.enter_label = Introducir etiqueta
 label.enter_label_for_the_structure = Introducir una etiqueta para la estructura
-label.pdb_entry_is_already_displayed = {0} Ya est\u00E1 mostrado.\nQuieres volver a usar este visor?
-label.map_sequences_to_visible_window = Mapa de secuencias en ventana visible: {0}
-label.add_pdbentry_to_view = Quieres a\u00F1adir {0} a la vista llamada\n{1}\n
-label.align_to_existing_structure_view = Alinear a una estructura ya existente
 label.pdb_entries_couldnt_be_retrieved = Las siguientes entradas pdb no pueden ser extra\u00EDdas del PDB\:\n{0}\nPor favor, prueba descarg\u00E1ndolas manualmente.
 label.couldnt_load_file = No se pudo cargar el fichero
 label.couldnt_find_pdb_id_in_file = No se pudo encontrar un Id PDB en el fichero suministrado. Por favor, introduzca un Id para identificar esta estructura.
@@ -1176,7 +1172,6 @@ label.structures_filter=Filtro de Estructuras
 label.scale_protein_to_cdna=Adaptar proteína a cDNA
 label.scale_protein_to_cdna_tip=Hacer a los residuos de proteínas de la misma anchura que los codones en ventanas divididas
 status.loading_cached_pdb_entries=Cargando Entradas PDB en Caché
-label.select=Seleccionar :
 label.select_by_annotation=Seleccionar/Ocultar Columnas por Anotación
 action.select_by_annotation=Seleccionar/Ocultar Columnas por Anotación...
 action.export_features=Exportar Características
index 29b994e..904a860 100755 (executable)
@@ -45,11 +45,11 @@ public class PDBChain
 
   public String id;
 
-  public Vector<Bond> bonds = new Vector<Bond>();
+  public Vector<Bond> bonds = new Vector<>();
 
-  public Vector<Atom> atoms = new Vector<Atom>();
+  public Vector<Atom> atoms = new Vector<>();
 
-  public Vector<Residue> residues = new Vector<Residue>();
+  public Vector<Residue> residues = new Vector<>();
 
   public int offset;
 
@@ -343,12 +343,13 @@ public class PDBChain
     boolean deoxyn = false;
     boolean nucleotide = false;
     StringBuilder seq = new StringBuilder(256);
-    Vector<SequenceFeature> resFeatures = new Vector<SequenceFeature>();
-    Vector<Annotation> resAnnotation = new Vector<Annotation>();
-    int i, iSize = atoms.size() - 1;
+    Vector<SequenceFeature> resFeatures = new Vector<>();
+    Vector<Annotation> resAnnotation = new Vector<>();
+    int iSize = atoms.size() - 1;
     int resNumber = -1;
     char insCode = ' ';
-    for (i = 0; i <= iSize; i++)
+
+    for (int i = 0; i <= iSize; i++)
     {
       Atom tmp = atoms.elementAt(i);
       resNumber = tmp.resNumber;
@@ -362,7 +363,7 @@ public class PDBChain
         offset = resNumber;
       }
 
-      Vector<Atom> resAtoms = new Vector<Atom>();
+      Vector<Atom> resAtoms = new Vector<>();
       // Add atoms to a vector while the residue number
       // remains the same as the first atom's resNumber (res)
       while ((resNumber == res) && (ins == insCode) && (i < atoms.size()))
@@ -469,7 +470,8 @@ public class PDBChain
 
     if (StructureImportSettings.isShowSeqFeatures())
     {
-      for (i = 0, iSize = resFeatures.size(); i < iSize; i++)
+      iSize = resFeatures.size();
+      for (int i = 0; i < iSize; i++)
       {
         sequence.addSequenceFeature(resFeatures.elementAt(i));
         resFeatures.setElementAt(null, i);
@@ -478,20 +480,20 @@ public class PDBChain
     if (visibleChainAnnotation)
     {
       Annotation[] annots = new Annotation[resAnnotation.size()];
-      float max = 0;
-      for (i = 0, iSize = annots.length; i < iSize; i++)
+      float max = 0f;
+      float min = 0f;
+      iSize = annots.length;
+      for (int i = 0; i < iSize; i++)
       {
         annots[i] = resAnnotation.elementAt(i);
-        if (annots[i].value > max)
-        {
-          max = annots[i].value;
-        }
+        max = Math.max(max, annots[i].value);
+        min = Math.min(min, annots[i].value);
         resAnnotation.setElementAt(null, i);
       }
 
       AlignmentAnnotation tfactorann = new AlignmentAnnotation(
               "Temperature Factor", "Temperature Factor for " + pdbid + id,
-              annots, 0, max, AlignmentAnnotation.LINE_GRAPH);
+              annots, min, max, AlignmentAnnotation.LINE_GRAPH);
       tfactorann.setSequenceRef(sequence);
       sequence.addAlignmentAnnotation(tfactorann);
     }
index b4612cf..8f778f7 100644 (file)
@@ -20,6 +20,9 @@
  */
 package jalview.api.structures;
 
+import jalview.api.AlignmentViewPanel;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
 import jalview.schemes.ColourSchemeI;
 import jalview.structures.models.AAStructureBindingModel;
 
@@ -69,4 +72,57 @@ public interface JalviewStructureDisplayI
    */
   boolean hasMapping();
 
+  /**
+   * Checks if the PDB file is already loaded in this viewer, if so just adds
+   * mappings as necessary and answers true, else answers false. This supports
+   * the use case of adding additional chains of the same structure to a viewer.
+   * 
+   * @param seq
+   * @param chains
+   * @param apanel
+   * @param pdbId
+   * @return
+   */
+  boolean addAlreadyLoadedFile(SequenceI[] seq, String[] chains,
+          AlignmentViewPanel apanel, String pdbId);
+
+  /**
+   * Adds one or more chains (sequences) of a PDB structure to this structure
+   * viewer
+   * 
+   * @param pdbentry
+   * @param seq
+   * @param chains
+   * @param apanel
+   * @param pdbId
+   * @return
+   */
+  void addToExistingViewer(PDBEntry pdbentry, SequenceI[] seq,
+          String[] chains, AlignmentViewPanel apanel, String pdbId);
+
+  /**
+   * refresh GUI after reconfiguring structure(s) and alignment panels
+   */
+  void updateTitleAndMenus();
+
+  /**
+   * Answers true if the viewer should attempt to align any added structures,
+   * else false
+   * 
+   * @return
+   */
+  boolean isAlignAddedStructures();
+
+  /**
+   * Sets the flag for whether added structures should be aligned
+   * 
+   * @param alignAdded
+   */
+  void setAlignAddedStructures(boolean alignAdded);
+
+  /**
+   * Raise the panel to the top of the stack...
+   */
+  void raiseViewer();
+
 }
index bc93c37..f911675 100755 (executable)
@@ -279,6 +279,8 @@ public class Jalview
       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
     } catch (Exception ex)
     {
+      System.err.println("Unexpected Look and Feel Exception");
+      ex.printStackTrace();
     }
     if (Platform.isAMac())
     {
@@ -294,6 +296,20 @@ public class Jalview
         System.err.println(
                 "Failed to set QuaQua look and feel: " + e.toString());
       }
+      if (!ch.randelshofer.quaqua.QuaquaManager.getLookAndFeel()
+              .equals(UIManager.getLookAndFeel()))
+      {
+        try
+        {
+          System.err.println(
+                  "Quaqua LaF not available. Using VAqua(4).");
+          UIManager.setLookAndFeel("org.violetlib.aqua.AquaLookAndFeel");
+        } catch (Throwable e)
+        {
+          System.err.println(
+                  "Failed to reset look and feel: " + e.toString());
+        }
+      }
     }
 
     /*
index cde50e5..d1e3fcc 100755 (executable)
@@ -267,9 +267,12 @@ public class SearchResults implements SearchResultsI
   {
     int count = 0;
     BitSet mask = new BitSet();
+    int startRes = sqcol.getStartRes();
+    int endRes = sqcol.getEndRes();
+
     for (SequenceI s : sqcol.getSequences())
     {
-      int[] cols = getResults(s, sqcol.getStartRes(), sqcol.getEndRes());
+      int[] cols = getResults(s, startRes, endRes);
       if (cols != null)
       {
         for (int pair = 0; pair < cols.length; pair += 2)
index 41bc116..8832278 100644 (file)
@@ -478,6 +478,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     lastCommand = command;
   }
 
+  Thread colourby = null;
   /**
    * Sends a set of colour commands to the structure viewer
    * 
@@ -485,15 +486,28 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
    */
   @Override
   protected void colourBySequence(
-          StructureMappingcommandSet[] colourBySequenceCommands)
+          final StructureMappingcommandSet[] colourBySequenceCommands)
   {
-    for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands)
+    if (colourby != null)
     {
-      for (String cbyseq : cpdbbyseq.commands)
+      colourby.interrupt();
+      colourby = null;
+    }
+    colourby = new Thread(new Runnable()
+    {
+      @Override
+      public void run()
       {
-        executeWhenReady(cbyseq);
+        for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands)
+        {
+          for (String cbyseq : cpdbbyseq.commands)
+          {
+            executeWhenReady(cbyseq);
+          }
+        }
       }
-    }
+    });
+    colourby.start();
   }
 
   /**
@@ -862,19 +876,30 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
       try
       {
         // recover PDB filename for the model hovered over.
-        int _mp = _modelFileNameMap.length - 1,
-                mnumber = new Integer(mdlId).intValue() - 1;
-        while (mnumber < _modelFileNameMap[_mp])
+        int mnumber = new Integer(mdlId).intValue() - 1;
+        if (_modelFileNameMap != null)
         {
-          _mp--;
+          int _mp = _modelFileNameMap.length - 1;
+
+          while (mnumber < _modelFileNameMap[_mp])
+          {
+            _mp--;
+          }
+          pdbfilename = modelFileNames[_mp];
         }
-        pdbfilename = modelFileNames[_mp];
-        if (pdbfilename == null)
+        else
         {
-          pdbfilename = new File(viewer.ms.getModelFileName(mnumber))
-                  .getAbsolutePath();
-        }
+          if (mnumber >= 0 && mnumber < modelFileNames.length)
+          {
+            pdbfilename = modelFileNames[mnumber];
+          }
 
+          if (pdbfilename == null)
+          {
+            pdbfilename = new File(viewer.ms.getModelFileName(mnumber))
+                    .getAbsolutePath();
+          }
+        }
       } catch (Exception e)
       {
       }
index 076e212..f94d455 100644 (file)
@@ -284,7 +284,8 @@ public abstract class FTSRestClient implements FTSRestClientI
               public boolean equals(Object otherObject)
               {
                 FTSDataColumnI that = (FTSDataColumnI) otherObject;
-                return this.getCode().equals(that.getCode())
+                return otherObject == null ? false
+                        : this.getCode().equals(that.getCode())
                         && this.getName().equals(that.getName())
                         && this.getGroup().equals(that.getGroup());
               }
index 153f70c..384635b 100644 (file)
@@ -459,4 +459,11 @@ public class AnnotationColourChooser extends AnnotationRowFilter
     }
   }
 
+  @Override
+  protected void sliderDragReleased()
+  {
+    super.sliderDragReleased();
+    ap.paintAlignment(true, true);
+  }
+
 }
index 71ad6a5..f13cb10 100644 (file)
@@ -172,11 +172,7 @@ public abstract class AnnotationRowFilter extends JPanel
       @Override
       public void mouseReleased(MouseEvent evt)
       {
-        if (sliderDragging)
-        {
-          sliderDragging = false;
-          valueChanged(true);
-        }
+        sliderDragReleased();
       }
     });
   }
@@ -523,4 +519,13 @@ public abstract class AnnotationRowFilter extends JPanel
   {
     this.annotations = anns;
   }
+
+  protected void sliderDragReleased()
+  {
+    if (sliderDragging)
+    {
+      sliderDragging = false;
+      valueChanged(true);
+    }
+  }
 }
index fef7451..6c934c8 100644 (file)
@@ -44,7 +44,6 @@ import java.util.List;
 import java.util.Vector;
 
 import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JInternalFrame;
 import javax.swing.JPanel;
 import javax.swing.JSplitPane;
 import javax.swing.SwingUtilities;
@@ -58,7 +57,7 @@ public class AppJmol extends StructureViewerBase
 
   private static final String SPACE = " ";
 
-  private static final String BACKSLASH = "\"";
+  private static final String QUOTE = "\"";
 
   AppJmolBinding jmb;
 
@@ -162,8 +161,9 @@ public class AppJmol extends StructureViewerBase
   {
     return progressBar;
   }
+  
   /**
-   * add a single PDB structure to a new or existing Jmol view
+   * display a single PDB structure in a new Jmol view
    * 
    * @param pdbentry
    * @param seq
@@ -174,33 +174,14 @@ public class AppJmol extends StructureViewerBase
           final AlignmentPanel ap)
   {
     progressBar = ap.alignFrame;
-    String pdbId = pdbentry.getId();
 
-    /*
-     * If the PDB file is already loaded, the user may just choose to add to an
-     * existing viewer (or cancel)
-     */
-    if (addAlreadyLoadedFile(seq, chains, ap, pdbId))
-    {
-      return;
-    }
-
-    /*
-     * Check if there are other Jmol views involving this alignment and prompt
-     * user about adding this molecule to one of them
-     */
-    if (addToExistingViewer(pdbentry, seq, chains, ap, pdbId))
-    {
-      return;
-    }
-
-    /*
-     * If the options above are declined or do not apply, open a new viewer
-     */
-    openNewJmol(ap, new PDBEntry[] { pdbentry }, new SequenceI[][] { seq });
+    openNewJmol(ap, alignAddedStructures, new PDBEntry[] { pdbentry },
+            new SequenceI[][]
+            { seq });
   }
 
-  private void openNewJmol(AlignmentPanel ap, PDBEntry[] pdbentrys,
+  private void openNewJmol(AlignmentPanel ap, boolean alignAdded,
+          PDBEntry[] pdbentrys,
           SequenceI[][] seqs)
   {
     progressBar = ap.alignFrame;
@@ -209,11 +190,9 @@ public class AppJmol extends StructureViewerBase
     addAlignmentPanel(ap);
     useAlignmentPanelForColourbyseq(ap);
 
-    if (pdbentrys.length > 1)
-    {
-      alignAddedStructures = true;
-      useAlignmentPanelForSuperposition(ap);
-    }
+    alignAddedStructures = alignAdded;
+    useAlignmentPanelForSuperposition(ap);
+
     jmb.setColourBySequence(true);
     setSize(400, 400); // probably should be a configurable/dynamic default here
     initMenus();
@@ -234,41 +213,21 @@ public class AppJmol extends StructureViewerBase
   }
 
   /**
-   * create a new Jmol containing several structures superimposed using the
-   * given alignPanel.
+   * create a new Jmol containing several structures optionally superimposed
+   * using the given alignPanel.
    * 
    * @param ap
+   * @param alignAdded
+   *          - true to superimpose
    * @param pe
    * @param seqs
    */
-  public AppJmol(AlignmentPanel ap, PDBEntry[] pe, SequenceI[][] seqs)
+  public AppJmol(AlignmentPanel ap, boolean alignAdded, PDBEntry[] pe,
+          SequenceI[][] seqs)
   {
-    openNewJmol(ap, pe, seqs);
+    openNewJmol(ap, alignAdded, pe, seqs);
   }
 
-  /**
-   * Returns a list of any Jmol viewers. The list is restricted to those linked
-   * to the given alignment panel if it is not null.
-   */
-  @Override
-  protected List<StructureViewerBase> getViewersFor(AlignmentPanel apanel)
-  {
-    List<StructureViewerBase> result = new ArrayList<>();
-    JInternalFrame[] frames = Desktop.instance.getAllFrames();
-
-    for (JInternalFrame frame : frames)
-    {
-      if (frame instanceof AppJmol)
-      {
-        if (apanel == null
-                || ((StructureViewerBase) frame).isLinkedWith(apanel))
-        {
-          result.add((StructureViewerBase) frame);
-        }
-      }
-    }
-    return result;
-  }
 
   void initJmol(String command)
   {
@@ -300,8 +259,6 @@ public class AppJmol extends StructureViewerBase
     jmb.setFinishedInit(true);
   }
 
-  boolean allChainsSelected = false;
-
   @Override
   void showSelectedChains()
   {
@@ -368,8 +325,8 @@ public class AppJmol extends StructureViewerBase
     StringBuilder fileList = new StringBuilder();
     for (String s : files)
     {
-      fileList.append(SPACE).append(BACKSLASH)
-              .append(Platform.escapeString(s)).append(BACKSLASH);
+      fileList.append(SPACE).append(QUOTE)
+              .append(Platform.escapeString(s)).append(QUOTE);
     }
     String filesString = fileList.toString();
 
@@ -444,7 +401,7 @@ public class AppJmol extends StructureViewerBase
       jmb.updateColours(ap);
     }
     // do superposition if asked to
-    if (Cache.getDefault("AUTOSUPERIMPOSE", true) && alignAddedStructures)
+    if (alignAddedStructures)
     {
       alignAddedStructures();
     }
@@ -478,7 +435,7 @@ public class AppJmol extends StructureViewerBase
         }
       }
     });
-    alignAddedStructures = false;
+
   }
 
   /**
@@ -507,6 +464,7 @@ public class AppJmol extends StructureViewerBase
         String file = jmb.getPdbEntry(pi).getFile();
         if (file == null)
         {
+          // todo: extract block as method and pull up (also ChimeraViewFrame)
           // retrieve the pdb and store it locally
           AlignmentI pdbseq = null;
           pdbid = jmb.getPdbEntry(pi).getId();
index 89de2e8..d07a7c2 100644 (file)
@@ -100,41 +100,34 @@ public class ChimeraViewFrame extends StructureViewerBase
     savemenu.setVisible(false); // not yet implemented
     viewMenu.add(fitToWindow);
 
-    /*
-     * exchange of Jalview features and Chimera attributes is for now
-     * an optionally enabled experimental feature
-     */
-    if (Desktop.instance.showExperimental())
+    JMenuItem writeFeatures = new JMenuItem(
+            MessageManager.getString("label.create_chimera_attributes"));
+    writeFeatures.setToolTipText(MessageManager
+            .getString("label.create_chimera_attributes_tip"));
+    writeFeatures.addActionListener(new ActionListener()
     {
-      JMenuItem writeFeatures = new JMenuItem(
-              MessageManager.getString("label.create_chimera_attributes"));
-      writeFeatures.setToolTipText(MessageManager
-              .getString("label.create_chimera_attributes_tip"));
-      writeFeatures.addActionListener(new ActionListener()
-      {
-        @Override
-        public void actionPerformed(ActionEvent e)
-        {
-          sendFeaturesToChimera();
-        }
-      });
-      viewerActionMenu.add(writeFeatures);
-
-      final JMenu fetchAttributes = new JMenu(
-              MessageManager.getString("label.fetch_chimera_attributes"));
-      fetchAttributes.setToolTipText(MessageManager
-              .getString("label.fetch_chimera_attributes_tip"));
-      fetchAttributes.addMouseListener(new MouseAdapter()
+      @Override
+      public void actionPerformed(ActionEvent e)
       {
+        sendFeaturesToChimera();
+      }
+    });
+    viewerActionMenu.add(writeFeatures);
 
-        @Override
-        public void mouseEntered(MouseEvent e)
-        {
-          buildAttributesMenu(fetchAttributes);
-        }
-      });
-      viewerActionMenu.add(fetchAttributes);
-    }
+    final JMenu fetchAttributes = new JMenu(
+            MessageManager.getString("label.fetch_chimera_attributes"));
+    fetchAttributes.setToolTipText(
+            MessageManager.getString("label.fetch_chimera_attributes_tip"));
+    fetchAttributes.addMouseListener(new MouseAdapter()
+    {
+
+      @Override
+      public void mouseEntered(MouseEvent e)
+      {
+        buildAttributesMenu(fetchAttributes);
+      }
+    });
+    viewerActionMenu.add(fetchAttributes);
   }
 
   /**
@@ -202,7 +195,7 @@ public class ChimeraViewFrame extends StructureViewerBase
   }
 
   /**
-   * add a single PDB structure to a new or existing Chimera view
+   * open a single PDB structure in a new Chimera view
    * 
    * @param pdbentry
    * @param seq
@@ -213,30 +206,7 @@ public class ChimeraViewFrame extends StructureViewerBase
           String[] chains, final AlignmentPanel ap)
   {
     this();
-    String pdbId = pdbentry.getId();
-
-    /*
-     * If the PDB file is already loaded, the user may just choose to add to an
-     * existing viewer (or cancel)
-     */
-    if (addAlreadyLoadedFile(seq, chains, ap, pdbId))
-    {
-      return;
-    }
 
-    /*
-     * Check if there are other Chimera views involving this alignment and give
-     * user the option to add and align this molecule to one of them (or cancel)
-     */
-    if (addToExistingViewer(pdbentry, seq, chains, ap, pdbId))
-    {
-      return;
-    }
-
-    /*
-     * If the options above are declined or do not apply, show the structure in
-     * a new viewer
-     */
     openNewChimera(ap, new PDBEntry[] { pdbentry },
             new SequenceI[][]
             { seq });
@@ -264,7 +234,6 @@ public class ChimeraViewFrame extends StructureViewerBase
 
     if (pdbentrys.length > 1)
     {
-      alignAddedStructures = true;
       useAlignmentPanelForSuperposition(ap);
     }
     jmb.setColourBySequence(true);
@@ -323,17 +292,19 @@ public class ChimeraViewFrame extends StructureViewerBase
   }
 
   /**
-   * create a new viewer containing several structures superimposed using the
-   * given alignPanel.
+   * create a new viewer containing several structures, optionally superimposed
+   * using the given alignPanel.
    * 
    * @param pe
    * @param seqs
    * @param ap
    */
-  public ChimeraViewFrame(PDBEntry[] pe, SequenceI[][] seqs,
+  public ChimeraViewFrame(PDBEntry[] pe, boolean alignAdded,
+          SequenceI[][] seqs,
           AlignmentPanel ap)
   {
     this();
+    setAlignAddedStructures(alignAdded);
     openNewChimera(ap, pe, seqs);
   }
 
@@ -352,29 +323,6 @@ public class ChimeraViewFrame extends StructureViewerBase
   }
 
   /**
-   * Returns a list of any Chimera viewers in the desktop. The list is
-   * restricted to those linked to the given alignment panel if it is not null.
-   */
-  @Override
-  protected List<StructureViewerBase> getViewersFor(AlignmentPanel ap)
-  {
-    List<StructureViewerBase> result = new ArrayList<>();
-    JInternalFrame[] frames = Desktop.instance.getAllFrames();
-
-    for (JInternalFrame frame : frames)
-    {
-      if (frame instanceof ChimeraViewFrame)
-      {
-        if (ap == null || ((StructureViewerBase) frame).isLinkedWith(ap))
-        {
-          result.add((StructureViewerBase) frame);
-        }
-      }
-    }
-    return result;
-  }
-
-  /**
    * Launch Chimera. If we have a chimera session file name, send Chimera the
    * command to open its saved session file.
    */
@@ -641,7 +589,7 @@ public class ChimeraViewFrame extends StructureViewerBase
         jmb.updateColours(ap);
       }
       // do superposition if asked to
-      if (Cache.getDefault("AUTOSUPERIMPOSE", true) && alignAddedStructures)
+      if (alignAddedStructures)
       {
         new Thread(new Runnable()
         {
@@ -651,7 +599,6 @@ public class ChimeraViewFrame extends StructureViewerBase
             alignStructs_withAllAlignPanels();
           }
         }).start();
-        alignAddedStructures = false;
       }
       addingStructures = false;
     }
@@ -681,7 +628,6 @@ public class ChimeraViewFrame extends StructureViewerBase
 
   private String fetchPdbFile(PDBEntry processingEntry) throws Exception
   {
-    // FIXME: this is duplicated code with Jmol frame ?
     String filePath = null;
     Pdb pdbclient = new Pdb();
     AlignmentI pdbseq = null;
index b26a8af..be64c85 100644 (file)
@@ -3397,4 +3397,41 @@ public class Desktop extends jalview.jbgui.GDesktop
   {
     Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
   }
+
+  /**
+   * Answers a (possibly empty) list of any structure viewer frames (currently
+   * for either Jmol or Chimera) which are currently open. This may optionally
+   * be restricted to viewers of a specified class, or viewers linked to a
+   * specified alignment panel.
+   * 
+   * @param apanel
+   *          if not null, only return viewers linked to this panel
+   * @param structureViewerClass
+   *          if not null, only return viewers of this class
+   * @return
+   */
+  public List<StructureViewerBase> getStructureViewers(
+          AlignmentPanel apanel,
+          Class<? extends StructureViewerBase> structureViewerClass)
+  {
+    List<StructureViewerBase> result = new ArrayList<>();
+    JInternalFrame[] frames = Desktop.instance.getAllFrames();
+
+    for (JInternalFrame frame : frames)
+    {
+      if (frame instanceof StructureViewerBase)
+      {
+        if (structureViewerClass == null
+                || structureViewerClass.isInstance(frame))
+        {
+          if (apanel == null
+                  || ((StructureViewerBase) frame).isLinkedWith(apanel))
+          {
+            result.add((StructureViewerBase) frame);
+          }
+        }
+      }
+    }
+    return result;
+  }
 }
index 0a6b9d6..1018d6e 100644 (file)
@@ -101,10 +101,10 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
      * identical DB sources, and should be collapsed.
      */
     DefaultMutableTreeNode tn = null, root = new DefaultMutableTreeNode();
-    Hashtable<String, DefaultMutableTreeNode> source = new Hashtable<String, DefaultMutableTreeNode>();
+    Hashtable<String, DefaultMutableTreeNode> source = new Hashtable<>();
     sfetcher = sfetch;
     String dbs[] = sfetch.getSupportedDb();
-    Hashtable<String, String> ht = new Hashtable<String, String>();
+    Hashtable<String, String> ht = new Hashtable<>();
     for (int i = 0; i < dbs.length; i++)
     {
       tn = source.get(dbs[i]);
@@ -370,7 +370,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
 
     tsel = dbviews.getSelectionPaths();
     boolean forcedFirstChild = false;
-    List<DbSourceProxy> srcs = new ArrayList<DbSourceProxy>();
+    List<DbSourceProxy> srcs = new ArrayList<>();
     if (tsel != null)
     {
       for (TreePath tp : tsel)
@@ -489,7 +489,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
       return null;
     }
     StringBuffer sb = new StringBuffer();
-    HashSet<String> hs = new HashSet<String>();
+    HashSet<String> hs = new HashSet<>();
     for (DbSourceProxy dbs : getSelectedSources())
     {
       String tq = dbs.getTestQuery();
@@ -506,7 +506,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
     return sb.toString();
   }
 
-  List<ActionListener> lstners = new Vector<ActionListener>();
+  List<ActionListener> lstners = new Vector<>();
 
   public void addActionListener(ActionListener actionListener)
   {
@@ -596,4 +596,11 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
     // TODO Auto-generated method stub
 
   }
+
+  @Override
+  public void setVisible(boolean arg0)
+  {
+    System.out.println("setVisible: " + arg0);
+    super.setVisible(arg0);
+  }
 }
index 9f52d26..7ceceee 100644 (file)
@@ -464,7 +464,16 @@ public class PCAPanel extends GPCAPanel
     public void run()
     {
       PrinterJob printJob = PrinterJob.getPrinterJob();
-      PageFormat pf = printJob.pageDialog(printJob.defaultPage());
+      PageFormat defaultPage = printJob.defaultPage();
+      PageFormat pf = printJob.pageDialog(defaultPage);
+
+      if (defaultPage == pf)
+      {
+        /*
+         * user cancelled
+         */
+        return;
+      }
 
       printJob.setPrintable(this, pf);
 
index 193d0ee..ce6bcbd 100644 (file)
@@ -2292,4 +2292,13 @@ public class SeqPanel extends JPanel
 
     return true;
   }
+
+  /**
+   * 
+   * @return null or last search results handled by this panel
+   */
+  public SearchResultsI getLastSearchResults()
+  {
+    return lastSearchResults;
+  }
 }
index 8d46792..f545e70 100755 (executable)
@@ -273,7 +273,7 @@ public class SequenceFetcher extends JPanel implements Runnable
         return Collections.emptyList();
       }
     }
-    sf.newAlframes = new ArrayList<AlignFrame>();
+    sf.newAlframes = new ArrayList<>();
     sf.run();
     return sf.newAlframes;
   }
@@ -674,10 +674,10 @@ public class SequenceFetcher extends JPanel implements Runnable
     // TODO: Refactor to GUI independent code and write tests.
     // indicate if successive sources should be merged into one alignment.
     boolean addToLast = false;
-    List<String> aresultq = new ArrayList<String>();
-    List<String> presultTitle = new ArrayList<String>();
-    List<AlignmentI> presult = new ArrayList<AlignmentI>();
-    List<AlignmentI> aresult = new ArrayList<AlignmentI>();
+    List<String> aresultq = new ArrayList<>();
+    List<String> presultTitle = new ArrayList<>();
+    List<AlignmentI> presult = new ArrayList<>();
+    List<AlignmentI> aresult = new ArrayList<>();
     Iterator<DbSourceProxy> proxies = database.getSelectedSources()
             .iterator();
     String[] qries;
@@ -695,7 +695,7 @@ public class SequenceFetcher extends JPanel implements Runnable
         nqueries = nextFetch.size();
         // save the remaining queries in the original array
         qries = nextFetch.toArray(new String[nqueries]);
-        nextFetch = new ArrayList<String>();
+        nextFetch = new ArrayList<>();
       }
 
       DbSourceProxy proxy = proxies.next();
@@ -861,7 +861,7 @@ public class SequenceFetcher extends JPanel implements Runnable
           List<AlignmentI> aresult, List<String> nextFetch) throws Exception
   {
     StringBuilder multiacc = new StringBuilder();
-    List<String> tosend = new ArrayList<String>();
+    List<String> tosend = new ArrayList<>();
     while (accessions.hasNext())
     {
       String nel = accessions.next();
index 198aa62..e18d6af 100644 (file)
@@ -22,6 +22,7 @@
 package jalview.gui;
 
 import jalview.api.structures.JalviewStructureDisplayI;
+import jalview.bin.Cache;
 import jalview.bin.Jalview;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
@@ -68,6 +69,8 @@ import javax.swing.table.AbstractTableModel;
 public class StructureChooser extends GStructureChooser
         implements IProgressIndicator
 {
+  private static final String AUTOSUPERIMPOSE = "AUTOSUPERIMPOSE";
+
   private static int MAX_QLENGTH = 7820;
 
   private SequenceI selectedSequence;
@@ -88,6 +91,8 @@ public class StructureChooser extends GStructureChooser
 
   private boolean cachedPDBExists;
 
+  private static StructureViewer lastTargetedView = null;
+
   public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
           AlignmentPanel ap)
   {
@@ -101,13 +106,15 @@ public class StructureChooser extends GStructureChooser
   /**
    * Initializes parameters used by the Structure Chooser Panel
    */
-  public void init()
+  protected void init()
   {
     if (!Jalview.isHeadlessMode())
     {
       progressBar = new ProgressBar(this.statusPanel, this.statusBar);
     }
 
+    chk_superpose.setSelected(Cache.getDefault(AUTOSUPERIMPOSE, true));
+
     // ensure a filter option is in force for search
     populateFilterComboBox(true, cachedPDBExists);
     Thread discoverPDBStructuresThread = new Thread(new Runnable()
@@ -125,6 +132,7 @@ public class StructureChooser extends GStructureChooser
         fetchStructuresMetaData();
         // revise filter options if no results were found
         populateFilterComboBox(isStructuresDiscovered(), cachedPDBExists);
+        discoverStructureViews();
         updateProgressIndicator(null, startTime);
         mainFrame.setVisible(true);
         updateCurrentView();
@@ -134,6 +142,59 @@ public class StructureChooser extends GStructureChooser
   }
 
   /**
+   * Builds a drop-down choice list of existing structure viewers to which new
+   * structures may be added. If this list is empty then it, and the 'Add'
+   * button, are hidden.
+   */
+  private void discoverStructureViews()
+  {
+    if (Desktop.instance != null)
+    {
+      targetView.removeAllItems();
+      if (lastTargetedView != null && !lastTargetedView.isVisible())
+      {
+        lastTargetedView = null;
+      }
+      int linkedViewsAt = 0;
+      for (StructureViewerBase view : Desktop.instance
+              .getStructureViewers(null, null))
+      {
+        StructureViewer viewHandler = (lastTargetedView != null
+                && lastTargetedView.sview == view) ? lastTargetedView
+                        : StructureViewer.reconfigure(view);
+
+        if (view.isLinkedWith(ap))
+        {
+          targetView.insertItemAt(viewHandler,
+                  linkedViewsAt++);
+        }
+        else
+        {
+          targetView.addItem(viewHandler);
+        }
+      }
+
+      /*
+       * show option to Add to viewer if at least 1 viewer found
+       */
+      targetView.setVisible(false);
+      if (targetView.getItemCount() > 0)
+      {
+        targetView.setVisible(true);
+        if (lastTargetedView != null)
+        {
+          targetView.setSelectedItem(lastTargetedView);
+        }
+        else
+        {
+          targetView.setSelectedIndex(0);
+        }
+      }
+      btn_add.setVisible(targetView.isVisible());
+    }
+  }
+
+  /**
    * Updates the progress indicator with the specified message
    * 
    * @param message
@@ -141,7 +202,7 @@ public class StructureChooser extends GStructureChooser
    * @param id
    *          unique handle for this indicator
    */
-  public void updateProgressIndicator(String message, long id)
+  protected void updateProgressIndicator(String message, long id)
   {
     if (progressIndicator != null)
     {
@@ -153,7 +214,7 @@ public class StructureChooser extends GStructureChooser
    * Retrieve meta-data for all the structure(s) for a given sequence(s) in a
    * selection group
    */
-  public void fetchStructuresMetaData()
+  void fetchStructuresMetaData()
   {
     long startTime = System.currentTimeMillis();
     pdbRestCleint = PDBFTSRestClient.getInstance();
@@ -224,7 +285,7 @@ public class StructureChooser extends GStructureChooser
     }
   }
 
-  public void loadLocalCachedPDBEntries()
+  protected void loadLocalCachedPDBEntries()
   {
     ArrayList<CachedPDB> entries = new ArrayList<>();
     for (SequenceI seq : selectedSequences)
@@ -255,7 +316,7 @@ public class StructureChooser extends GStructureChooser
    * @return the built query string
    */
 
-  public static String buildQuery(SequenceI seq)
+  static String buildQuery(SequenceI seq)
   {
     boolean isPDBRefsFound = false;
     boolean isUniProtRefsFound = false;
@@ -357,7 +418,7 @@ public class StructureChooser extends GStructureChooser
    * @param seqName
    * @return
    */
-  public static boolean isValidSeqName(String seqName)
+  static boolean isValidSeqName(String seqName)
   {
     // System.out.println("seqName : " + seqName);
     String ignoreList = "pdb,uniprot,swiss-prot";
@@ -380,7 +441,7 @@ public class StructureChooser extends GStructureChooser
     return true;
   }
 
-  public static String getDBRefId(DBRefEntry dbRef)
+  static String getDBRefId(DBRefEntry dbRef)
   {
     String ref = dbRef.getAccessionId().replaceAll("GO:", "");
     return ref;
@@ -392,7 +453,7 @@ public class StructureChooser extends GStructureChooser
    * @param fieldToFilterBy
    *          the field to filter by
    */
-  public void filterResultSet(final String fieldToFilterBy)
+  void filterResultSet(final String fieldToFilterBy)
   {
     Thread filterThread = new Thread(new Runnable()
     {
@@ -502,7 +563,7 @@ public class StructureChooser extends GStructureChooser
    * Handles action event for btn_pdbFromFile
    */
   @Override
-  public void pdbFromFile_actionPerformed()
+  protected void pdbFromFile_actionPerformed()
   {
     jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
             jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
@@ -603,28 +664,37 @@ public class StructureChooser extends GStructureChooser
   }
 
   /**
-   * Validates user selection and activates the view button if all parameters
-   * are correct
+   * Validates user selection and enables the 'Add' and 'New View' buttons if
+   * all parameters are correct (the Add button will only be visible if there is
+   * at least one existing structure viewer open). This basically means at least
+   * one structure selected and no error messages.
+   * <p>
+   * The 'Superpose Structures' option is enabled if either more than one
+   * structure is selected, or the 'Add' to existing view option is enabled, and
+   * disabled if the only option is to open a new view of a single structure.
    */
   @Override
-  public void validateSelections()
+  protected void validateSelections()
   {
     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
             .getSelectedItem());
-    btn_view.setEnabled(false);
+    btn_add.setEnabled(false);
     String currentView = selectedFilterOpt.getView();
+    int selectedCount = 0;
     if (currentView == VIEWS_FILTER)
     {
-      if (getResultTable().getSelectedRows().length > 0)
+      selectedCount = getResultTable().getSelectedRows().length;
+      if (selectedCount > 0)
       {
-        btn_view.setEnabled(true);
+        btn_add.setEnabled(true);
       }
     }
     else if (currentView == VIEWS_LOCAL_PDB)
     {
-      if (tbl_local_pdb.getSelectedRows().length > 0)
+      selectedCount = tbl_local_pdb.getSelectedRows().length;
+      if (selectedCount > 0)
       {
-        btn_view.setEnabled(true);
+        btn_add.setEnabled(true);
       }
     }
     else if (currentView == VIEWS_ENTER_ID)
@@ -635,12 +705,21 @@ public class StructureChooser extends GStructureChooser
     {
       validateAssociationFromFile();
     }
+
+    btn_newView.setEnabled(btn_add.isEnabled());
+
+    /*
+     * enable 'Superpose' option if more than one structure is selected,
+     * or there are view(s) available to add structure(s) to
+     */
+    chk_superpose
+            .setEnabled(selectedCount > 1 || targetView.getItemCount() > 0);
   }
 
   /**
    * Validates inputs from the Manual PDB entry panel
    */
-  public void validateAssociationEnterPdb()
+  protected void validateAssociationEnterPdb()
   {
     AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) idInputAssSeqPanel
             .getCmb_assSeq().getSelectedItem();
@@ -666,7 +745,7 @@ public class StructureChooser extends GStructureChooser
       txt_search.setEnabled(true);
       if (isValidPBDEntry)
       {
-        btn_view.setEnabled(true);
+        btn_add.setEnabled(true);
         lbl_pdbManualFetchStatus.setToolTipText("");
         lbl_pdbManualFetchStatus.setIcon(goodImage);
       }
@@ -681,7 +760,7 @@ public class StructureChooser extends GStructureChooser
   /**
    * Validates inputs for the manual PDB file selection options
    */
-  public void validateAssociationFromFile()
+  protected void validateAssociationFromFile()
   {
     AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
             .getCmb_assSeq().getSelectedItem();
@@ -692,7 +771,7 @@ public class StructureChooser extends GStructureChooser
       btn_pdbFromFile.setEnabled(true);
       if (selectedPdbFileName != null && selectedPdbFileName.length() > 0)
       {
-        btn_view.setEnabled(true);
+        btn_add.setEnabled(true);
         lbl_fromFileStatus.setIcon(goodImage);
       }
     }
@@ -704,7 +783,7 @@ public class StructureChooser extends GStructureChooser
   }
 
   @Override
-  public void cmbAssSeqStateChanged()
+  protected void cmbAssSeqStateChanged()
   {
     validateSelections();
   }
@@ -768,11 +847,22 @@ public class StructureChooser extends GStructureChooser
     }
     return found;
   }
+  
+  /**
+   * Handles the 'New View' action
+   */
+  @Override
+  protected void newView_ActionPerformed()
+  {
+    targetView.setSelectedItem(null);
+    showStructures(false);
+  }
+
   /**
-   * Handles action event for btn_ok
+   * Handles the 'Add to existing viewer' action
    */
   @Override
-  public void ok_ActionPerformed()
+  protected void add_ActionPerformed()
   {
     showStructures(false);
   }
@@ -957,6 +1047,30 @@ public class StructureChooser extends GStructureChooser
     return foundEntry;
   }
 
+  /**
+   * Answers a structure viewer (new or existing) configured to superimpose
+   * added structures or not according to the user's choice
+   * 
+   * @param ssm
+   * @return
+   */
+  StructureViewer getTargetedStructureViewer(
+          StructureSelectionManager ssm)
+  {
+    Object sv = targetView.getSelectedItem();
+
+    return sv == null ? new StructureViewer(ssm) : (StructureViewer) sv;
+  }
+
+  /**
+   * Adds PDB structures to a new or existing structure viewer
+   * 
+   * @param ssm
+   * @param pdbEntriesToView
+   * @param alignPanel
+   * @param sequences
+   * @return
+   */
   private StructureViewer launchStructureViewer(
           StructureSelectionManager ssm,
           final PDBEntry[] pdbEntriesToView,
@@ -965,9 +1079,17 @@ public class StructureChooser extends GStructureChooser
     long progressId = sequences.hashCode();
     setProgressBar(MessageManager
             .getString("status.launching_3d_structure_viewer"), progressId);
-    final StructureViewer sViewer = new StructureViewer(ssm);
-    setProgressBar(null, progressId);
+    final StructureViewer theViewer = getTargetedStructureViewer(ssm);
+    boolean superimpose = chk_superpose.isSelected();
+    theViewer.setSuperpose(superimpose);
+
+    /*
+     * remember user's choice of superimpose or not
+     */
+    Cache.setProperty(AUTOSUPERIMPOSE,
+            Boolean.valueOf(superimpose).toString());
 
+    setProgressBar(null, progressId);
     if (SiftsSettings.isMapWithSifts())
     {
       List<SequenceI> seqsWithoutSourceDBRef = new ArrayList<>();
@@ -992,7 +1114,7 @@ public class StructureChooser extends GStructureChooser
             }
           }
         }
-        if (seq.getPrimaryDBRefs().size() == 0)
+        if (seq.getPrimaryDBRefs().isEmpty())
         {
           seqsWithoutSourceDBRef.add(seq);
           continue;
@@ -1004,13 +1126,8 @@ public class StructureChooser extends GStructureChooser
         setProgressBar(MessageManager.formatMessage(
                 "status.fetching_dbrefs_for_sequences_without_valid_refs",
                 y), progressId);
-        SequenceI[] seqWithoutSrcDBRef = new SequenceI[y];
-        int x = 0;
-        for (SequenceI fSeq : seqsWithoutSourceDBRef)
-        {
-          seqWithoutSrcDBRef[x++] = fSeq;
-        }
-
+        SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
+                .toArray(new SequenceI[y]);
         DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef);
         dbRefFetcher.fetchDBRefs(true);
 
@@ -1022,17 +1139,19 @@ public class StructureChooser extends GStructureChooser
       setProgressBar(MessageManager.getString(
               "status.fetching_3d_structures_for_selected_entries"),
               progressId);
-      sViewer.viewStructures(pdbEntriesToView, sequences, alignPanel);
+      theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel);
     }
     else
     {
       setProgressBar(MessageManager.formatMessage(
               "status.fetching_3d_structures_for",
               pdbEntriesToView[0].getId()),progressId);
-      sViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
+      theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
     }
     setProgressBar(null, progressId);
-    return sViewer;
+    // remember the last viewer we used...
+    lastTargetedView = theViewer;
+    return theViewer;
   }
 
   /**
@@ -1040,7 +1159,7 @@ public class StructureChooser extends GStructureChooser
    * a unique sequence when more than one sequence selection is made.
    */
   @Override
-  public void populateCmbAssociateSeqOptions(
+  protected void populateCmbAssociateSeqOptions(
           JComboBox<AssociateSeqOptions> cmb_assSeq,
           JLabel lbl_associateSeq)
   {
@@ -1065,17 +1184,12 @@ public class StructureChooser extends GStructureChooser
     }
   }
 
-  public boolean isStructuresDiscovered()
+  protected boolean isStructuresDiscovered()
   {
     return discoveredStructuresSet != null
             && !discoveredStructuresSet.isEmpty();
   }
 
-  public Collection<FTSData> getDiscoveredStructuresSet()
-  {
-    return discoveredStructuresSet;
-  }
-
   @Override
   protected void txt_search_ActionPerformed()
   {
@@ -1125,7 +1239,7 @@ public class StructureChooser extends GStructureChooser
   }
 
   @Override
-  public void tabRefresh()
+  protected void tabRefresh()
   {
     if (selectedSequences != null)
     {
index f37df71..0c8354b 100644 (file)
@@ -49,6 +49,11 @@ public class StructureViewer
 
   StructureSelectionManager ssm;
 
+  /**
+   * decide if new structures are aligned to existing ones
+   */
+  private boolean superposeAdded = true;
+
   public enum ViewerType
   {
     JMOL, CHIMERA
@@ -64,6 +69,27 @@ public class StructureViewer
     ssm = structureSelectionManager;
   }
 
+  /**
+   * Factory to create a proxy for modifying existing structure viewer
+   * 
+   */
+  public static StructureViewer reconfigure(
+          JalviewStructureDisplayI display)
+  {
+    StructureViewer sv = new StructureViewer(display.getBinding().getSsm());
+    sv.sview = display;
+    return sv;
+  }
+
+  @Override
+  public String toString()
+  {
+    if (sview != null)
+    {
+      return sview.toString();
+    }
+    return "New View";
+  }
   public ViewerType getViewerType()
   {
     String viewType = Cache.getDefault(Preferences.STRUCTURE_DISPLAY,
@@ -104,14 +130,40 @@ public class StructureViewer
             new PDBEntry[seqsForPdbs.size()]);
     SequenceI[][] theSeqs = seqsForPdbs.values().toArray(
             new SequenceI[seqsForPdbs.size()][]);
+    if (sview != null)
+    {
+      sview.setAlignAddedStructures(superposeAdded);
+      new Thread(new Runnable()
+      {
+        @Override
+        public void run()
+        {
+
+          for (int pdbep = 0; pdbep < pdbsForFile.length; pdbep++)
+          {
+            PDBEntry pdb = pdbsForFile[pdbep];
+            if (!sview.addAlreadyLoadedFile(theSeqs[pdbep], null, ap,
+                    pdb.getId()))
+            {
+              sview.addToExistingViewer(pdb, theSeqs[pdbep], null, ap,
+                      pdb.getId());
+            }
+          }
+
+          sview.updateTitleAndMenus();
+        }
+      }).start();
+      return sview;
+    }
 
     if (viewerType.equals(ViewerType.JMOL))
     {
-      sview = new AppJmol(ap, pdbsForFile, theSeqs);
+      sview = new AppJmol(ap, superposeAdded, pdbsForFile, theSeqs);
     }
     else if (viewerType.equals(ViewerType.CHIMERA))
     {
-      sview = new ChimeraViewFrame(pdbsForFile, theSeqs, ap);
+      sview = new ChimeraViewFrame(pdbsForFile, superposeAdded, theSeqs,
+              ap);
     }
     else
     {
@@ -232,6 +284,18 @@ public class StructureViewer
   public JalviewStructureDisplayI viewStructures(PDBEntry pdb,
           SequenceI[] seqsForPdb, AlignmentPanel ap)
   {
+    if (sview != null)
+    {
+      sview.setAlignAddedStructures(superposeAdded);
+      String pdbId = pdb.getId();
+      if (!sview.addAlreadyLoadedFile(seqsForPdb, null, ap, pdbId))
+      {
+        sview.addToExistingViewer(pdb, seqsForPdb, null, ap, pdbId);
+      }
+      sview.updateTitleAndMenus();
+      sview.raiseViewer();
+      return sview;
+    }
     ViewerType viewerType = getViewerType();
     if (viewerType.equals(ViewerType.JMOL))
     {
@@ -299,4 +363,29 @@ public class StructureViewer
     return false;
   }
 
+  /**
+   * 
+   * @param pDBid
+   * @return true if view is already showing PDBid
+   */
+  public boolean hasPdbId(String pDBid)
+  {
+    if (sview == null)
+    {
+      return false;
+    }
+
+    return sview.getBinding().hasPdbId(pDBid);
+  }
+
+  public boolean isVisible()
+  {
+    return sview != null && sview.isVisible();
+  }
+
+  public void setSuperpose(boolean alignAddedStructures)
+  {
+    superposeAdded = alignAddedStructures;
+  }
+
 }
index 93d675a..72b0bcc 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import jalview.api.AlignmentViewPanel;
 import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
@@ -129,6 +130,26 @@ public abstract class StructureViewerBase extends GStructureViewer
   }
 
   /**
+   * @return true if added structures should be aligned to existing one(s)
+   */
+  @Override
+  public boolean isAlignAddedStructures()
+  {
+    return alignAddedStructures;
+  }
+
+  /**
+   * 
+   * @param true
+   *          if added structures should be aligned to existing one(s)
+   */
+  @Override
+  public void setAlignAddedStructures(boolean alignAdded)
+  {
+    alignAddedStructures = alignAdded;
+  }
+
+  /**
    * 
    * @param ap2
    * @return true if this Jmol instance is linked with the given alignPanel
@@ -334,7 +355,7 @@ public abstract class StructureViewerBase extends GStructureViewer
    */
   protected void addStructure(final PDBEntry pdbentry,
           final SequenceI[] seqs, final String[] chains,
-          final boolean align, final IProgressIndicator alignFrame)
+          final IProgressIndicator alignFrame)
   {
     if (pdbentry.getFile() == null)
     {
@@ -358,7 +379,7 @@ public abstract class StructureViewerBase extends GStructureViewer
               }
             }
             // and call ourselves again.
-            addStructure(pdbentry, seqs, chains, align, alignFrame);
+            addStructure(pdbentry, seqs, chains, alignFrame);
           }
         }).start();
         return;
@@ -370,87 +391,42 @@ public abstract class StructureViewerBase extends GStructureViewer
             { seqs }, new String[][] { chains });
     addingStructures = true;
     _started = false;
-    alignAddedStructures = align;
     worker = new Thread(this);
     worker.start();
     return;
   }
 
-  /**
-   * Presents a dialog with the option to add an align a structure to an
-   * existing structure view
-   * 
-   * @param pdbId
-   * @param view
-   * @return YES, NO or CANCEL JvOptionPane code
-   */
-  protected int chooseAlignStructureToViewer(String pdbId,
-          StructureViewerBase view)
-  {
-    int option = JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
-            MessageManager.formatMessage("label.add_pdbentry_to_view",
-                    new Object[]
-                    { pdbId, view.getTitle() }),
-            MessageManager
-                    .getString("label.align_to_existing_structure_view"),
-            JvOptionPane.YES_NO_CANCEL_OPTION);
-    return option;
-  }
-
   protected boolean hasPdbId(String pdbId)
   {
     return getBinding().hasPdbId(pdbId);
   }
 
-  protected abstract List<StructureViewerBase> getViewersFor(
-          AlignmentPanel alp);
-
   /**
-   * Check for any existing views involving this alignment and give user the
-   * option to add and align this molecule to one of them
-   * 
-   * @param pdbentry
-   * @param seq
-   * @param chains
-   * @param apanel
-   * @param pdbId
-   * @return true if user adds to a view, or cancels entirely, else false
+   * Returns a list of any viewer of the instantiated type. The list is
+   * restricted to those linked to the given alignment panel if it is not null.
    */
-  protected boolean addToExistingViewer(PDBEntry pdbentry, SequenceI[] seq,
-          String[] chains, final AlignmentPanel apanel, String pdbId)
+  protected List<StructureViewerBase> getViewersFor(AlignmentPanel alp)
   {
-    for (StructureViewerBase view : getViewersFor(apanel))
-    {
-      // TODO: highlight the view somehow
-      /*
-       * JAL-1742 exclude view with this structure already mapped (don't offer
-       * to align chain B to chain A of the same structure)
-       */
-      if (view.hasPdbId(pdbId))
-      {
-        continue;
-      }
-      int option = chooseAlignStructureToViewer(pdbId, view);
-      if (option == JvOptionPane.CANCEL_OPTION)
-      {
-        return true;
-      }
-      else if (option == JvOptionPane.YES_OPTION)
-      {
-        view.useAlignmentPanelForSuperposition(apanel);
-        view.addStructure(pdbentry, seq, chains, true, apanel.alignFrame);
-        return true;
-      }
-      else
-      {
-        // NO_OPTION - offer the next viewer if any
-      }
-    }
+    return Desktop.instance.getStructureViewers(alp, this.getClass());
+  }
 
+  @Override
+  public void addToExistingViewer(PDBEntry pdbentry, SequenceI[] seq,
+          String[] chains, final AlignmentViewPanel apanel, String pdbId)
+  {
     /*
-     * nothing offered and selected
+     * JAL-1742 exclude view with this structure already mapped (don't offer
+     * to align chain B to chain A of the same structure); code may defend
+     * against this possibility before we reach here
      */
-    return false;
+    if (hasPdbId(pdbId))
+    {
+      return;
+    }
+    AlignmentPanel alignPanel = (AlignmentPanel) apanel; // Implementation error if this
+                                                 // cast fails
+    useAlignmentPanelForSuperposition(alignPanel);
+    addStructure(pdbentry, seq, chains, alignPanel.alignFrame);
   }
 
   /**
@@ -462,9 +438,12 @@ public abstract class StructureViewerBase extends GStructureViewer
    * @param apanel
    * @param pdbFilename
    */
-  protected void addSequenceMappingsToStructure(SequenceI[] seq,
-          String[] chains, final AlignmentPanel apanel, String pdbFilename)
+  public void addSequenceMappingsToStructure(SequenceI[] seq,
+          String[] chains, final AlignmentViewPanel alpanel,
+          String pdbFilename)
   {
+    AlignmentPanel apanel = (AlignmentPanel) alpanel;
+
     // TODO : Fix multiple seq to one chain issue here.
     /*
      * create the mappings
@@ -511,47 +490,20 @@ public abstract class StructureViewerBase extends GStructureViewer
     }
   }
 
-  /**
-   * Check if the PDB file is already loaded, if so offer to add it to the
-   * existing viewer
-   * 
-   * @param seq
-   * @param chains
-   * @param apanel
-   * @param pdbId
-   * @return true if the user chooses to add to a viewer, or to cancel entirely
-   */
-  protected boolean addAlreadyLoadedFile(SequenceI[] seq, String[] chains,
-          final AlignmentPanel apanel, String pdbId)
+  @Override
+  public boolean addAlreadyLoadedFile(SequenceI[] seq, String[] chains,
+          final AlignmentViewPanel apanel, String pdbId)
   {
-    boolean finished = false;
     String alreadyMapped = apanel.getStructureSelectionManager()
             .alreadyMappedToFile(pdbId);
 
-    if (alreadyMapped != null)
+    if (alreadyMapped == null)
     {
-      /*
-       * the PDB file is already loaded
-       */
-      int option = JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
-              MessageManager.formatMessage(
-                      "label.pdb_entry_is_already_displayed", new Object[]
-                      { pdbId }),
-              MessageManager.formatMessage(
-                      "label.map_sequences_to_visible_window", new Object[]
-                      { pdbId }),
-              JvOptionPane.YES_NO_CANCEL_OPTION);
-      if (option == JvOptionPane.CANCEL_OPTION)
-      {
-        finished = true;
-      }
-      else if (option == JvOptionPane.YES_OPTION)
-      {
-        addSequenceMappingsToStructure(seq, chains, apanel, alreadyMapped);
-        finished = true;
-      }
+      return false;
     }
-    return finished;
+
+    addSequenceMappingsToStructure(seq, chains, apanel, alreadyMapped);
+    return true;
   }
 
   void setChainMenuItems(List<String> chainNames)
@@ -831,11 +783,11 @@ public abstract class StructureViewerBase extends GStructureViewer
       int[] alm = new int[_alignwith.size()];
       int a = 0;
 
-      for (AlignmentPanel ap : _alignwith)
+      for (AlignmentPanel alignPanel : _alignwith)
       {
-        als[a] = ap.av.getAlignment();
+        als[a] = alignPanel.av.getAlignment();
         alm[a] = -1;
-        alc[a++] = ap.av.getAlignment().getHiddenColumns();
+        alc[a++] = alignPanel.av.getAlignment().getHiddenColumns();
       }
       reply = getBinding().superposeStructures(als, alm, alc);
       if (reply != null)
@@ -847,9 +799,9 @@ public abstract class StructureViewerBase extends GStructureViewer
     } catch (Exception e)
     {
       StringBuffer sp = new StringBuffer();
-      for (AlignmentPanel ap : _alignwith)
+      for (AlignmentPanel alignPanel : _alignwith)
       {
-        sp.append("'" + ap.alignFrame.getTitle() + "' ");
+        sp.append("'" + alignPanel.alignFrame.getTitle() + "' ");
       }
       Cache.log.info("Couldn't align structures with the " + sp.toString()
               + "associated alignment panels.", e);
@@ -913,9 +865,9 @@ public abstract class StructureViewerBase extends GStructureViewer
         }
       }
       // Set the colour using the current view for the associated alignframe
-      for (AlignmentPanel ap : _colourwith)
+      for (AlignmentPanel alignPanel : _colourwith)
       {
-        binding.colourBySequence(ap);
+        binding.colourBySequence(alignPanel);
       }
       seqColoursApplied = true;
     }
@@ -997,6 +949,7 @@ public abstract class StructureViewerBase extends GStructureViewer
   /**
    * Configures the title and menu items of the viewer panel.
    */
+  @Override
   public void updateTitleAndMenus()
   {
     AAStructureBindingModel binding = getBinding();
@@ -1039,6 +992,12 @@ public abstract class StructureViewerBase extends GStructureViewer
   }
 
   @Override
+  public String toString()
+  {
+    return getTitle();
+  }
+
+  @Override
   public boolean hasMapping()
   {
     if (worker != null && (addingStructures || _started))
@@ -1075,4 +1034,10 @@ public abstract class StructureViewerBase extends GStructureViewer
     return seqColoursApplied;
   }
 
+  @Override
+  public void raiseViewer()
+  {
+    toFront();
+  }
+
 }
index 9bcaa5a..a30be66 100644 (file)
@@ -29,6 +29,7 @@ import jalview.fts.service.pdb.PDBFTSRestClient;
 import jalview.gui.AlignmentPanel;
 import jalview.gui.Desktop;
 import jalview.gui.JvSwingUtils;
+import jalview.gui.StructureViewer;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
@@ -36,6 +37,7 @@ import java.awt.CardLayout;
 import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
+import java.awt.Font;
 import java.awt.GridLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ItemEvent;
@@ -70,6 +72,8 @@ import javax.swing.event.DocumentListener;
 import javax.swing.event.InternalFrameEvent;
 import javax.swing.table.TableColumn;
 
+import net.miginfocom.swing.MigLayout;
+
 @SuppressWarnings("serial")
 /**
  * GUI layout for structure chooser
@@ -80,12 +84,23 @@ import javax.swing.table.TableColumn;
 public abstract class GStructureChooser extends JPanel
         implements ItemListener
 {
+  private static final Font VERDANA_12 = new Font("Verdana", 0, 12);
+
+  protected static final String VIEWS_FILTER = "VIEWS_FILTER";
+
+  protected static final String VIEWS_FROM_FILE = "VIEWS_FROM_FILE";
+
+  protected static final String VIEWS_ENTER_ID = "VIEWS_ENTER_ID";
+
+  /*
+   * 'cached' structure view
+   */
+  protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
+
   protected JPanel statusPanel = new JPanel();
 
   public JLabel statusBar = new JLabel();
 
-  private JPanel pnl_actionsAndStatus = new JPanel(new BorderLayout());
-
   protected String frameTitle = MessageManager
           .getString("label.structure_chooser");
 
@@ -97,41 +112,22 @@ public abstract class GStructureChooser extends JPanel
 
   protected StringBuilder errorWarning = new StringBuilder();
 
-  protected JLabel lbl_result = new JLabel(
-          MessageManager.getString("label.select"));
-
-  protected JButton btn_view = new JButton();
+  protected JButton btn_add;
 
-  protected JButton btn_cancel = new JButton();
+  protected JButton btn_newView;
 
   protected JButton btn_pdbFromFile = new JButton();
 
-  protected JTextField txt_search = new JTextField(14);
-
-  private JPanel pnl_actions = new JPanel();
-
-  private JPanel pnl_main = new JPanel();
-
-  private JPanel pnl_idInput = new JPanel(new FlowLayout());
+  protected JCheckBox chk_superpose = new JCheckBox(
+          MessageManager.getString("label.superpose_structures"));
 
-  private JPanel pnl_fileChooser = new JPanel(new FlowLayout());
-
-  private JPanel pnl_idInputBL = new JPanel(new BorderLayout());
-
-  private JPanel pnl_fileChooserBL = new JPanel(new BorderLayout());
-
-  private JPanel pnl_locPDB = new JPanel(new BorderLayout());
+  protected JTextField txt_search = new JTextField(14);
 
   protected JPanel pnl_switchableViews = new JPanel(new CardLayout());
 
   protected CardLayout layout_switchableViews = (CardLayout) (pnl_switchableViews
           .getLayout());
 
-  private BorderLayout mainLayout = new BorderLayout();
-
-  protected JCheckBox chk_rememberSettings = new JCheckBox(
-          MessageManager.getString("label.dont_ask_me_again"));
-
   protected JCheckBox chk_invertFilter = new JCheckBox(
           MessageManager.getString("label.invert"));
 
@@ -147,33 +143,20 @@ public abstract class GStructureChooser extends JPanel
   protected ImageIcon warningImage = new ImageIcon(
           getClass().getResource("/images/warning.gif"));
 
-  protected JLabel lbl_warning = new JLabel(warningImage);
-
   protected JLabel lbl_loading = new JLabel(loadingImage);
 
   protected JLabel lbl_pdbManualFetchStatus = new JLabel(errorImage);
 
   protected JLabel lbl_fromFileStatus = new JLabel(errorImage);
 
-  protected AssciateSeqPanel idInputAssSeqPanel = new AssciateSeqPanel();
-
-  protected AssciateSeqPanel fileChooserAssSeqPanel = new AssciateSeqPanel();
-
-  protected static final String VIEWS_FILTER = "VIEWS_FILTER";
+  protected AssociateSeqPanel idInputAssSeqPanel = new AssociateSeqPanel();
 
-  protected static final String VIEWS_FROM_FILE = "VIEWS_FROM_FILE";
+  protected AssociateSeqPanel fileChooserAssSeqPanel = new AssociateSeqPanel();
 
-  protected static final String VIEWS_ENTER_ID = "VIEWS_ENTER_ID";
-
-  /**
-   * 'cached' structure view
-   */
-  protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
+  protected JComboBox<StructureViewer> targetView = new JComboBox<>();
 
   protected JTable tbl_local_pdb = new JTable();
 
-  protected JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
-
   protected JTabbedPane pnl_filter = new JTabbedPane();
 
   protected FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences(
@@ -262,8 +245,6 @@ public abstract class GStructureChooser extends JPanel
     }
   };
 
-  protected JScrollPane scrl_foundStructures = new JScrollPane(tbl_summary);
-
   public GStructureChooser()
   {
     try
@@ -319,9 +300,9 @@ public abstract class GStructureChooser extends JPanel
           mainFrame.dispose();
           break;
         case KeyEvent.VK_ENTER: // enter key
-          if (btn_view.isEnabled())
+          if (btn_add.isEnabled())
           {
-            ok_ActionPerformed();
+            add_ActionPerformed();
           }
           break;
         case KeyEvent.VK_TAB: // tab key
@@ -331,7 +312,7 @@ public abstract class GStructureChooser extends JPanel
           }
           else
           {
-            btn_view.requestFocus();
+            btn_add.requestFocus();
           }
           evt.consume();
           break;
@@ -340,6 +321,30 @@ public abstract class GStructureChooser extends JPanel
         }
       }
     });
+
+    JButton btn_cancel = new JButton(
+            MessageManager.getString("action.cancel"));
+    btn_cancel.setFont(VERDANA_12);
+    btn_cancel.addActionListener(new java.awt.event.ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        closeAction(pnl_filter.getHeight());
+      }
+    });
+    btn_cancel.addKeyListener(new KeyAdapter()
+    {
+      @Override
+      public void keyPressed(KeyEvent evt)
+      {
+        if (evt.getKeyCode() == KeyEvent.VK_ENTER)
+        {
+          closeAction(pnl_filter.getHeight());
+        }
+      }
+    });
+
     tbl_local_pdb.setAutoCreateRowSorter(true);
     tbl_local_pdb.getTableHeader().setReorderingAllowed(false);
     tbl_local_pdb.addMouseListener(new MouseAdapter()
@@ -368,9 +373,9 @@ public abstract class GStructureChooser extends JPanel
           mainFrame.dispose();
           break;
         case KeyEvent.VK_ENTER: // enter key
-          if (btn_view.isEnabled())
+          if (btn_add.isEnabled())
           {
-            ok_ActionPerformed();
+            add_ActionPerformed();
           }
           break;
         case KeyEvent.VK_TAB: // tab key
@@ -380,9 +385,9 @@ public abstract class GStructureChooser extends JPanel
           }
           else
           {
-            if (btn_view.isEnabled())
+            if (btn_add.isEnabled())
             {
-              btn_view.requestFocus();
+              btn_add.requestFocus();
             }
             else
             {
@@ -396,51 +401,52 @@ public abstract class GStructureChooser extends JPanel
         }
       }
     });
-    btn_view.setFont(new java.awt.Font("Verdana", 0, 12));
-    btn_view.setText(MessageManager.getString("action.view"));
-    btn_view.addActionListener(new java.awt.event.ActionListener()
+
+    btn_newView = new JButton(MessageManager.getString("action.new_view"));
+    btn_newView.setFont(VERDANA_12);
+    btn_newView.addActionListener(new java.awt.event.ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        ok_ActionPerformed();
+        newView_ActionPerformed();
       }
     });
-    btn_view.addKeyListener(new KeyAdapter()
+    btn_newView.addKeyListener(new KeyAdapter()
     {
       @Override
       public void keyPressed(KeyEvent evt)
       {
         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
         {
-          ok_ActionPerformed();
+          newView_ActionPerformed();
         }
       }
     });
 
-    btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12));
-    btn_cancel.setText(MessageManager.getString("action.cancel"));
-    btn_cancel.addActionListener(new java.awt.event.ActionListener()
+    btn_add = new JButton(MessageManager.getString("action.add"));
+    btn_add.setFont(VERDANA_12);
+    btn_add.addActionListener(new java.awt.event.ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        closeAction(pnl_filter.getHeight());
+        add_ActionPerformed();
       }
     });
-    btn_cancel.addKeyListener(new KeyAdapter()
+    btn_add.addKeyListener(new KeyAdapter()
     {
       @Override
       public void keyPressed(KeyEvent evt)
       {
         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
         {
-          closeAction(pnl_filter.getHeight());
+          add_ActionPerformed();
         }
       }
     });
 
-    btn_pdbFromFile.setFont(new java.awt.Font("Verdana", 0, 12));
+    btn_pdbFromFile.setFont(VERDANA_12);
     String btn_title = MessageManager.getString("label.select_pdb_file");
     btn_pdbFromFile.setText(btn_title + "              ");
     btn_pdbFromFile.addActionListener(new java.awt.event.ActionListener()
@@ -463,20 +469,17 @@ public abstract class GStructureChooser extends JPanel
       }
     });
 
+    JScrollPane scrl_foundStructures = new JScrollPane(tbl_summary);
     scrl_foundStructures.setPreferredSize(new Dimension(width, height));
 
+    JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
     scrl_localPDB.setPreferredSize(new Dimension(width, height));
     scrl_localPDB.setHorizontalScrollBarPolicy(
             JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
 
-    cmb_filterOption.setFont(new java.awt.Font("Verdana", 0, 12));
-    chk_invertFilter.setFont(new java.awt.Font("Verdana", 0, 12));
-    chk_rememberSettings.setFont(new java.awt.Font("Verdana", 0, 12));
-    chk_rememberSettings.setVisible(false);
+    chk_invertFilter.setFont(VERDANA_12);
     txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
             MessageManager.getString("label.enter_pdb_id_tip")));
-    cmb_filterOption.setToolTipText(
-            MessageManager.getString("info.select_filter_option"));
     txt_search.getDocument().addDocumentListener(new DocumentListener()
     {
       @Override
@@ -498,8 +501,10 @@ public abstract class GStructureChooser extends JPanel
       }
     });
 
+    cmb_filterOption.setFont(VERDANA_12);
+    cmb_filterOption.setToolTipText(
+            MessageManager.getString("info.select_filter_option"));
     cmb_filterOption.addItemListener(this);
-
     // add CustomComboSeparatorsRenderer to filter option combo-box
     cmb_filterOption.setRenderer(new CustomComboSeparatorsRenderer(
             (ListCellRenderer<Object>) cmb_filterOption.getRenderer())
@@ -514,23 +519,33 @@ public abstract class GStructureChooser extends JPanel
 
     chk_invertFilter.addItemListener(this);
 
-    pnl_actions.add(chk_rememberSettings);
-    pnl_actions.add(btn_view);
-    pnl_actions.add(btn_cancel);
+    targetView.setVisible(false);
 
-    // pnl_filter.add(lbl_result);
+    JPanel actionsPanel = new JPanel(new MigLayout());
+    actionsPanel.add(targetView, "left");
+    actionsPanel.add(btn_add, "wrap");
+    actionsPanel.add(chk_superpose, "left");
+    actionsPanel.add(btn_newView);
+    actionsPanel.add(btn_cancel, "right");
+
+    JPanel pnl_main = new JPanel();
     pnl_main.add(cmb_filterOption);
     pnl_main.add(lbl_loading);
     pnl_main.add(chk_invertFilter);
     lbl_loading.setVisible(false);
 
+    JPanel pnl_fileChooser = new JPanel(new FlowLayout());
     pnl_fileChooser.add(btn_pdbFromFile);
     pnl_fileChooser.add(lbl_fromFileStatus);
+    JPanel pnl_fileChooserBL = new JPanel(new BorderLayout());
     pnl_fileChooserBL.add(fileChooserAssSeqPanel, BorderLayout.NORTH);
     pnl_fileChooserBL.add(pnl_fileChooser, BorderLayout.CENTER);
 
+    JPanel pnl_idInput = new JPanel(new FlowLayout());
     pnl_idInput.add(txt_search);
     pnl_idInput.add(lbl_pdbManualFetchStatus);
+
+    JPanel pnl_idInputBL = new JPanel(new BorderLayout());
     pnl_idInputBL.add(idInputAssSeqPanel, BorderLayout.NORTH);
     pnl_idInputBL.add(pnl_idInput, BorderLayout.CENTER);
 
@@ -546,13 +561,15 @@ public abstract class GStructureChooser extends JPanel
         JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
                 .getSource();
         int index = sourceTabbedPane.getSelectedIndex();
-        btn_view.setVisible(true);
+        btn_add.setVisible(targetView.isVisible());
+        btn_newView.setVisible(true);
         btn_cancel.setVisible(true);
         if (sourceTabbedPane.getTitleAt(index).equals(configureCols))
         {
-          btn_view.setEnabled(false);
+          btn_add.setEnabled(false);
           btn_cancel.setEnabled(false);
-          btn_view.setVisible(false);
+          btn_add.setVisible(false);
+          btn_newView.setEnabled(false);
           btn_cancel.setVisible(false);
           previousWantedFields = pdbDocFieldPrefs
                   .getStructureSummaryFields()
@@ -578,6 +595,7 @@ public abstract class GStructureChooser extends JPanel
     pnl_filter.add(foundStructureSummary, scrl_foundStructures);
     pnl_filter.add(configureCols, pdbDocFieldPrefs);
 
+    JPanel pnl_locPDB = new JPanel(new BorderLayout());
     pnl_locPDB.add(scrl_localPDB);
 
     pnl_switchableViews.add(pnl_fileChooserBL, VIEWS_FROM_FILE);
@@ -585,12 +603,14 @@ public abstract class GStructureChooser extends JPanel
     pnl_switchableViews.add(pnl_filter, VIEWS_FILTER);
     pnl_switchableViews.add(pnl_locPDB, VIEWS_LOCAL_PDB);
 
-    this.setLayout(mainLayout);
+    this.setLayout(new BorderLayout());
     this.add(pnl_main, java.awt.BorderLayout.NORTH);
     this.add(pnl_switchableViews, java.awt.BorderLayout.CENTER);
     // this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
     statusPanel.setLayout(new GridLayout());
-    pnl_actionsAndStatus.add(pnl_actions, BorderLayout.CENTER);
+
+    JPanel pnl_actionsAndStatus = new JPanel(new BorderLayout());
+    pnl_actionsAndStatus.add(actionsPanel, BorderLayout.CENTER);
     pnl_actionsAndStatus.add(statusPanel, BorderLayout.SOUTH);
     statusPanel.add(statusBar, null);
     this.add(pnl_actionsAndStatus, java.awt.BorderLayout.SOUTH);
@@ -801,13 +821,13 @@ public abstract class GStructureChooser extends JPanel
    * @author tcnofoegbu
    *
    */
-  public class AssciateSeqPanel extends JPanel implements ItemListener
+  public class AssociateSeqPanel extends JPanel implements ItemListener
   {
     private JComboBox<AssociateSeqOptions> cmb_assSeq = new JComboBox<>();
 
     private JLabel lbl_associateSeq = new JLabel();
 
-    public AssciateSeqPanel()
+    public AssociateSeqPanel()
     {
       this.setLayout(new FlowLayout());
       this.add(cmb_assSeq);
@@ -901,19 +921,21 @@ public abstract class GStructureChooser extends JPanel
 
   protected abstract void stateChanged(ItemEvent e);
 
-  protected abstract void ok_ActionPerformed();
+  protected abstract void add_ActionPerformed();
+
+  protected abstract void newView_ActionPerformed();
 
   protected abstract void pdbFromFile_actionPerformed();
 
   protected abstract void txt_search_ActionPerformed();
 
-  public abstract void populateCmbAssociateSeqOptions(
+  protected abstract void populateCmbAssociateSeqOptions(
           JComboBox<AssociateSeqOptions> cmb_assSeq,
           JLabel lbl_associateSeq);
 
-  public abstract void cmbAssSeqStateChanged();
+  protected abstract void cmbAssSeqStateChanged();
 
-  public abstract void tabRefresh();
+  protected abstract void tabRefresh();
 
-  public abstract void validateSelections();
+  protected abstract void validateSelections();
 }
\ No newline at end of file
index fcf322d..4174f5b 100644 (file)
@@ -30,6 +30,12 @@ import java.util.List;
 
 public class StructureMapping
 {
+  public static final int UNASSIGNED_VALUE = Integer.MIN_VALUE;
+
+  private static final int PDB_RES_NUM_INDEX = 0;
+
+  private static final int PDB_ATOM_NUM_INDEX = 1;
+
   String mappingDetails;
 
   SequenceI sequence;
@@ -40,17 +46,12 @@ public class StructureMapping
 
   String pdbchain;
 
-  public static final int UNASSIGNED_VALUE = Integer.MIN_VALUE;
-
-  private static final int PDB_RES_NUM_INDEX = 0;
-
-  private static final int PDB_ATOM_NUM_INDEX = 1;
-
   // Mapping key is residue index while value is an array containing PDB resNum,
   // and atomNo
   HashMap<Integer, int[]> mapping;
 
   jalview.datamodel.Mapping seqToPdbMapping = null;
+
   /**
    * Constructor
    * 
@@ -145,7 +146,7 @@ public class StructureMapping
    */
   public List<int[]> getPDBResNumRanges(int fromSeqPos, int toSeqPos)
   {
-    List<int[]> result = new ArrayList<int[]>();
+    List<int[]> result = new ArrayList<>();
     int startRes = -1;
     int endRes = -1;
 
@@ -263,4 +264,105 @@ public class StructureMapping
   {
     return seqToPdbMapping;
   }
+
+  /**
+   * A hash function that satisfies the contract that if two mappings are
+   * equal(), they have the same hashCode
+   */
+  @Override
+  public int hashCode()
+  {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result
+            + ((mappingDetails == null) ? 0 : mappingDetails.hashCode());
+    result = prime * result
+            + ((pdbchain == null) ? 0 : pdbchain.hashCode());
+    result = prime * result + ((pdbfile == null) ? 0 : pdbfile.hashCode());
+    result = prime * result + ((pdbid == null) ? 0 : pdbid.hashCode());
+    result = prime * result
+            + ((seqToPdbMapping == null) ? 0 : seqToPdbMapping.hashCode());
+    result = prime * result
+            + ((sequence == null) ? 0 : sequence.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object obj)
+  {
+    if (this == obj)
+    {
+      return true;
+    }
+    if (obj == null)
+    {
+      return false;
+    }
+    if (getClass() != obj.getClass())
+    {
+      return false;
+    }
+    StructureMapping other = (StructureMapping) obj;
+    if (mappingDetails == null)
+    {
+      if (other.mappingDetails != null)
+      {
+        return false;
+      }
+    }
+    else if (!mappingDetails.equals(other.mappingDetails))
+    {
+      return false;
+    }
+    if (pdbchain == null)
+    {
+      if (other.pdbchain != null)
+      {
+        return false;
+      }
+    }
+    else if (!pdbchain.equals(other.pdbchain))
+    {
+      return false;
+    }
+    if (pdbfile == null)
+    {
+      if (other.pdbfile != null)
+      {
+        return false;
+      }
+    }
+    else if (!pdbfile.equals(other.pdbfile))
+    {
+      return false;
+    }
+    if (pdbid == null)
+    {
+      if (other.pdbid != null)
+      {
+        return false;
+      }
+    }
+    else if (!pdbid.equals(other.pdbid))
+    {
+      return false;
+    }
+    if (seqToPdbMapping == null)
+    {
+      if (other.seqToPdbMapping != null)
+      {
+        return false;
+      }
+    }
+    else if (!seqToPdbMapping.equals(other.seqToPdbMapping))
+    {
+      return false;
+    }
+    if (sequence != other.sequence)
+    {
+      return false;
+    }
+
+    return true;
+  }
 }
index 10fe836..ad259fd 100644 (file)
@@ -285,7 +285,8 @@ public class StructureSelectionManager
   }
 
   /**
-   * Returns the file name for a mapped PDB id (or null if not mapped).
+   * Returns the filename the PDB id is already mapped to if known, or null if
+   * it is not mapped
    * 
    * @param pdbid
    * @return
@@ -294,7 +295,7 @@ public class StructureSelectionManager
   {
     for (StructureMapping sm : mappings)
     {
-      if (sm.getPdbId().equals(pdbid))
+      if (sm.getPdbId().equalsIgnoreCase(pdbid))
       {
         return sm.pdbfile;
       }
@@ -572,6 +573,13 @@ public class StructureSelectionManager
             {
               System.err.println(e.getMessage());
             }
+            catch (Exception e)
+            {
+              System.err
+                      .println(
+                              "Unexpected exception during SIFTS mapping - falling back to NW for this sequence/structure pair");
+              System.err.println(e.getMessage());
+            }
           }
           if (!foundSiftsMappings.isEmpty())
           {
@@ -605,7 +613,10 @@ public class StructureSelectionManager
       }
       if (forStructureView)
       {
-        mappings.addAll(seqToStrucMapping);
+        for (StructureMapping sm : seqToStrucMapping)
+        {
+          addStructureMapping(sm); // not addAll!
+        }
       }
       if (progress != null)
       {
@@ -657,7 +668,10 @@ public class StructureSelectionManager
 
   public void addStructureMapping(StructureMapping sm)
   {
-    mappings.add(sm);
+    if (!mappings.contains(sm))
+    {
+      mappings.add(sm);
+    }
   }
 
   /**
index 81b9964..60054f1 100644 (file)
@@ -116,8 +116,17 @@ public class MapList
   {
     int hashCode = 31 * fromRatio;
     hashCode = 31 * hashCode + toRatio;
-    hashCode = 31 * hashCode + fromShifts.toArray().hashCode();
-    hashCode = 31 * hashCode + toShifts.toArray().hashCode();
+    for (int[] shift : fromShifts)
+    {
+      hashCode = 31 * hashCode + shift[0];
+      hashCode = 31 * hashCode + shift[1];
+    }
+    for (int[] shift : toShifts)
+    {
+      hashCode = 31 * hashCode + shift[0];
+      hashCode = 31 * hashCode + shift[1];
+    }
+
     return hashCode;
   }
 
index defcdbc..533c0af 100644 (file)
@@ -91,7 +91,7 @@ public class PDBChainTest
     a3.resName = "ASP";
     a3.resNumber = 41;
 
-    Vector<Bond> v = new Vector<Bond>();
+    Vector<Bond> v = new Vector<>();
     v.add(new Bond(a1, a2));
     v.add(new Bond(a2, a3));
     v.add(new Bond(a3, a1));
@@ -234,7 +234,7 @@ public class PDBChainTest
   @Test(groups = { "Functional" })
   public void testMakeResidueList_noAnnotation()
   {
-    Vector<Atom> atoms = new Vector<Atom>();
+    Vector<Atom> atoms = new Vector<>();
     c.atoms = atoms;
     c.isNa = true;
     atoms.add(makeAtom(4, "N", "MET"));
@@ -292,7 +292,7 @@ public class PDBChainTest
   @Test(groups = { "Functional" })
   public void testMakeResidueList_withTempFactor()
   {
-    Vector<Atom> atoms = new Vector<Atom>();
+    Vector<Atom> atoms = new Vector<>();
     c.atoms = atoms;
     atoms.add(makeAtom(4, "N", "MET"));
     atoms.get(atoms.size() - 1).tfactor = 1f;
@@ -307,7 +307,7 @@ public class PDBChainTest
     atoms.add(makeAtom(5, "CA", "LYS"));
     atoms.get(atoms.size() - 1).tfactor = 9f;
     atoms.add(makeAtom(6, "O", "LEU"));
-    atoms.get(atoms.size() - 1).tfactor = 4f;
+    atoms.get(atoms.size() - 1).tfactor = -4f;
     atoms.add(makeAtom(6, "N", "LEU"));
     atoms.get(atoms.size() - 1).tfactor = 5f;
     atoms.add(makeAtom(6, "CA", "LEU"));
@@ -320,7 +320,7 @@ public class PDBChainTest
 
     /*
      * Verify annotations; note the tempFactor is read from the first atom in
-     * each residue i.e. we expect values 1, 7, 4 for the residues
+     * each residue i.e. we expect values 1, 7, -4 for the residues
      */
     AlignmentAnnotation[] ann = c.sequence.getAnnotation();
     assertEquals(1, ann.length);
@@ -328,12 +328,12 @@ public class PDBChainTest
     assertEquals("Temperature Factor for 1gaqA", ann[0].description);
     assertSame(c.sequence, ann[0].sequenceRef);
     assertEquals(AlignmentAnnotation.LINE_GRAPH, ann[0].graph);
-    assertEquals(0f, ann[0].graphMin, 0.001f);
+    assertEquals(-4f, ann[0].graphMin, 0.001f);
     assertEquals(7f, ann[0].graphMax, 0.001f);
     assertEquals(3, ann[0].annotations.length);
     assertEquals(1f, ann[0].annotations[0].value, 0.001f);
     assertEquals(7f, ann[0].annotations[1].value, 0.001f);
-    assertEquals(4f, ann[0].annotations[2].value, 0.001f);
+    assertEquals(-4f, ann[0].annotations[2].value, 0.001f);
   }
 
   /**
@@ -344,7 +344,7 @@ public class PDBChainTest
   public void testMakeCaBondList()
   {
     c.isNa = true;
-    Vector<Atom> atoms = new Vector<Atom>();
+    Vector<Atom> atoms = new Vector<>();
     c.atoms = atoms;
     atoms.add(makeAtom(4, "N", "MET"));
     atoms.add(makeAtom(4, "CA", "MET"));
@@ -375,7 +375,7 @@ public class PDBChainTest
   public void testMakeCaBondList_nucleotide()
   {
     c.isNa = false;
-    Vector<Atom> atoms = new Vector<Atom>();
+    Vector<Atom> atoms = new Vector<>();
     c.atoms = atoms;
     atoms.add(makeAtom(4, "N", "G"));
     atoms.add(makeAtom(4, "P", "G"));
@@ -406,7 +406,7 @@ public class PDBChainTest
   @Test(groups = { "Functional" })
   public void testMakeExactMapping()
   {
-    Vector<Atom> atoms = new Vector<Atom>();
+    Vector<Atom> atoms = new Vector<>();
     c.atoms = atoms;
     atoms.add(makeAtom(4, "N", "MET"));
     atoms.add(makeAtom(4, "CA", "MET"));
index e47c787..686cd2f 100644 (file)
@@ -23,7 +23,7 @@ public class FeatureAttributesTest
   /**
    * clear down attributes map before tests
    */
-  @BeforeClass
+  @BeforeClass(alwaysRun = true)
   public void setUp()
   {
     FeatureAttributes fa = FeatureAttributes.getInstance();
@@ -33,7 +33,7 @@ public class FeatureAttributesTest
   /**
    * clear down attributes map after tests
    */
-  @AfterMethod
+  @AfterMethod(alwaysRun = true)
   public void tearDown()
   {
     FeatureAttributes fa = FeatureAttributes.getInstance();
index 792f7ad..e451ed2 100644 (file)
  */
 package jalview.ext.jmol;
 
+import static org.junit.Assert.assertNotNull;
+import static org.testng.Assert.assertEquals;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.Cache;
 import jalview.bin.Jalview;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.JvOptionPane;
@@ -32,6 +36,10 @@ import jalview.gui.Preferences;
 import jalview.gui.StructureViewer;
 import jalview.gui.StructureViewer.ViewerType;
 import jalview.io.DataSourceType;
+import jalview.io.FileFormat;
+import jalview.io.FileLoader;
+
+import java.lang.reflect.InvocationTargetException;
 
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -54,8 +62,10 @@ public class JmolViewerTest
   @BeforeClass(alwaysRun = true)
   public static void setUpBeforeClass() throws Exception
   {
-    Jalview.main(new String[] { "-noquestionnaire", "-nonews", "-props",
-        "test/jalview/ext/rbvi/chimera/testProps.jvprops" });
+    Jalview.main(
+            new String[]
+            { "-noquestionnaire", "-nonews", "-props",
+                "test/jalview/ext/rbvi/chimera/testProps.jvprops" });
   }
 
   /**
@@ -70,10 +80,11 @@ public class JmolViewerTest
   @Test(groups = { "Functional" })
   public void testSingleSeqViewJMol()
   {
-    Cache.setProperty(Preferences.STRUCTURE_DISPLAY, ViewerType.JMOL.name());
+    Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
+            ViewerType.JMOL.name());
     String inFile = "examples/1gaq.txt";
-    AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
-            inFile, DataSourceType.FILE);
+    AlignFrame af = new jalview.io.FileLoader()
+            .LoadFileWaitTillLoaded(inFile, DataSourceType.FILE);
     assertTrue("Didn't read input file " + inFile, af != null);
     for (SequenceI sq : af.getViewport().getAlignment().getSequences())
     {
@@ -87,13 +98,13 @@ public class JmolViewerTest
       {
         for (int q = 0; q < dsq.getAllPDBEntries().size(); q++)
         {
-          final StructureViewer structureViewer = new StructureViewer(af
-                  .getViewport().getStructureSelectionManager());
+          final StructureViewer structureViewer = new StructureViewer(
+                  af.getViewport().getStructureSelectionManager());
           structureViewer.setViewerType(ViewerType.JMOL);
           JalviewStructureDisplayI jmolViewer = structureViewer
                   .viewStructures(dsq.getAllPDBEntries().elementAt(q),
-                          new SequenceI[] { sq }, af.getCurrentView()
-                                  .getAlignPanel());
+                          new SequenceI[]
+                          { sq }, af.getCurrentView().getAlignPanel());
           /*
            * Wait for viewer load thread to complete
            */
@@ -116,5 +127,86 @@ public class JmolViewerTest
     }
   }
 
+  @Test(groups = { "Functional" })
+  public void testAddStrToSingleSeqViewJMol()
+          throws InvocationTargetException, InterruptedException
+  {
+    Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
+            ViewerType.JMOL.name());
+    String inFile = "examples/1gaq.txt";
+    AlignFrame af = new jalview.io.FileLoader(true)
+            .LoadFileWaitTillLoaded(inFile, DataSourceType.FILE);
+    assertTrue("Didn't read input file " + inFile, af != null);
+    // show a structure for 4th Sequence
+    SequenceI sq1 = af.getViewport().getAlignment().getSequences().get(0);
+    final StructureViewer structureViewer = new StructureViewer(
+            af.getViewport().getStructureSelectionManager());
+    structureViewer.setViewerType(ViewerType.JMOL);
+    JalviewStructureDisplayI jmolViewer = structureViewer.viewStructures(
+            sq1.getDatasetSequence().getAllPDBEntries().elementAt(0),
+            new SequenceI[]
+            { sq1 }, af.getCurrentView().getAlignPanel());
+    /*
+     * Wait for viewer load thread to complete
+     */
+    try
+    {
+      while (!jmolViewer.getBinding().isFinishedInit())
+      {
+        Thread.sleep(500);
+      }
+    } catch (InterruptedException e)
+    {
+    }
+
+    assertTrue(jmolViewer.isVisible());
+
+    // add another pdb file and add it to view
+    final String _inFile = "examples/3W5V.pdb";
+    inFile = _inFile;
+    FileLoader fl = new FileLoader();
+    fl.LoadFile(af.getCurrentView(), _inFile, DataSourceType.FILE,
+            FileFormat.PDB);
+    try
+    {
+      int time = 0;
+      do
+      {
+        Thread.sleep(50); // hope we can avoid race condition
+
+      } while (++time < 30
+              && af.getViewport().getAlignment().getHeight() == 3);
+    } catch (Exception q)
+    {
+    }
+    ;
+    assertTrue("Didn't paste additional structure" + inFile,
+            af.getViewport().getAlignment().getHeight() > 3);
+    SequenceI sq2 = af.getViewport().getAlignment().getSequenceAt(3);
+    PDBEntry pdbe = sq2.getDatasetSequence().getAllPDBEntries().get(0);
+    assertTrue(pdbe.getFile().contains(inFile));
+    structureViewer.viewStructures(pdbe, new SequenceI[] { sq2 },
+            af.alignPanel);
+    /*
+     * Wait for viewer load thread to complete
+     */
+    try
+    {
+      while (structureViewer.isBusy())
+      {
+        Thread.sleep(500);
+      }
+    } catch (InterruptedException e)
+    {
+    }
+    assertEquals(jmolViewer.getBinding().getPdbCount(), 2);
+    String mouseOverTest = "[GLY]293:A.CA/2.1 #2164";
+    ((JalviewJmolBinding) jmolViewer.getBinding()).mouseOverStructure(2164,
+            mouseOverTest);
+    SearchResultsI highlight = af.alignPanel.getSeqPanel()
+            .getLastSearchResults();
+    assertNotNull("Didn't find highlight from second structure mouseover",
+            highlight.getResults(sq2, sq2.getStart(), sq2.getEnd()));
+  }
 
 }
index 91fe602..f69e6b5 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.gui;
 
 import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.datamodel.DBRefEntry;
@@ -28,8 +29,10 @@ import jalview.datamodel.DBRefSource;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSData;
 import jalview.jbgui.GStructureChooser.FilterOption;
 
+import java.util.Collection;
 import java.util.Vector;
 
 import org.testng.annotations.AfterMethod;
@@ -37,6 +40,8 @@ import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import junit.extensions.PA;
+
 public class StructureChooserTest
 {
 
@@ -142,8 +147,10 @@ public class StructureChooserTest
     SequenceI[] selectedSeqs = new SequenceI[] { seq };
     StructureChooser sc = new StructureChooser(selectedSeqs, seq, null);
     sc.fetchStructuresMetaData();
-    assertTrue(sc.getDiscoveredStructuresSet() != null);
-    assertTrue(sc.getDiscoveredStructuresSet().size() > 0);
+    Collection<FTSData> ss = (Collection<FTSData>) PA.getValue(sc,
+            "discoveredStructuresSet");
+    assertNotNull(ss);
+    assertTrue(ss.size() > 0);
 
   }
 
index 9c5ab00..3a727b4 100644 (file)
@@ -260,6 +260,31 @@ public class Jalview2xmlTests extends Jalview2xmlBase
 
   }
 
+  /**
+   * Test for JAL-2223 - multiple mappings in View Mapping report
+   * 
+   * @throws Exception
+   */
+  @Test(groups = { "Functional" })
+  public void noDuplicatePdbMappingsMade() throws Exception
+  {
+    StructureImportSettings.setProcessSecondaryStructure(true);
+    StructureImportSettings.setVisibleChainAnnotation(true);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/exampleFile_2_7.jar", DataSourceType.FILE);
+    assertNotNull(af, "Didn't read in the example file correctly.");
+
+    // locate Jmol viewer
+    // count number of PDB mappings the structure selection manager holds -
+    String pdbFile = af.getCurrentView().getStructureSelectionManager()
+            .findFileForPDBId("1A70");
+    assertEquals(
+            af.getCurrentView().getStructureSelectionManager()
+                    .getMapping(pdbFile).length,
+            2, "Expected only two mappings for 1A70");
+
+  }
+
   @Test(groups = { "Functional" })
   public void viewRefPdbAnnotation() throws Exception
   {
index f26c5f1..036aeaa 100644 (file)
@@ -1,8 +1,14 @@
 package jalview.structure;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 
+import jalview.datamodel.Mapping;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.util.MapList;
+
 import java.util.HashMap;
 import java.util.List;
 
@@ -11,9 +17,9 @@ import org.testng.annotations.Test;
 public class StructureMappingTest
 {
   @Test(groups = "Functional")
-  public void testgetPDBResNumRanges()
+  public void testGetPDBResNumRanges()
   {
-    HashMap<Integer, int[]> map = new HashMap<Integer, int[]>();
+    HashMap<Integer, int[]> map = new HashMap<>();
 
     StructureMapping mapping = new StructureMapping(null, null, null, null,
             map, null);
@@ -43,4 +49,75 @@ public class StructureMappingTest
     assertEquals(ranges.get(1)[0], 15);
     assertEquals(ranges.get(1)[1], 15);
   }
+
+  @Test(groups = "Functional")
+  public void testEquals()
+  {
+    SequenceI seq1 = new Sequence("seq1", "ABCDE");
+    SequenceI seq2 = new Sequence("seq1", "ABCDE");
+    String pdbFile = "a/b/file1.pdb";
+    String pdbId = "1a70";
+    String chain = "A";
+    String mappingDetails = "these are the mapping details, honest";
+    HashMap<Integer, int[]> map = new HashMap<>();
+
+    Mapping seqToPdbMapping = new Mapping(seq1,
+            new MapList(new int[]
+            { 1, 5 }, new int[] { 2, 6 }, 1, 1));
+    StructureMapping sm1 = new StructureMapping(seq1, pdbFile, pdbId, chain,
+            map, mappingDetails, seqToPdbMapping);
+    assertFalse(sm1.equals(null));
+    assertFalse(sm1.equals("x"));
+
+    StructureMapping sm2 = new StructureMapping(seq1, pdbFile, pdbId, chain,
+            map, mappingDetails, seqToPdbMapping);
+    assertTrue(sm1.equals(sm2));
+    assertTrue(sm2.equals(sm1));
+    assertEquals(sm1.hashCode(), sm2.hashCode());
+
+    // with different sequence
+    sm2 = new StructureMapping(seq2, pdbFile, pdbId, chain, map,
+            mappingDetails, seqToPdbMapping);
+    assertFalse(sm1.equals(sm2));
+    assertFalse(sm2.equals(sm1));
+
+    // with different file
+    sm2 = new StructureMapping(seq1, "a/b/file2.pdb", pdbId, chain, map,
+            mappingDetails, seqToPdbMapping);
+    assertFalse(sm1.equals(sm2));
+    assertFalse(sm2.equals(sm1));
+
+    // with different pdbid (case sensitive)
+    sm2 = new StructureMapping(seq1, pdbFile, "1A70", chain, map,
+            mappingDetails, seqToPdbMapping);
+    assertFalse(sm1.equals(sm2));
+    assertFalse(sm2.equals(sm1));
+
+    // with different chain
+    sm2 = new StructureMapping(seq1, pdbFile, pdbId, "B", map,
+            mappingDetails, seqToPdbMapping);
+    assertFalse(sm1.equals(sm2));
+    assertFalse(sm2.equals(sm1));
+
+    // map is ignore for this test
+    sm2 = new StructureMapping(seq1, pdbFile, pdbId, chain, null,
+            mappingDetails, seqToPdbMapping);
+    assertTrue(sm1.equals(sm2));
+    assertTrue(sm2.equals(sm1));
+
+    // with different mapping details
+    sm2 = new StructureMapping(seq1, pdbFile, pdbId, chain, map,
+            "different details!", seqToPdbMapping);
+    assertFalse(sm1.equals(sm2));
+    assertFalse(sm2.equals(sm1));
+
+    // with different seq to pdb mapping
+    Mapping map2 = new Mapping(seq1,
+            new MapList(new int[]
+            { 1, 5 }, new int[] { 3, 7 }, 1, 1));
+    sm2 = new StructureMapping(seq1, pdbFile, pdbId, chain, map,
+            mappingDetails, map2);
+    assertFalse(sm1.equals(sm2));
+    assertFalse(sm2.equals(sm1));
+  }
 }
index fd68e96..cd3e124 100644 (file)
@@ -391,7 +391,9 @@ public class MapListTest
     MapList ml7 = new MapList(codons, protein, 3, 1); // toShifts differ
 
     assertTrue(ml.equals(ml));
+    assertEquals(ml.hashCode(), ml.hashCode());
     assertTrue(ml.equals(ml1));
+    assertEquals(ml.hashCode(), ml1.hashCode());
     assertTrue(ml1.equals(ml));
 
     assertFalse(ml.equals(null));
index a649cb4..20726f5 100755 (executable)
@@ -2320,6 +2320,58 @@ and any path to a file to save to the file]]></string>
                                                </object>
                                        </method>
                                        <method name="addElement">
+            <object class="com.zerog.ia.installer.actions.InstallZipfile" objectID="9a1f46efeef911a">
+              <property name="belongsToUninstallPhase">
+                <boolean>false</boolean>
+              </property>
+              <property name="rollbackEnabledCancel">
+                <boolean>true</boolean>
+              </property>
+              <property name="rollbackEnabledError">
+                <boolean>true</boolean>
+              </property>
+              <property name="ruleExpression">
+                <string><![CDATA[]]></string>
+              </property>
+              <property name="unixPermissions">
+                <string><![CDATA[664]]></string>
+              </property>
+              <property name="sourceName">
+                <string><![CDATA[VAqua4.jar]]></string>
+              </property>
+              <property name="overrideUnixPermissions">
+                <boolean>false</boolean>
+              </property>
+              <property name="sourcePath">
+                <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+              </property>
+              <property name="shouldUninstall">
+                <boolean>true</boolean>
+              </property>
+              <property name="rollbackEnabledCancel">
+                <boolean>true</boolean>
+              </property>
+              <property name="rollbackEnabledError">
+                <boolean>true</boolean>
+              </property>
+              <property name="destinationName">
+                <string><![CDATA[VAqua4.jar]]></string>
+              </property>
+              <property name="fileSize">
+                <long>1355141</long>
+              </property>
+              <property name="macBinary">
+                <boolean>false</boolean>
+              </property>
+              <property name="targetCheckKind">
+                <int>0</int>
+              </property>
+              <property name="ruleExpression">
+                <string><![CDATA[]]></string>
+              </property>
+            </object>
+          </method>
+          <method name="addElement">
                                                <object class="com.zerog.ia.installer.actions.InstallZipfile" objectID="1936efeefab93">
                                                        <property name="belongsToUninstallPhase">
                                                                <boolean>false</boolean>
@@ -7230,6 +7282,7 @@ and any path to a file to read from that file]]></string>
                                                                                <object refID="24485f8ca673"/>
                                                                                <object refID="24485f8ba674"/>
                                                                                <object refID="24485f8ca674"/>
+                                                                               <object refID="9a1f46efeef911a"/>
                                                                                <object class="com.zerog.ia.installer.actions.CreateShortcut" objectID="3cd8e2ffa672">
                                                                                        <property name="belongsToUninstallPhase">
                                                                                                <boolean>false</boolean>
@@ -7981,6 +8034,7 @@ and any path to a file to read from that file]]></string>
                                                                                                <object refID="24485f8ca673"/>
                                                                                                <object refID="24485f8ba674"/>
                                                                                                <object refID="24485f8ca674"/>
+                                                                                               <object refID="9a1f46efeef911a"/>
                                                                                                <object refID="b1a16838a449"/>
                                                                                                <object refID="b1a16839a449"/>
                                                                                                <object refID="495aeddb8b3d"/>