Merge branch 'develop' into features/JAL-2068groovyAnnotationWorker features/JAL-2068groovyAnnotationWorker
authorJim Procter <jprocter@issues.jalview.org>
Mon, 20 Jun 2016 11:12:29 +0000 (12:12 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Mon, 20 Jun 2016 11:12:29 +0000 (12:12 +0100)
fun fact: Jalview.getCurrentAlignFrame() should be used in place of Desktop.getCurrentAlignFrame() now

188 files changed:
.classpath
build.xml
doc/AddingGroovySupport.html
doc/building.html
examples/appletDeployment.html
examples/appletParameters.html
examples/exampleFeatures.txt
examples/groovy/featureCounter.groovy
examples/groovy/printtitle.groovy
examples/plantfdx.features
examples/testdata/test.html
help/html/calculations/consensus.html
help/html/calculations/conservation.html
help/html/features/annotation.html
help/html/features/annotationsFormat.html
help/html/features/bioJsonFormat.html
help/html/features/featuresettings.html
help/html/features/groovy.html
help/html/features/mmcif.html [new file with mode: 0644]
help/html/features/seqmappings.html
help/html/features/sifts_mapping_output.png [new file with mode: 0644]
help/html/features/siftsmapping.html [new file with mode: 0644]
help/html/features/splitView.html
help/html/features/uniprotqueryfields.html [new file with mode: 0644]
help/html/features/uniprotseqfetcher.png [new file with mode: 0644]
help/html/features/uniprotsequencefetcher.html [new file with mode: 0644]
help/html/features/viewingpdbs.html
help/html/keys.html
help/html/menus/desktopMenu.html
help/html/menus/popupMenu.html
help/html/releases.html
help/html/webServices/AACon.html
help/html/webServices/index.html
help/html/webServices/msaclient.html
help/html/webServices/urllinks.html
lib/Jmol-14.2.14_2015.06.11.jar
lib/VARNAv3-93.jar
lib/castor-1.1-cycle-xml.jar
lib/groovy-all-1.8.2.jar [deleted file]
lib/groovy-all-2.4.6-indy.jar [new file with mode: 0644]
lib/min-jabaws-client-2.1.0.jar
lib/quaqua-filechooser-only-8.0.jar
lib/xercesImpl.jar [changed mode: 0755->0644]
resources/embl_mapping.xml
resources/fts/pdb_data_columns.txt [moved from resources/fts/pdb_data_columns.conf with 75% similarity]
resources/fts/uniprot_data_columns.txt [moved from resources/fts/uniprot_data_columns.conf with 74% similarity]
resources/images/blank_16x16_placeholder.png [new file with mode: 0644]
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/MCview/PDBViewer.java
src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java
src/jalview/analysis/AlignmentUtils.java
src/jalview/analysis/Conservation.java
src/jalview/analysis/CrossRef.java
src/jalview/analysis/SequenceIdMatcher.java
src/jalview/api/AlignViewControllerI.java
src/jalview/api/AlignViewportI.java
src/jalview/api/DBRefEntryI.java
src/jalview/api/FeatureRenderer.java
src/jalview/api/SiftsClientI.java
src/jalview/appletgui/AnnotationLabels.java
src/jalview/appletgui/FeatureRenderer.java
src/jalview/appletgui/FeatureSettings.java
src/jalview/appletgui/IdCanvas.java
src/jalview/appletgui/IdPanel.java
src/jalview/appletgui/SeqPanel.java
src/jalview/bin/ArgsParser.java [new file with mode: 0644]
src/jalview/bin/Cache.java
src/jalview/bin/Jalview.java
src/jalview/controller/AlignViewController.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/AlignmentI.java
src/jalview/datamodel/ColumnSelection.java
src/jalview/datamodel/DBRefEntry.java
src/jalview/datamodel/DBRefSource.java
src/jalview/datamodel/FeatureProperties.java
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceFeature.java
src/jalview/datamodel/SequenceI.java
src/jalview/datamodel/xdb/embl/BasePosition.java [deleted file]
src/jalview/datamodel/xdb/embl/EmblEntry.java
src/jalview/datamodel/xdb/embl/EmblFeature.java
src/jalview/datamodel/xdb/embl/EmblFeatureLocElement.java [deleted file]
src/jalview/datamodel/xdb/embl/EmblFeatureLocations.java [deleted file]
src/jalview/datamodel/xdb/embl/EmblSequence.java
src/jalview/ext/ensembl/EnsemblGene.java
src/jalview/ext/ensembl/EnsemblInfo.java [new file with mode: 0644]
src/jalview/ext/ensembl/EnsemblRestClient.java
src/jalview/ext/ensembl/EnsemblSeqProxy.java
src/jalview/ext/ensembl/EnsemblSequenceFetcher.java
src/jalview/ext/jmol/JalviewJmolBinding.java
src/jalview/ext/paradise/Annotate3D.java
src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java
src/jalview/fts/api/FTSDataColumnI.java
src/jalview/fts/api/FTSRestClientI.java
src/jalview/fts/api/GFTSPanelI.java
src/jalview/fts/core/DecimalFormatTableCellRenderer.java [new file with mode: 0644]
src/jalview/fts/core/FTSDataColumnPreferences.java
src/jalview/fts/core/FTSRestClient.java
src/jalview/fts/core/FTSRestRequest.java
src/jalview/fts/core/FTSRestResponse.java
src/jalview/fts/core/GFTSPanel.java
src/jalview/fts/service/pdb/PDBFTSPanel.java
src/jalview/fts/service/pdb/PDBFTSRestClient.java
src/jalview/fts/service/uniprot/UniProtFTSRestClient.java
src/jalview/fts/service/uniprot/UniprotFTSPanel.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/IdCanvas.java
src/jalview/gui/IdPanel.java
src/jalview/gui/JDatabaseTree.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/OptsAndParamsPage.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/Preferences.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/SeqCanvas.java
src/jalview/gui/SeqPanel.java
src/jalview/gui/SequenceFetcher.java
src/jalview/gui/StructureChooser.java
src/jalview/gui/TextColourChooser.java
src/jalview/gui/TreePanel.java
src/jalview/io/FeaturesFile.java
src/jalview/io/HtmlSvgOutput.java
src/jalview/io/IdentifyFile.java
src/jalview/io/StructureFile.java
src/jalview/jbgui/GPreferences.java
src/jalview/jbgui/GStructureChooser.java
src/jalview/renderer/ScaleRenderer.java [new file with mode: 0644]
src/jalview/renderer/seqfeatures/FeatureRenderer.java
src/jalview/structure/StructureSelectionManager.java
src/jalview/structures/models/AAStructureBindingModel.java
src/jalview/util/DnaUtils.java [new file with mode: 0644]
src/jalview/util/ImageMaker.java
src/jalview/util/Platform.java
src/jalview/util/StringUtils.java
src/jalview/viewmodel/AlignmentViewport.java
src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java
src/jalview/workers/AlignmentAnnotationFactory.java
src/jalview/ws/DBRefFetcher.java
src/jalview/ws/DasSequenceFeatureFetcher.java
src/jalview/ws/SequenceFetcher.java
src/jalview/ws/dbsources/EmblXmlSource.java
src/jalview/ws/dbsources/Pdb.java
src/jalview/ws/dbsources/PfamFull.java
src/jalview/ws/dbsources/PfamSeed.java
src/jalview/ws/dbsources/RfamFull.java
src/jalview/ws/dbsources/RfamSeed.java
src/jalview/ws/dbsources/Uniprot.java
src/jalview/ws/dbsources/Xfam.java
src/jalview/ws/ebi/EBIFetchClient.java
src/jalview/ws/jws2/Jws2Client.java
src/jalview/ws/jws2/MsaWSClient.java
src/jalview/ws/sifts/SiftsClient.java
test/jalview/analysis/AlignmentUtilsTests.java
test/jalview/analysis/SequenceIdMatcherTest.java
test/jalview/bin/ArgsParserTest.java [new file with mode: 0644]
test/jalview/datamodel/ColumnSelectionTest.java
test/jalview/datamodel/DBRefEntryTest.java
test/jalview/datamodel/SequenceTest.java
test/jalview/datamodel/xdb/embl/EmblEntryTest.java
test/jalview/datamodel/xdb/embl/EmblFileTest.java
test/jalview/datamodel/xdb/embl/EmblTestHelper.java [new file with mode: 0644]
test/jalview/ext/ensembl/EnsemblRestClientTest.java
test/jalview/ext/ensembl/EnsemblSeqProxyTest.java
test/jalview/ext/ensembl/EnsemblXrefTest.java
test/jalview/ext/paradise/TestAnnotate3D.java
test/jalview/fts/core/FTSRestClientTest.java
test/jalview/fts/service/pdb/PDBFTSPanelTest.java
test/jalview/fts/service/pdb/PDBFTSRestClientTest.java
test/jalview/gui/AlignFrameTest.java [new file with mode: 0644]
test/jalview/gui/StructureChooserTest.java
test/jalview/io/FeaturesFileTest.java
test/jalview/io/IdentifyFileTest.java
test/jalview/io/Jalview2xmlTests.java
test/jalview/util/DnaUtilsTest.java [new file with mode: 0644]
test/jalview/util/StringUtilsTest.java
test/jalview/ws/PDBSequenceFetcherTest.java
test/jalview/ws/dbsources/XfamFetcherTest.java [new file with mode: 0644]
test/jalview/ws/ebi/EBIFetchClientTest.java [new file with mode: 0644]
test/jalview/ws/jabaws/DisorderAnnotExportImport.java
test/jalview/ws/sifts/SiftsClientTest.java
utils/HelpLinksChecker.java [new file with mode: 0644]
utils/InstallAnywhere/Jalview.iap_xml
utils/MessageBundleChecker.java [new file with mode: 0644]

index cad9e2b..6583992 100644 (file)
@@ -39,7 +39,6 @@
        <classpathentry kind="lib" path="lib/jdas-1.0.4.jar"/>
        <classpathentry kind="lib" path="lib/spring-core-3.0.5.RELEASE.jar"/>
        <classpathentry kind="lib" path="lib/spring-web-3.0.5.RELEASE.jar"/>
-       <classpathentry kind="lib" path="lib/groovy-all-1.8.2.jar"/>
        <classpathentry kind="lib" path="lib/min-jabaws-client-2.1.0.jar" sourcepath="/clustengine"/>
        <classpathentry kind="lib" path="lib/json_simple-1.1.jar" sourcepath="/Users/jimp/Downloads/json_simple-1.1-all.zip"/>
        <classpathentry kind="lib" path="lib/slf4j-api-1.7.7.jar"/>
@@ -69,5 +68,6 @@
        <classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
        <classpathentry kind="lib" path="lib/biojava-core-4.1.0.jar"/>
        <classpathentry kind="lib" path="lib/biojava-ontology-4.1.0.jar"/>
+       <classpathentry kind="lib" path="lib/groovy-all-2.4.6-indy.jar"/>
        <classpathentry kind="output" path="classes"/>
 </classpath>
index 00fdf04..a8b8928 100755 (executable)
--- a/build.xml
+++ b/build.xml
@@ -27,7 +27,9 @@
     <echo message="build - compiles all necessary files for Application" />
     <echo message="makedist - compiles and places all necessary jar files into directory dist" />
     <echo message="makefulldist - signs all jar files and builds jnlp file for full distribution" />
-    <echo message="              this needs a keystore and key. Add -Dtimestamp to timestamp signed jars"/>
+    <echo message="              this needs a keystore and key."/>
+    <echo message="              Add -Dtimestamp to timestamp signed jars"/>
+    <echo message="              -Djalview.keyalg and -Djalview.keydig are SHA1/SHA1withRSA"/>
     <echo message="              See docs/building.html for more information." />
     <echo message="compileApplet - compiles all necessary files for Applet" />
     <echo message="makeApplet - compiles, then packages and obfuscates the Applet" />
@@ -88,6 +90,9 @@
     <!-- locally valid proxy for signing with external time server -->
     <property name="proxyPort" value="80"/>
     <property name="proxyHost" value="sqid"/>
+    <!-- key sign/digest algorithms -->
+    <property name="jalview.keyalg" value="SHA1withRSA" description="key algorithm for signing"/>
+    <property name="jalview.keydig" value="SHA1" description="algorithm for jar digest"/>
 
     <!-- default TestNG groups to run -->
     <property name="testng-groups" value="Functional" />
   </target>
 
   <target name="-jarsignwithtsa" depends="makedist,preparejnlp" if="timestamp">
-    <signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false" sigalg="SHA1withRSA"
+    <signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false" sigalg="${jalview.keyalg}" digestalg="${jalview.keydig}"
       tsaproxyhost="${proxyHost}" tsaproxyport="${proxyPort}" tsaurl="${jalview.tsaurl}">
       <fileset dir="${packageDir}">
         <include name="*.jar" />
     </signjar>
   </target>
   <target name="-jarsignnotsa" depends="makedist,preparejnlp" unless="timestamp">
-    <signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false" sigalg="SHA1withRSA">
+    <signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false" sigalg="${jalview.keyalg}" digestalg="${jalview.keydig}">
       <fileset dir="${packageDir}">
         <include name="*.jar" />
       </fileset>
         </information>
         <resources>
           <j2se version="${j2sev}" initial_heap_size="${inih}" max_heap_size="${maxh}" />
+          <jar main="true" href="jalview.jar"/>
           <fileset dir="${packageDir}">
-            <include name="jalview.jar" />
-          </fileset>
-          <fileset dir="${packageDir}">
+            <exclude name="jalview.jar" />
             <include name="*.jar" />
             <include name="*_*.jar" />
-            <exclude name="jalview.jar" />
             <exclude name="*jnilib.jar" />
           </fileset>
           <property name="jalview.version" value="${JALVIEW_VERSION}" />
index 63e7170..e3e453f 100644 (file)
@@ -29,7 +29,7 @@ Groovy Support in Jalview
 <p>Here are some scripts to get you started:</p>
 <ul><li>Getting the title, alignment and first sequence from the current alignFrame<br>
 <pre>
-def alf = Jalview.getAlignframes();
+def alf = Jalview.getAlignFrames();
 print alf[0].getTitle();
 def alignment = alf[0].viewport.alignment;
 def seq = alignment.getSequenceAt(0);
index 3a39691..ecde4d8 100755 (executable)
 <p>
 You will need the following (hopefully):<br>
 <ul>
-<li>Java development kit (JDK1.6 is the recommended platform for developing with Jalview, although JDK1.7 seems to work too!).</li>
-<li>Ant (we think 1.5.4 is quite sufficient to use the simple build
-file supplied, and it seems to work with later versions e.g. 1.7).</li>
+<li>Java development kit (JDK1.8 is now the recommended platform for developing with Jalview.</li>
+<li>Ant (1.7 or later will be needed for some of the jarsigning tools).</li>
 </ul>
 With any luck, after setting your paths and JAVA_HOME correctly, you
 just need to change to the Jalview directory and run ant (this works
-from JBuilder and eclipse too, but NetBeans is a bit trickier).
+from eclipse too, but NetBeans is a bit trickier).
 <pre>
    ant
 </pre>
@@ -46,23 +45,24 @@ build target in ant to make the signed jar files in a directory called
 dist. But first you need to make your own key:
 <p><strong>Making your own key</strong></p>
 
-<p>The ant 'makefulldist' target assumes that a keystore exists in a
-directory 'keys'. To make a key accessible using the default settings
-in the build.xml file then make the keys directory and add the
-jarsigner key with the following :
-</p>
-<pre>
-mkdir keys
-keytool -genkey -keystore keys/.keystore -keypass alignmentisfun
--storepass alignmentisfun -alias jalview
- (you will have to answer some personal questions here)
-ant makedist
- (should eventually generate a Jalview.jnlp file
-  in ./dist along with a set of signed jars using the jalview
-  key)
-</pre>
-
-       <p>
+  <p>The ant 'makefulldist' target assumes that a keystore exists in
+    a directory 'keys'. To make a key accessible using the default
+    settings in the build.xml file then make the keys directory and add
+    the jarsigner key with the following :</p>
+  <pre>mkdir keys</pre>
+  <pre>keytool -genkey -keystore keys/.keystore -keypass alignmentisfun
+  -storepass alignmentisfun -sigalg SHA1withRSA -keyalg RSA -alias jalview</pre>
+  <em>(you will have to answer some personal questions here)</em>
+  <pre>ant makedist -DWebStartLocation="file://.pathtojalviewsource./dist" -Dapplication.codebase="*"</pre>
+  <p>This should eventually generate a jalview.jnlp file in ./dist
+    along with a set of signed jars using the jalview key). In order to
+    test locally via webstart you'll now need to add 'file:/' to your
+    java webstart security exception list. Then:</p>
+  <pre>javaws file://.pathtojalviewsource./dist/jalview.jnlp</pre>
+  <p>Please remember to remove that entry afterwards, since it will leave
+  your system vulnerable to malicious code.
+  </p>
+  <p>
                <strong>Building the JalviewLite applet<br>
                </strong> The JalviewLite applet is compiled using a subset of the packages in
                the src directory (specifically: MCView, and jalview.{datamodel,
index a7653ed..9eed0bc 100644 (file)
 <div id="view_decorated" name="view_decorated"  style="margin:8px; padding:10px; border: 2px solid red; text-align:center; display:none;"><b>Click <a href="index.html#appletDeployment"> here</a> to view decorated page</b></div>
 
 <!-- content start -->
-<h2><a name="appletdeploymentnotes"/>Notes on applet deployment</h2>
+<h2><a name="appletDeployment"/>Notes on applet deployment</h2>
+<table width=80% border="1">
+  <tr><th colspan="2" align="center">Required Dependency Downloads</th></tr>
+  <tr>
+    <th>Dependency</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td><a href="http://www.jalview.org/builds/develop/examples/JmolApplet-14.2.14_2015.06.11.jar">JmolApplet-14.2.14_2015.06.11.jar</a> </td>
+    <td>Jmol Applet Jar</td>
+  </tr>
+  <tr>
+    <td><a href="http://www.jalview.org/builds/develop/examples/java-json.jar">java-json.jar</a></td>
+    <td>Required for BioJSON Generation</td>
+  </tr>
+  <tr>
+    <td><a href="http://www.jalview.org/builds/develop/examples/json_simple-1.1.jar">json_simple-1.1.jar</a></td>
+    <td>Required for BioJSON Generation</td>
+  </tr>
+</table>
+
         <ul>
           <li>Package all your data files into a single (or multiple) zip / jar 
             files. This is very useful to reduce download time of large data files. 
index 433f5a9..cc95ecb 100644 (file)
@@ -28,7 +28,7 @@ which are described <a href="#parameters"> below</a>. Once initialised,
 the applet can be interacted with <em>via</em> its 
 <a href="javascript:doSubmit('jalviewLiteJs')">Javascript API</a>. 
 </p><p><strong>Issues arising from tightening of Java Security default settings</strong><br/>JalviewLite is provided as a signed applet with 'sandbox' permissions and wildcards that allow it to be run from any website. Unfortunately, earlier versions of Java may not be compatible with these settings. </p>
-    <p>For additional deployment notes, <a href="#appletdeploymentnotes">see below</a>.</p>
+    <p>For additional deployment notes, <a href="javascript:doSubmit('appletDeployment')">see Applet Deployment</a>.</p>
            <p><h2>Applet Parameters</h2><br/>The applet takes the following initialisation parameters.</p>
         <a name="parameters"></a>        <table width="97%" class="borderTable" align="center" >
           <tr> 
index dfadb50..c0098a9 100755 (executable)
@@ -1,5 +1,5 @@
 ST-TURN-IIL    blue|255,0,255|absolute|20.0|95.0|below|66.0
-GAMMA-TURN-CLASSIC             red|0,255,255|20.0|95.0|below|66.0
+GAMMA-TURN-CLASSIC     red|0,255,255|20.0|95.0|below|66.0
 BETA-TURN-IR   9a6a94
 BETA-TURN-IL   d6a6ca
 BETA-BULGE     1dc451
@@ -26,73 +26,74 @@ BETA-TURN-IIL       8b5b50
 ST-MOTIF       ac25a1
 
 STARTGROUP     uniprot
+<html><a href="http://pfam.xfam.org/family/PF00111">Pfam family</a></html>     FER_CAPAA       -1      0       0       Pfam
 Iron-sulfur (2Fe-2S)   FER_CAPAA       -1      39      39      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAA       -1      44      44      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAA       -1      47      47      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAA       -1      77      77      METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 8_8</a></html> FER_CAPAA       -1      8       83      Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 8_8</a></html>     FER_CAPAA       -1      8       83      Pfam
 Ferredoxin_fold Status: True Positive  FER_CAPAA       -1      3       93      Cath
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      86      86      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      91      91      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      94      94      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      124     124     METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 55_13</a></html>       FER_CAPAN       -1      55      130     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 55_13</a></html>   FER_CAPAN       -1      55      130     Pfam
 Ferredoxin_fold Status: True Positive  FER_CAPAN       -1      45      140     Cath
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      86      86      METAL
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      91      91      METAL
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      94      94      METAL
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      124     124     METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 55_13</a></html>       FER1_SOLLC      -1      55      130     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 55_13</a></html>   FER1_SOLLC      -1      55      130     Pfam
 Ferredoxin_fold Status: True Positive  FER1_SOLLC      -1      45      140     Cath
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 55_13</a></html>       Q93XJ9_SOLTU    -1      55      130     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 55_13</a></html>   Q93XJ9_SOLTU    -1      55      130     Pfam
 Ferredoxin_fold Status: True Positive  Q93XJ9_SOLTU    -1      45      140     Cath
 Iron-sulfur (2Fe-2S)   FER1_PEA        -1      91      91      METAL
 Iron-sulfur (2Fe-2S)   FER1_PEA        -1      96      96      METAL
 Iron-sulfur (2Fe-2S)   FER1_PEA        -1      99      99      METAL
 Iron-sulfur (2Fe-2S)   FER1_PEA        -1      129     129     METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 60_13</a></html>       FER1_PEA        -1      60      135     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_13</a></html>   FER1_PEA        -1      60      135     Pfam
 Ferredoxin_fold Status: True Positive  FER1_PEA        -1      50      145     Cath
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 63_13</a></html>       Q7XA98_TRIPR    -1      63      138     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 63_13</a></html>   Q7XA98_TRIPR    -1      63      138     Pfam
 Ferredoxin_fold Status: True Positive  Q7XA98_TRIPR    -1      53      148     Cath
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      90      90      METAL
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      95      95      METAL
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      98      98      METAL
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      128     128     METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 59_13</a></html>       FER1_MESCR      -1      59      134     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 59_13</a></html>   FER1_MESCR      -1      59      134     Pfam
 Ferredoxin_fold Status: True Positive  FER1_MESCR      -1      49      144     Cath
 Iron-sulfur (2Fe-2S)   FER1_SPIOL      -1      89      89      METAL
 Iron-sulfur (2Fe-2S)   FER1_SPIOL      -1      94      94      METAL
 Iron-sulfur (2Fe-2S)   FER1_SPIOL      -1      97      97      METAL
 Iron-sulfur (2Fe-2S)   FER1_SPIOL      -1      127     127     METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 58_13</a></html>       FER1_SPIOL      -1      58      133     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 58_13</a></html>   FER1_SPIOL      -1      58      133     Pfam
 Ferredoxin_fold Status: True Positive  FER1_SPIOL      -1      48      143     Cath
 Iron-sulfur (2Fe-2S)   FER3_RAPSA      -1      39      39      METAL
 Iron-sulfur (2Fe-2S)   FER3_RAPSA      -1      44      44      METAL
 Iron-sulfur (2Fe-2S)   FER3_RAPSA      -1      47      47      METAL
 Iron-sulfur (2Fe-2S)   FER3_RAPSA      -1      77      77      METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 8_8</a></html> FER3_RAPSA      -1      8       83      Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 8_8</a></html>     FER3_RAPSA      -1      8       83      Pfam
 Ferredoxin_fold Status: True Positive  FER3_RAPSA      -1      3       93      Cath
 Iron-sulfur (2Fe-2S)   FER_BRANA       -1      39      39      METAL
 Iron-sulfur (2Fe-2S)   FER_BRANA       -1      44      44      METAL
 Iron-sulfur (2Fe-2S)   FER_BRANA       -1      47      47      METAL
 Iron-sulfur (2Fe-2S)   FER_BRANA       -1      77      77      METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 8_8</a></html> FER_BRANA       -1      8       83      Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 8_8</a></html>     FER_BRANA       -1      8       83      Pfam
 Ferredoxin_fold Status: True Positive  FER_BRANA       -1      2       96      Cath
 Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      91      91      METAL
 Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      96      96      METAL
 Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      99      99      METAL
 Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      129     129     METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 60_13</a></html>       FER2_ARATH      -1      60      135     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_13</a></html>   FER2_ARATH      -1      60      135     Pfam
 Ferredoxin_fold Status: True Positive  FER2_ARATH      -1      50      145     Cath
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 60_11</a></html>       Q93Z60_ARATH    -1      60      118     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_11</a></html>   Q93Z60_ARATH    -1      60      118     Pfam
 Ferredoxin_fold Status: True Positive  Q93Z60_ARATH    -1      52      118     Cath
 Iron-sulfur (2Fe-2S)   FER1_MAIZE      -1      91      91      METAL
 Iron-sulfur (2Fe-2S)   FER1_MAIZE      -1      96      96      METAL
 Iron-sulfur (2Fe-2S)   FER1_MAIZE      -1      99      99      METAL
 Iron-sulfur (2Fe-2S)   FER1_MAIZE      -1      129     129     METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 60_13</a></html>       FER1_MAIZE      -1      60      135     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_13</a></html>   FER1_MAIZE      -1      60      135     Pfam
 Ferredoxin_fold Status: True Positive  FER1_MAIZE      -1      50      145     Cath
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 52_12</a></html>       O80429_MAIZE    -1      52      127     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 52_12</a></html>   O80429_MAIZE    -1      52      127     Pfam
 Ferredoxin_fold Status: True Positive  O80429_MAIZE    -1      42      137     Cath
 ENDGROUP       uniprot
 
index 08d038d..42d3187 100644 (file)
@@ -5,6 +5,9 @@ import jalview.workers.AlignmentAnnotationFactory;
  * Example script that registers two alignment annotation calculators
  * - one that counts residues in a column with Pfam annotation
  * - one that counts only charged residues with Pfam annotation
+ * To try this, first load uniref50.fa from the examples folder, then load features
+ * from examples/exampleFeatures.txt, before running this script from the Groovy console.
  * Modify this example as required to count by column any desired value that can be 
  * derived from the residue and sequence features at each position of an alignment.
  */
@@ -49,7 +52,7 @@ def hasPfam = { features ->
  * - a closure (groovy function) that tests whether to include a residue
  * - a closure that tests whether to increment count based on sequence features  
  */
-def getColumnCounter = { name, desc, residueTester, featureCounter ->
+def getColumnCounter = { name, desc, acceptResidue, acceptFeatures ->
     [
      getName: { name }, 
      getDescription: { desc },
@@ -58,9 +61,9 @@ def getColumnCounter = { name, desc, residueTester, featureCounter ->
      count: 
          { res, feats -> 
             def c = 0
-            if (residueTester.call(res))
+            if (acceptResidue.call(res))
             {
-                if (featureCounter.call(feats))
+                if (acceptFeatures.call(feats))
                 {
                     c++
                 }
@@ -71,12 +74,12 @@ def getColumnCounter = { name, desc, residueTester, featureCounter ->
 }
 
 /*
- * Define annotation that counts any residue with Pfam domain annotation
+ * Define an annotation that counts any residue with Pfam domain annotation
  */
 def pfamAnnotation = getColumnCounter("Pfam", "Count of residues with Pfam domain annotation", {true}, hasPfam)
 
 /*
- * Define annotation that counts charged residues with Pfam domain annotation
+ * Define an annotation that counts charged residues with Pfam domain annotation
  */
 def chargedPfamAnnotation = getColumnCounter("Pfam charged", "Count of charged residues with Pfam domain annotation", isCharged, hasPfam)
 
index 813df63..b3387ea 100644 (file)
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
 // do something groovy in jalview
-print "Hello World.\n";
-def alf = Jalview.getAlignFrames();
+println "Hello World.\n"
+println "First sequence is " + currentAlFrame.viewport.alignment.getSequenceAt(0).getDisplayId(true)
+
+def alf = Jalview.getAlignFrames()
 for (ala in alf)
 {
        // ala is an jalview.gui.AlignFrame object 
-       print ala.getTitle()+"\n";
+       println ala.getTitle()
        // get the parent jalview.datamodel.Alignment from the alignment viewport
-       def alignment = ala.viewport.alignment;
+       def alignment = ala.viewport.alignment
        // get the first sequence from the jalview.datamodel.Alignment object
-       def seq = alignment.getSequenceAt(0); 
+       def seq = alignment.getSequenceAt(0) 
 }
+Jalview.quit()
index a23d152..872dadc 100644 (file)
@@ -14,22 +14,22 @@ Iron-sulfur (2Fe-2S)        FER_CAPAA       -1      39      39      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAA       -1      44      44      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAA       -1      47      47      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAA       -1      77      77      METAL
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 8_83</a></html>   FER_CAPAA       -1      8       83      Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 8_83</a></html>       FER_CAPAA       -1      8       83      Pfam
 Chloroplast    FER_CAPAN       -1      1       47      TRANSIT
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      86      86      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      91      91      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      94      94      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      124     124     METAL
 Phosphothreonine       FER_CAPAN       -1      136     136     MOD_RES
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 55_130</a></html> FER_CAPAN       -1      55      130     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 55_130</a></html>     FER_CAPAN       -1      55      130     Pfam
 Chloroplast    FER1_SOLLC      -1      1       47      TRANSIT
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      86      86      METAL
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      91      91      METAL
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      94      94      METAL
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      124     124     METAL
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 55_130</a></html> FER1_SOLLC      -1      55      130     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 55_130</a></html>     FER1_SOLLC      -1      55      130     Pfam
 Evidence: EI4  Q93XJ9_SOLTU    -1      1       48      SIGNAL
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 55_130</a></html> Q93XJ9_SOLTU    -1      55      130     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 55_130</a></html>     Q93XJ9_SOLTU    -1      55      130     Pfam
 Chloroplast    FER1_PEA        -1      1       52      TRANSIT
 L -> I (in strain: cv. Onward)         FER1_PEA        -1      59      59      VARIANT
 I -> L (in strain: cv. Onward)         FER1_PEA        -1      85      85      VARIANT
@@ -38,14 +38,14 @@ Iron-sulfur (2Fe-2S)        FER1_PEA        -1      96      96      METAL
 Iron-sulfur (2Fe-2S)   FER1_PEA        -1      99      99      METAL
 Iron-sulfur (2Fe-2S)   FER1_PEA        -1      129     129     METAL
 YPTS -> PPPA (in Ref. 2)       FER1_PEA        -1      132     135     CONFLICT
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 60_135</a></html> FER1_PEA        -1      60      135     Pfam
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 63_138</a></html> Q7XA98_TRIPR    -1      63      138     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_135</a></html>     FER1_PEA        -1      60      135     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 63_138</a></html>     Q7XA98_TRIPR    -1      63      138     Pfam
 Chloroplast    FER1_MESCR      -1      1       51      TRANSIT
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      90      90      METAL
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      95      95      METAL
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      98      98      METAL
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      128     128     METAL
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 59_134</a></html> FER1_MESCR      -1      59      134     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 59_134</a></html>     FER1_MESCR      -1      59      134     Pfam
 Chloroplast    FER1_SPIOL      -1      1       50      TRANSIT
 STRAND FER1_SPIOL      -1      52      59      STRAND
 TURN   FER1_SPIOL      -1      60      61      TURN
@@ -68,7 +68,7 @@ Iron-sulfur (2Fe-2S)  FER1_SPIOL      -1      127     127     METAL
 STRAND FER1_SPIOL      -1      130     133     STRAND
 STRAND FER1_SPIOL      -1      135     138     STRAND
 HELIX  FER1_SPIOL      -1      142     144     HELIX
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 58_133</a></html> FER1_SPIOL      -1      58      133     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 58_133</a></html>     FER1_SPIOL      -1      58      133     Pfam
 I -> V         FER3_RAPSA      -1      8       8       VARIANT
 Iron-sulfur (2Fe-2S)   FER3_RAPSA      -1      39      39      METAL
 Iron-sulfur (2Fe-2S)   FER3_RAPSA      -1      44      44      METAL
@@ -77,25 +77,25 @@ S -> T      FER3_RAPSA      -1      55      55      VARIANT
 Iron-sulfur (2Fe-2S)   FER3_RAPSA      -1      77      77      METAL
 R -> K         FER3_RAPSA      -1      91      91      VARIANT
 M -> V         FER3_RAPSA      -1      95      95      VARIANT
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 8_83</a></html>   FER3_RAPSA      -1      8       83      Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 8_83</a></html>       FER3_RAPSA      -1      8       83      Pfam
 Chloroplast    FER1_ARATH      -1      1       52      TRANSIT
 Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      91      91      METAL
 Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      96      96      METAL
 Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      99      99      METAL
 Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      129     129     METAL
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 60_135</a></html> FER1_ARATH      -1      60      135     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_135</a></html>     FER1_ARATH      -1      60      135     Pfam
 Iron-sulfur (2Fe-2S)   FER_BRANA       -1      39      39      METAL
 Iron-sulfur (2Fe-2S)   FER_BRANA       -1      44      44      METAL
 Iron-sulfur (2Fe-2S)   FER_BRANA       -1      47      47      METAL
 Iron-sulfur (2Fe-2S)   FER_BRANA       -1      77      77      METAL
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 8_83</a></html>   FER_BRANA       -1      8       83      Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 8_83</a></html>       FER_BRANA       -1      8       83      Pfam
 Chloroplast    FER2_ARATH      -1      1       52      TRANSIT
 Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      91      91      METAL
 Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      96      96      METAL
 Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      99      99      METAL
 Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      129     129     METAL
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 60_135</a></html> FER2_ARATH      -1      60      135     Pfam
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 60_118</a></html> Q93Z60_ARATH    -1      60      118     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_135</a></html>     FER2_ARATH      -1      60      135     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_118</a></html>     Q93Z60_ARATH    -1      60      118     Pfam
 Chloroplast    FER1_MAIZE      -1      1       52      TRANSIT
 STRAND FER1_MAIZE      -1      57      59      STRAND
 STRAND FER1_MAIZE      -1      72      74      STRAND
@@ -113,6 +113,6 @@ Iron-sulfur (2Fe-2S)        FER1_MAIZE      -1      129     129     METAL
 STRAND FER1_MAIZE      -1      132     135     STRAND
 STRAND FER1_MAIZE      -1      137     141     STRAND
 TURN   FER1_MAIZE      -1      142     142     TURN
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 60_135</a></html> FER1_MAIZE      -1      60      135     Pfam
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 52_127</a></html> O80429_MAIZE    -1      52      127     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_135</a></html>     FER1_MAIZE      -1      60      135     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 52_127</a></html>     O80429_MAIZE    -1      52      127     Pfam
 ENDGROUP       uniprot
index 229596c..1e41232 100644 (file)
@@ -26,4 +26,4 @@ subCatContainer.scroll(
 function() {
 subCatContainer.scrollTop($(this).scrollTop());
 });
-</script></hmtl>
\ No newline at end of file
+</script></html>
index 0a0214e..c870887 100644 (file)
   <strong>Normalise Consensus Logo</strong> to scale all columns of the
   logo to the same height.
 
+    <p>
+    <strong>Group Consensus</strong><br>
+    If sequence groups have been defined, then selecting option 'Group Consensus' in the <a href="../menus/alwannotation.html">Annotations menu</a> will 
+    result in Consensus being calculated for each group, as well as the alignment as a whole.
+  </p>
   <p>
     <strong>cDNA Consensus</strong>
   </p>
index df8b5ff..9cb8ce1 100755 (executable)
     (e.g. !proline).
   </p>
   <p>
-    <em>Colouring an alignment by conservation</em><br>
+    <strong>Colouring an alignment by conservation</strong><br>
     Conservation scores can be used to colour an alignment. This is
     explained further in the help page for <a
       href="../colourSchemes/conservation.html"
     >conservation colouring</a>.
   </p>
+  <p>
+    <strong>Group conservation</strong><br>
+    If sequence groups have been defined, then selecting option 'Group Conservation' in the <a href="../menus/alwannotation.html">Annotations menu</a> will 
+    result in Conservation being calculated for each group, as well as the alignment as a whole.
+  </p>
 </body>
 </html>
index a645630..7e52c46 100755 (executable)
@@ -48,6 +48,25 @@ alignment window or loaded from the alignment's file menu.
                        href="../webServices/proteinDisorder.html">disordered region</a>
                prediction methods. 
 </p>
+<p><strong>Sequence Group Annotation</strong>
+</p>
+<p>
+       If sequence groups are defined, <a href="../calculations/conservation.html">Conservation</a>
+        and <a href="../calculations/consensus.html">Consensus</a> annotation can be enabled
+       for each group from the <a href="../menus/alwannotation.html">Annotations menu</a>, or can
+       be imported from a Jalview <a href="annotationsFormat.html">Annotations file</a>.
+</p>
+<p><strong>Sequence Selection from Annotation</strong>
+</p>
+<p>
+    Sequences associated with sequence (or sequence group) annotations can be selected by
+    double-clicking the annotation label with these key combinations:
+    <ul>
+    <li>double-click - Select associated sequences (replaces current selection)</li>
+    <li>shift double-click - add  sequences to selection</li>
+    <li>Ctrl (Mac CMD) double-click - toggles inclusion of associated sequences in the current selection</li>
+    </ul>
+    Note this also works in combination with manual sequence selection in the alignment.
 <p><strong>Interactive Alignment Annotation</strong></p>
 <p>
 Annotation rows are added using the <strong>Annotation Label</strong>
index 545f0c1..744370b 100755 (executable)
     followed by a <em>description</em> for the row, which is shown in a
     tooltip when the user mouses over the annotation row's label. Since
     Jalview 2.7, the description field may also contain HTML tags (in
-    the same way as a <a href="featuresFile.html">sequence feature's</a>
+    the same way as a <a href="featuresFormat.html">sequence feature's</a>
     label), providing the text is enclosed in an &lt;html/&gt; tag.
   <ul>
     <em>Please note: URL links embedded in HTML descriptions are
index f8f87dc..cb7ccc0 100644 (file)
@@ -20,7 +20,7 @@
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  -->
 <head>
-<title>BioJSON in Jalviwe</title>
+<title>BioJSON in Jalview</title>
 </head>
 <body>
   <p>
index 9164afd..200fc8f 100755 (executable)
     the bottom of the list is rendered <em>below</em> a feature higher
     up in the list.<br> <em><strong>You can change
         the order of a feature by dragging it up and down the list with
-        the mouse</strong></em>.
+        the mouse (not applet)</strong></em>.
   </p>
   <p>
     The <strong><em>Optimise order</em></strong> button (currently only
index 9aa341b..a2bc627 100644 (file)
@@ -56,6 +56,9 @@
     </em>
   </p>
   <p>
+    <strong>Executing a groovy script on a particular alignment</strong><br/>
+    
+  <p>
     <strong>Access to Jalview's functions from Groovy Scripts</strong><br>
     There is as yet no properly defined scripting interface to Jalview,
     but all the public methods of the jalview class hierarchy can be
diff --git a/help/html/features/mmcif.html b/help/html/features/mmcif.html
new file mode 100644 (file)
index 0000000..6df0fd4
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>mmCIF File Format</title>
+</head>
+<body>
+       <strong>mmCIF File Format</strong>
+       <p>The mmCIF file format (macromolecular Crystallographic
+               Information) was developed under the auspices of the International Union of Crystallography (IUCr) to extend the Crystallographic Information
+               File (CIF) data representation used for describing small molecule
+               structures and associated diffraction experiments.</p>
+       <strong>Merits of mmCIF file format</strong>
+       <ul>
+               <li>Large structures (containing >62 chains and/or 99999 ATOM
+                       records) that cannot be fully represented in the PDB file format are
+                       available in the PDB archive as single PDBx/mmCIF files.</li>
+               <li>PDBx/mmCIF file format provides richer data annotation</li>         
+               <li>PDBx/mmCIF became the standard PDB archive format in 2014.
+                       Since 2016 the PDB File Format is no longer being modified or
+                       extended to support new content.
+               </li>
+       </ul>
+
+       <em>mmCIF file format support for importing 3D structure data from
+               flat file and EMBL-PDBe via mmCIF was added in Jalview 2.9.1</em>
+</body>
+</html>
\ No newline at end of file
index ac63c9e..60ac6ab 100644 (file)
@@ -42,5 +42,7 @@
     retrieved by the <a href="seqfetch.html">Sequence Fetcher</a>, and
     allows sequence features to be mapped directly from Uniprot das
     sources to their coding region on EMBL sequence records.
+  </p>
+   <p>In Jalview 2.9.1 <a href="siftsmapping.html">SIFTS Mapping</a> was added as a better means for explicitly identifying the coordinates corresponding to a displayed sequence when viewing a PDB structure associated with a sequence </p>
 </body>
 </html>
diff --git a/help/html/features/sifts_mapping_output.png b/help/html/features/sifts_mapping_output.png
new file mode 100644 (file)
index 0000000..3c28b81
Binary files /dev/null and b/help/html/features/sifts_mapping_output.png differ
diff --git a/help/html/features/siftsmapping.html b/help/html/features/siftsmapping.html
new file mode 100644 (file)
index 0000000..c344a20
--- /dev/null
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>SIFTS Mapping</title>
+</head>
+<body>
+  <p><strong>SIFTS Mapping</strong></p>
+  
+  <p>
+       SIFTS (Structure integration with function, taxonomy
+       and sequences) provides an up-to-date resource for residue-level
+       mapping between Uniprot and PDB entries. The information is updated and
+       released weekly simultaneously with the release of new PDB entries.
+       SIFTS Entries are published as XML files and made publicly available via an FTP
+       site hosted at the European Bioinformatics Institute. 
+  </p>
+       
+  <p>
+    At the point of viewing a PDB structure, Jalview downloads a SIFTS file 
+       for the target entry and uses it to accurately map the sequence residues with the 
+       structure residue. Prior to SIFTS integration, Jalview uses Needleman and Wunsch 
+       Alignment algorithm to  map sequence residues to structure residues, and that may not 
+       always result to a correct mapping since it is computational determined.        
+  </p>
+  
+  <p>
+       The default method for 'Sequence &harr; Structure' mapping can be configured 
+       in the Structure tab in the <strong>Tools &rarr; Preferences</strong> dialog box. When 'SIFTS' 
+       is enabled as the default, all mappings between 'Sequence &harr; Structure' is 
+       performed via SIFTS provided that there is a valid SIFTS entry for PDB structure. If no 
+       valid SIFTS resource is available, then the 'Sequence &harr; Structure' mapping falls 
+       back to Needleman and Wunsch Alignment algorithm.
+  </p>
+       
+  <p>To verify the mapping method used, you can view the mapping output via the structure viewer menu <strong>File &rarr; View mapping.</strong> A sample mapping output can be seen in the screenshot below. The highlighted position shows the method used. </p>     
+  <p>
+       <img src="sifts_mapping_output.png" align="left" alt="SIFTS mapping output" />
+  </p>
+       
+  <p><em>SIFTS Mapping integration was added in Jalview 2.9.1</em></p>
+       
+</body>
+</html>
\ No newline at end of file
index ed5bef3..1c36abd 100644 (file)
@@ -53,7 +53,7 @@
     <li>On selecting rows, columns or regions in one alignment, the
       corresponding selection is made in the other</li>
     <li>Sequence ordering in one alignment (using the cursor, or <strong><a
-        href="../calculate/sorting.html"
+        href="../calculations/sorting.html"
       >"Calculate&#8594;Sort")</a></strong> is also applied to the other
     </li>
     <li>Editing (gap insertion / deletion) in the protein alignment
@@ -75,7 +75,7 @@
       panels.</li>
     <li>Panel heights are adjusted dragging the divider between
       them using the mouse</li>
-    <li><a href="menus/alwview.html"><strong>"View&#8594;New
+    <li><a href="../menus/alwview.html"><strong>"View&#8594;New
           View / Expand Views / Gather Views"</strong></a> behave as for a normal
       alignment window, but always create new views as Split Frames</li>
   </ul>
diff --git a/help/html/features/uniprotqueryfields.html b/help/html/features/uniprotqueryfields.html
new file mode 100644 (file)
index 0000000..376180a
--- /dev/null
@@ -0,0 +1,599 @@
+<html>
+<!--
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ -->
+<head>
+<title>UniProtKB query fields</title>
+</head>
+
+<body>
+  <p>
+    <strong>UniProtKB query fields</strong>
+  </p>
+<p>Supported query fields for searching specific data in UniProtKB (see also <a href="text-search">query syntax</a>).</p>
+
+<table  border="1" width="95%">
+  <tr>
+    <th>Field</th>
+    <th>Example</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>accession</td>
+    <td>
+      <code>accession:P62988</code>
+    </td>
+    <td>
+        Lists all entries with the primary or secondary
+        accession number P62988.
+    </td>
+  </tr>
+  <tr>
+    <td>active</td>
+    <td>
+      <code>active:no </code>
+    </td>
+    <td>
+        Lists all obsolete entries.
+    </td>
+  </tr>
+  <tr>
+    <td>annotation</td>
+    <td>
+      <code>
+        annotation:(type:non-positional)
+        <br />
+        annotation:(type:positional)
+        <br />
+        annotation:(type:mod_res "Pyrrolidone carboxylic acid" evidence:experimental)
+      </code>
+    </td>
+    <td>
+      Lists all entries with:
+      <ul>
+        <li>any general annotation (comments [CC])</li>
+        <li>any sequence annotation (features [FT])</li>
+        <li>at least one amino acid modified with a Pyrrolidone carboxylic acid group</li>
+      </ul>
+    </td>
+  </tr>
+  <tr>
+    <td>author</td>
+    <td>
+      <code>
+        author:ashburner
+      </code>
+    </td>
+    <td>
+        Lists all entries with at least one reference co-authored by Michael Ashburner.
+    </td>
+  </tr>
+  <tr>
+    <td>cdantigen</td>
+    <td>
+      <code>
+        cdantigen:CD233
+      </code>
+    </td>
+    <td>
+        Lists all entries whose cluster of differentiation number is CD233.
+    </td>
+  </tr>
+  <tr>
+    <td>citation</td>
+    <td>
+      <code>
+        citation:("intracellular structural proteins")
+        <br />
+        citation:(author:ashburner journal:nature)
+        citation:9169874
+      </code>
+    </td>
+    <td>
+      Lists all entries with a literature citation:
+      <ul>
+        <li>containing the phrase "intracellular structural proteins" in either title or abstract</li>
+        <li>co-authored by Michael Ashburner and published in Nature</li>
+        <li>with the PubMed identifier 9169874</li>
+      </ul>
+    </td>
+  </tr>
+  <tr>
+    <td>cluster</td>
+    <td>
+      <code>
+        cluster:UniRef90_A5YMT3
+      </code>
+    </td>
+    <td>
+        Lists all entries in the UniRef 90% identity cluster whose
+        representative sequence is UniProtKB entry A5YMT3.
+    </td>
+  </tr>
+  <tr>
+       <td>count</td>
+       <td>
+               <code>
+                       annotation:(type:transmem count:5)<br />
+                       annotation:(type:transmem count:[5 TO *])<br />
+                       annotation:(type:cofactor count:[3 TO *])
+               </code>
+       </td>
+       <td>Lists all entries with:
+               <ul>
+                       <li>exactly 5 transmembrane regions</li>
+                       <li>5 or more transmembrane regions</li>
+                       <li>3 or more Cofactor comments</li>
+               </ul>
+       </td>
+  </tr>
+  <tr>
+    <td>created</td>
+    <td>
+      <code>
+        created:[20121001 TO *]<br />
+        reviewed:yes AND created:[current TO *]
+      </code>
+    </td>
+    <td>
+        Lists all entries created since October 1st 2012.<br />
+        Lists all new UniProtKB/Swiss-Prot entries in the last release.
+    </td>
+  </tr>
+  <tr>
+    <td>database</td>
+    <td>
+      <code>
+        database:(type:pfam)
+        <br />
+        database:(type:pdb 1aut)
+      </code>
+    </td>
+    <td>
+      Lists all entries with:
+      <ul>
+        <li>a cross-reference to the Pfam database</li>
+        <li>a cross-reference to the PDB database entry 1aut</li>
+      </ul>
+     
+    </td>
+  </tr>
+  <tr>
+    <td>domain</td>
+    <td>
+      <code>
+        domain:VWFA
+      </code>
+    </td>
+    <td>
+        Lists all entries with a Von Willebrand factor type A domain described
+        in the 'Family and Domains' section.
+    </td>
+  </tr>
+  <tr>
+    <td>ec</td>
+    <td>
+      <code>
+        ec:3.2.1.23
+      </code>
+    </td>
+    <td>
+        Lists all beta-galactosidases.
+    </td>
+  </tr>
+  <tr>
+       <td>evidence</td>
+       <td>
+               <code>
+                       annotation:(type:signal evidence:ECO_0000269)<br />
+                       (type:mod_res phosphoserine evidence:ECO_0000269)<br />
+                       annotation:(type:function AND evidence:ECO_0000255)
+               </code>
+       </td>
+       <td>Lists all entries with:
+               <ul>
+                       <li>a signal sequence whose positions have been experimentally proven</li>
+                       <li>experimentally proven phosphoserine sites</li>
+                       <li>a function manually asserted according to rules</li>
+               </ul>
+       </td>
+  </tr>
+  <tr>
+    <td>family</td>
+    <td>
+      <code>
+        family:serpin
+      </code>
+    </td>
+    <td>
+        Lists all entries belonging to the Serpin family of proteins.
+    </td>
+  </tr>
+  <tr>
+    <td>fragment</td>
+    <td>
+      <code>
+        fragment:yes
+      </code>
+    </td>
+    <td>
+        Lists all entries with an incomplete sequence.
+    </td>
+  </tr>
+
+  <tr>
+    <td>gene</td>
+    <td>
+      <code>
+        gene:HSPC233
+      </code>
+    </td>
+    <td>
+        Lists all entries for proteins encoded by gene HSPC233.
+    </td>
+  </tr>
+  <tr>
+    <td>go</td>
+    <td>
+      <code>
+        go:cytoskeleton
+        <br />
+        go:0015629
+      </code>
+    </td>
+    <td>
+      Lists all entries associated with:
+      <ul>
+        <li>a GO term containing the word "cytoskeleton"</li>
+        <li>the GO term Actin cytoskeleton and any subclasses</li>
+      </ul>
+    </td>
+  </tr>
+  <tr>
+    <td>host</td>
+    <td>
+      <code>
+        host:mouse
+        <br />
+        host:10090
+        <br />
+        host:40674
+      </code>
+    </td>
+    <td>
+      Lists all entries for viruses infecting:
+      <ul>
+        <li>organisms with a name containing the word "mouse"</li>
+        <li>Mus musculus (Mouse)</li>
+        <li>all mammals (all taxa classified under the taxonomy node for Mammalia)</li>
+      </ul>
+    </td>
+  </tr>
+  <tr>
+    <td>id</td>
+    <td>
+      <code>id:P00750</code>
+    </td>
+    <td>
+        Returns the entry with the primary
+        accession number P00750.
+    </td>
+  </tr>
+  <tr>
+    <td>inn</td>
+    <td>
+      <code>
+        inn:Anakinra
+      </code>
+    </td>
+    <td>
+        Lists all entries whose "International Nonproprietary Name" is Anakinra.
+    </td>
+  </tr>
+  <tr>
+    <td>interactor</td>
+    <td>
+      <code>
+        interactor:P00520
+      </code>
+    </td>
+    <td>
+        Lists all entries describing interactions with the protein described by
+        entry P00520.
+    </td>
+  </tr>
+  <tr>
+    <td>keyword</td>
+    <td>
+      <code>
+        keyword:toxin
+      </code>
+    </td>
+    <td>
+        Lists all entries associated with the keyword Toxin.
+    </td>
+  </tr>
+  <tr>
+    <td>length</td>
+    <td>
+      <code>
+        length:[500 TO 700]
+      </code>
+    </td>
+    <td>
+        Lists all entries describing sequences of length between 500 and 700 residues.
+    </td>
+  </tr>
+  <tr>
+    <td>lineage</td>
+    <td />
+    <td>
+      This field is a synonym for the field <code>taxonomy</code>.
+    </td>
+  </tr>
+  <tr>
+    <td>mass</td>
+    <td>
+      <code>
+        mass:[500000 TO *]
+      </code>
+    </td>
+    <td>
+        Lists all entries describing sequences with a mass of at least 500,000 Da.
+    </td>
+  </tr>
+  <tr>
+    <td>method</td>
+    <td>
+      <code>
+        method:maldi
+        <br />
+        method:xray
+      </code>
+    </td>
+    <td>
+        Lists all entries for proteins identified by: matrix-assisted laser
+        desorption/ionization (MALDI), crystallography (X-Ray). The
+        <code>method</code> field searches names of physico-chemical
+        identification methods in the 'Biophysicochemical properties' subsection of the 'Function' section, the 'Publications' and
+        'Cross-references' sections.
+    </td>
+  </tr>
+  <tr>
+    <td>mnemonic</td>
+    <td>
+      <code>
+        mnemonic:ATP6_HUMAN
+      </code>
+    </td>
+    <td>
+        Lists all entries with entry name (ID) ATP6_HUMAN. Searches also
+        obsolete entry names.
+    </td>
+  </tr>
+  <tr>
+    <td>modified</td>
+    <td>
+      <code>
+        modified:[20120101 TO 20120301]<br />
+        reviewed:yes AND modified:[current TO *]
+      </code>
+    </td>
+    <td>
+        Lists all entries that were last modified between January and March 2012.<br />
+        Lists all UniProtKB/Swiss-Prot entries modified in the last release.
+    </td>
+  </tr>
+  <tr>
+    <td>name</td>
+    <td>
+      <code>
+        name:"prion protein"
+      </code>
+    </td>
+    <td>
+        Lists all entries for prion proteins.
+    </td>
+  </tr>
+  <tr>
+    <td>organelle</td>
+    <td>
+      <code>
+        organelle:Mitochondrion
+      </code>
+    </td>
+    <td>
+        Lists all entries for proteins encoded by a gene of the mitochondrial
+        chromosome.
+    </td>
+  </tr>
+  <tr>
+    <td>organism</td>
+    <td>
+      <code>
+        organism:"Ovis aries"
+        <br />
+        organism:9940
+        <br />
+        organism:sheep
+        <br />
+      </code>
+    </td>
+    <td>
+        Lists all entries for proteins expressed in sheep (first 2 examples) and
+        organisms whose name contains the term "sheep".
+    </td>
+  </tr>
+  <tr>
+    <td>plasmid</td>
+    <td>
+      <code>
+        plasmid:ColE1
+      </code>
+    </td>
+    <td>
+        Lists all entries for proteins encoded by a gene of plasmid ColE1.
+    </td>
+  </tr>
+  <tr>
+    <td>proteome</td>
+    <td>
+      <code>
+        proteome:UP000005640
+      </code>
+    </td>
+    <td>
+        Lists all entries from the human proteome.
+    </td>
+  </tr>
+  <tr>
+    <td>proteomecomponent</td>
+    <td>
+      <code>
+        proteomecomponent:"chromosome 1" and organism:9606
+      </code>
+    </td>
+    <td>
+        Lists all entries from the human chromosome 1.
+    </td>
+  </tr>
+  <tr>
+    <td>replaces</td>
+    <td>
+      <code>
+        replaces:P02023
+      </code>
+    </td>
+    <td>
+        Lists all entries that were created from a merge with entry P02023.
+    </td>
+  </tr>
+  <tr>
+    <td>reviewed</td>
+    <td>
+      <code>
+        reviewed:yes
+      </code>
+    </td>
+    <td>
+        Lists all UniProtKB/Swiss-Prot entries.
+    </td>
+  </tr>
+  <tr>
+    <td>scope</td>
+    <td>
+      <code>
+        scope:mutagenesis
+      </code>
+    </td>
+    <td>
+        Lists all entries containing a reference that was used to gather
+        information about mutagenesis.
+    </td>
+  </tr>
+  <tr>
+    <td>sequence</td>
+    <td>
+      <code>
+        sequence:P05067-9
+      </code>
+    </td>
+    <td>
+        Lists all entries containing a link to isoform 9 of the sequence
+        described in entry P05067. Allows searching by specific sequence
+        identifier.
+    </td>
+  </tr>
+  <tr>
+    <td>sequence_modified</td>
+    <td>
+      <code>
+        sequence_modified:[20120101 TO 20120301]<br />
+        reviewed:yes AND sequence_modified:[current TO *]
+      </code>
+    </td>
+    <td>
+        Lists all entries whose sequences were last modified between January and March 2012.<br />
+        Lists all UniProtKB/Swiss-Prot entries whose sequences were modified in the last release.
+    </td>
+  </tr>
+  <tr>
+    <td>source</td>
+    <td>
+      <code>
+        source:intact
+      </code>
+    </td>
+    <td>
+        Lists all entries containing a GO term whose annotation source is the
+        IntAct database.
+    </td>
+  </tr>
+  <tr>
+    <td>strain</td>
+    <td>
+      <code>
+        strain:wistar
+      </code>
+    </td>
+    <td>
+        Lists all entries containing a reference relevant to strain wistar.
+    </td>
+  </tr>
+  <tr>
+    <td>taxonomy</td>
+    <td>
+      <code>
+        taxonomy:40674
+      </code>
+    </td>
+    <td>
+        Lists all entries for proteins expressed in Mammals. This field is used to retrieve
+        entries for all organisms classified below a given taxonomic node taxonomy classification).
+    </td>
+  </tr>
+  <tr>
+    <td>tissue</td>
+    <td>
+      <code>
+        tissue:liver
+      </code>
+    </td>
+    <td>
+        Lists all entries containing a reference describing the protein sequence
+        obtained from a clone isolated from liver.
+    </td>
+  </tr>
+  <tr>
+    <td>web</td>
+    <td>
+      <code>
+        web:wikipedia
+      </code>
+    </td>
+    <td>
+        Lists all entries for proteins that are described in Wikipedia.
+    </td>
+  </tr>
+</table>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/help/html/features/uniprotseqfetcher.png b/help/html/features/uniprotseqfetcher.png
new file mode 100644 (file)
index 0000000..a592e8e
Binary files /dev/null and b/help/html/features/uniprotseqfetcher.png differ
diff --git a/help/html/features/uniprotsequencefetcher.html b/help/html/features/uniprotsequencefetcher.html
new file mode 100644 (file)
index 0000000..9b2e3fa
--- /dev/null
@@ -0,0 +1,161 @@
+<html>
+<!--
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ -->
+<head>
+<title>The Uniprot Free Text Search Interface</title>
+</head>
+<body>
+
+  <strong>The Uniprot Free Text Search Interface</strong>
+  <p>
+    Jalview provides a specialised interface that allows fast and
+    efficient discovery and retrieval of data from the Uniprot database.
+    It allows
+    interactive querying of Uniprot metadata with free text and structured
+    queries, so sequences can be located without prior knowledge of
+    their database accessions, or <em>via</em> manual cross-referencing
+    from Uniprot or other bioinformatics websites.
+  </p>
+  <p>
+    To open the UniProt Sequence Fetcher, select UniProt as the database from
+    any <a href="seqfetch.html">Sequence Fetcher</a> dialog (opened <em>via</em>
+    <strong>&quot;File &#8594;Fetch Sequences&quot;</strong>).
+  </p>
+  <p>
+  <img src="uniprotseqfetcher.png" align="left"
+    alt="Uniprot sequence fetcher (introduced in Jalview 2.9.1)"
+  />
+  </p>
+
+  <p>
+    <strong>Searching the Uniprot Database</strong>
+  </p>
+  <p>
+    To search the Uniprot, begin typing in the text box. The results of your
+    query are shown in the search results tab, which queries Uniprot after 1.5secs every time
+    you type in the search text box. You can sort results according to
+    the displayed columns, and select entries with the mouse or
+    keyboard. Once you have selected one or more entries, hit the <strong>OK</strong>
+    button to retrieve and visualise the sequences in Jalview Alignment interface.
+  </p>
+  <ul>
+    <li><strong>Searching a specific Uniprot field </strong> If you
+      want to find sequences based on a specific Uniprot metadata field,
+      you can select it from the drop-down menu.</li>
+      
+
+               <li><strong>Bulk Uniprot retrieval</strong><br>
+      Firstly, switch the search target to Uniprot Id, then enter multiple IDs by separating them with a semi-colon.
+      e.g. fila_human; mnt_human; mnt_mouse.<br />Hitting Return or OK will automatically
+      fetch those IDs, like the default Sequence Fetcher interface.</li>
+      
+            <li><strong>Advanced / Custom querying</strong>  
+      The table below provides a brief overview of the supported Uniprot query syntax (see <a href="uniprotqueryfields.html">query fields for UniProtKB</a>):
+               <table border="1" width="95%">
+                               <tr>
+                                       <td><code>human antigen</code></td>
+                                       <td rowspan="3">All entries containing both terms.</td>
+                               </tr>
+                               <tr>
+                                       <td><code>human AND antigen</code></td>
+                               </tr>
+                               <tr>
+                                       <td><code>human &amp;&amp; antigen</code></td>
+                               </tr>
+                               <tr>
+                                       <td><code>"human antigen"</code></td>
+                                       <td>All entries containing both terms in the exact order.</td>
+                               </tr>
+                               <tr>
+                                       <td><code>human -antigen</code></td>
+                                       <td rowspan="3">All entries containing the term <code>human</code>
+                                               but not <code>antigen</code>.
+                                       </td>
+                               </tr>
+                               <tr>
+                                       <td><code>human NOT antigen</code></td>
+                               </tr>
+                               <tr>
+                                       <td><code>human ! antigen</code></td>
+                               </tr>
+                               <tr>
+                                       <td><code>human OR mouse</code></td>
+                                       <td rowspan="2">All entries containing either term.</td>
+                               </tr>
+                               <tr>
+                                       <td><code>human || mouse</code></td>
+                               </tr>
+                               <tr>
+                                       <td><code>antigen AND (human OR mouse)</code></td>
+                                       <td>Using parentheses to override boolean precedence rules.</td>
+                               </tr>
+                               <tr>
+                                       <td><code>anti*</code></td>
+                                       <td>All entries containing terms starting with <code>anti</code>.
+                                               Asterisks can also be used at the beginning and within terms. <strong>Note:</strong>
+                                               Terms starting with an asterisk or a single letter followed by an
+                                               asterisk can slow down queries considerably.
+                                       </td>
+                               </tr>
+                               <tr>
+                                       <td><code> author:Tiger*</code></td>
+                                       <td>Citations that have an author whose name starts with <code>Tiger</code>.
+                                               To search in a specific field of a dataset, you must prefix your
+                                               search term with the field name and a colon. To discover what
+                                               fields can be queried explicitly, observe the query hints that are
+                                               shown after submitting a query or use the query builder (see
+                                               below).
+                                       </td>
+                               </tr>
+                               <tr>
+                                       <td><code>length:[100 TO *]</code></td>
+                                       <td>All entries with a sequence of at least 100 amino acids.</td>
+                               </tr>
+                               <tr>
+                                       <td><code>citation:(author:Arai author:Chung)</code></td>
+                                       <td>All entries with a publication that was coauthored by two
+                                               specific authors.</td>
+                               </tr>
+                       </table>
+               </li>
+</ul>
+  <p>
+    <strong>Result pagination</strong>
+  </p>
+  The query results returned from the Uniprot server are paginated for performance optimisation. 
+  The button labelled <strong>'&nbsp;&lt;&lt;&nbsp;'</strong> and <strong>'&nbsp;&gt;&gt;&nbsp;'</strong> can be used to navigate to the next or previous result page respectively. 
+  The page range is shown on the title bar of the Free Text Search interface. Jalview's pagination implementation supports multiple selection of entries across multiple pages. 
+  
+  
+ <p>
+    <strong>Customising The Uniprot Sequence Fetcher</strong>
+  </p>
+  <p>
+    To change the displayed meta-data in the search result, click the
+    'Customise Displayed Options' tab, and select the fields you'd like
+    to displayed or remove. 
+  </p>
+  <p>
+    <em>The Uniprot Free Test Search Interface was introduced in
+      Jalview 2.9.1</em>
+  </p>
+</body>
+</html>
\ No newline at end of file
index 4d35516..d4819f1 100755 (executable)
   </p>
 
   <p>
+    <strong>Importing PDB Entries or files in mmCIF format</strong><br>
+    <a href="mmcif.html">mmCIF file format</a> provides an alternative means for 
+    importing 3D structure data from flat file and EMBL-PDBe 
+    web-service. To enable mmCIF as the default format for 
+    importing PBD sequences from the PDB sequence fetcher, add or modify the 
+    property  
+    <code>DEFAULT_STRUCTURE_FORMAT=mmCIF</code> in Jalview properties file. 
+    Once this is done, the steps followed in retrieving PDB format files above can 
+    be followed to obtain the same data with mmCIF. <em>mmCIF format file support was added in Jalview 2.9.1.</em></p>
+    
+   
+
+  <p>
     <strong>Associating a large number of PDB files to
       sequences in an alignment</strong><br /> It is often the case when working
     with structure alignments that you will have a directory of PDB
index a477457..f129551 100755 (executable)
       <td>Both</td>
       <td>Cuts the (fully) selected sequences from the alignment. <!-- not yet in this version 
 This will not happen if only some
-columns are selected, you should use the <a href="features/regionHiding.html">Hide Regions feature</a> instead.-->
+columns are selected, you should use the <a href="features/hiddenRegions.html">Hide Regions feature</a> instead.-->
       </td>
     </tr>
     <tr>
index 15c94ce..edbd1e9 100755 (executable)
@@ -82,8 +82,7 @@
             <a href="../webServices/newsreader.html">Jalview News</a>
             dialog box.
         </em></li>
-        <li><strong>Groovy Console...<em> (only
-              available if groovy is on the classpath)</em><br></strong> <em>Opens
+        <li><strong>Groovy Console...<br></strong> <em>Opens
             the <a href="../features/groovy.html">Groovy Console</a> for
             interactive scripting.
         </em><strong><br></strong></li>
index 1eb2366..353fb41 100755 (executable)
             and sequence description to be entered. Press OK to accept
             your edit. To save sequence descriptions, you must save in
             Fasta, PIR or Jalview File format.</em></li>
-        <li><a href="sqaddrefannot"><strong>Add
-              Reference Annotations<br>
-          </strong><em>When enabled, copies any available alignment
+        <li><strong>Add <a href="../features/annotation.html#seqannots">Reference Annotations</a></strong><br>
+              <em>When enabled, copies any available alignment
               annotation for this sequence to the current view.</em></li>
         <li><strong>Set as Reference</strong> or <strong>Unmark
             as Reference</strong><br /> Sets or unsets the reference sequence for
index 23e958c..37ad369 100755 (executable)
     <tr>
       <td width="60" nowrap>
         <div align="center">
-          <strong><a name="Jalview.2.9.0b2">2.9.0b2</a><br />
-            <em>16/10/2015</em></strong>
+          <strong><a name="Jalview.2.9.1">2.9.1</a><br /> <em>21/6/2016</em></strong>
         </div>
       </td>
+      <td><em>General</em>
+        <ul>
+            <li><!-- JAL---></li>
+        </ul> <em>Application</em>
+        <ul>
+            <li><!-- JAL---></li>
+            <li><!-- JAL-2027-->Support for reverse-complement coding regions in ENA and EMBL</li>
+            <li><!-- JAL-1855, JAL-2113, JAL-2114-->Upgrade to EMBL XML 1.2 for ENA record retrieval</li>
+            <li><!--  JAL 1812 -->New 'execute Groovy script' option in an alignment window's Calculate menu</li>
+            <li><!--  JAL 1812 -->Allow groovy scripts that call Jalview.getAlignFrames() to run in headless mode</li>
+             
+        </ul> <em>Applet</em>
+        <ul>
+            <li><!-- JAL---></li>
+        </ul></td>
       <td>
-      <em>General</em>
-      <ul>
-            <li>Time stamps for signed Jalview application and applet jars</li>
-      </ul>
+        <div align="left">
+          <em>General</em>
+          <ul>
+            <li><!-- JAL-2077 -->reinstate CTRL-click for opening pop-up menu on OSX</li>
+            <li><!-- JAL-2018-->Export features in Jalview format (again) includes graduated colourschemes</li>
+            <li><!-- JAL-1722, JAL-2001-->More responsive when working with big alignments and lots of hidden columns</li>
+            <li><!-- JAL-2053-->hidden column markers not always rendered at right of alignment window</li>
+            <li><!-- JAL-2067, JAL-  -->Tidied up links in help file table of contents</li>
+            <li><!-- JAL-2072  -->Feature based tree calculation not shown for DNA alignments</li>
+            <li><!-- JAL-2075  -->Hidden columns ignored during feature based tree calculation</li>
+            
+          </ul>
+          <em>Application</em>
+          <ul>
+            <li><!-- JAL-1944 not yet fixed Error thrown when exporting a view with hidden sequences as flat-file alignment--></li>
+            <li><!-- JAL-1911-->Corrupt preferences for SVG, EPS & HTML output when running on non-gb/us i18n platforms</li>
+            <li><!-- JAL-1552-->URLs and links can imported by drag'n'drop on OSX webstart</li>
+            <li><!-- JAL-2030-->InstallAnywhere distribution fails when launching Chimera</li>
+            <li><!-- JAL-2080-->Jalview very slow to launch via webstart (also hotfix for 2.9.0b2)</li>
+            <!--  may exclude, this is an external service stability issue  JAL-1941 /> RNA 3D structure not added via DSSR service</li> -->
+          </ul>
+          <em>Applet</em>
+          <ul>
+            <li><!--  --></li>
+          </ul>
+        </div>
+      </td>
+    </tr>
+    <tr>
+      <td width="60" nowrap>
+        <div align="center">
+          <strong><a name="Jalview.2.9.0b2">2.9.0b2</a><br />
+            <em>16/10/2015</em></strong>
+        </div>
       </td>
+      <td><em>General</em>
+        <ul>
+          <li>Time stamps for signed Jalview application and applet
+            jars</li>
+        </ul></td>
       <td>
         <div align="left">
-        <em>Application</em><ul>
-          <li>Duplicate group consensus and conservation rows shown when tree is partitioned</li>
-            <li>Erratic behaviour when tree partitions made with multiple cDNA/Protein split views</li>
-            </ul>
+          <em>Application</em>
+          <ul>
+            <li>Duplicate group consensus and conservation rows
+              shown when tree is partitioned</li>
+            <li>Erratic behaviour when tree partitions made with
+              multiple cDNA/Protein split views</li>
+          </ul>
         </div>
       </td>
     </tr>
             <em>8/10/2015</em></strong>
         </div>
       </td>
-      <td>
-      <em>General</em>
+      <td><em>General</em>
+        <ul>
+          <li>Updated Spanish translations of localized text for
+            2.9</li>
+        </ul> <em>Application</em>
       <ul>
-            <li>Updated Spanish translations of localized text for 2.9</li>
-      </ul>
-      <em>Application</em><ul>
-      <!-- <li>cDNA/Protein splitframe window geometry preserved in Jalview projects</li>-->
-      <li>Signed OSX InstallAnywhere installer<br></li>
-      <li>Support for per-sequence based annotations in BioJSON</li></ul>
-        <em>Applet</em>
-        <ul><li>Split frame example added to applet examples page</li>
-            </ul>
-      </td>
+          <!-- <li>cDNA/Protein splitframe window geometry preserved in Jalview projects</li>-->
+          <li>Signed OSX InstallAnywhere installer<br></li>
+          <li>Support for per-sequence based annotations in BioJSON</li>
+        </ul> <em>Applet</em>
+        <ul>
+          <li>Split frame example added to applet examples page</li>
+        </ul></td>
       <td>
         <div align="left">
-        <em>General</em>
+          <em>General</em>
           <ul>
-            <li>Mapping of cDNA to protein in split frames incorrect when sequence start > 1</li>
-            <li>Broken images in filter column by annotation dialog documentation</li>
+            <li>Mapping of cDNA to protein in split frames
+              incorrect when sequence start > 1</li>
+            <li>Broken images in filter column by annotation dialog
+              documentation</li>
             <li>Feature colours not parsed from features file</li>
-            <li>Exceptions and incomplete link URLs recovered when loading a features file containing HTML tags in feature description</li>
-            
+            <li>Exceptions and incomplete link URLs recovered when
+              loading a features file containing HTML tags in feature
+              description</li>
+
           </ul>
-      <em>Application</em><ul>
-            <li>Annotations corrupted after BioJS export and reimport</li>
-            <li>Incorrect sequence limits after Fetch DB References with 'trim retrieved sequences'</li>
-            <li>Incorrect warning about deleting all data when deleting selected columns</li>
-            <li>Patch to build system for shipping properly signed JNLP templates for webstart launch</li>
-            <li>EMBL-PDBe fetcher/viewer dialogs do not offer unreleased structures for download or viewing</li>
-            <li>Tab/space/return keystroke operation of EMBL-PDBe fetcher/viewer dialogs works correctly</li>
-            <li>Disabled 'minimise' button on Jalview windows running on OSX to workaround redraw hang bug</li>
-            <li>Split cDNA/Protein view position and geometry not recovered from jalview project</li>
-            <li>Initial enabled/disabled state of annotation menu sorter 'show autocalculated first/last' corresponds to alignment view</li>
-            <li>Restoring of Clustal, RNA Helices and T-Coffee color schemes from BioJSON</li>
-            </ul>
-      <em>Applet</em><ul>
-            <li>Reorder sequences mirrored in cDNA/Protein split frame</li>
+          <em>Application</em>
+          <ul>
+            <li>Annotations corrupted after BioJS export and
+              reimport</li>
+            <li>Incorrect sequence limits after Fetch DB References
+              with 'trim retrieved sequences'</li>
+            <li>Incorrect warning about deleting all data when
+              deleting selected columns</li>
+            <li>Patch to build system for shipping properly signed
+              JNLP templates for webstart launch</li>
+            <li>EMBL-PDBe fetcher/viewer dialogs do not offer
+              unreleased structures for download or viewing</li>
+            <li>Tab/space/return keystroke operation of EMBL-PDBe
+              fetcher/viewer dialogs works correctly</li>
+            <li>Disabled 'minimise' button on Jalview windows
+              running on OSX to workaround redraw hang bug</li>
+            <li>Split cDNA/Protein view position and geometry not
+              recovered from jalview project</li>
+            <li>Initial enabled/disabled state of annotation menu
+              sorter 'show autocalculated first/last' corresponds to
+              alignment view</li>
+            <li>Restoring of Clustal, RNA Helices and T-Coffee
+              color schemes from BioJSON</li>
+          </ul>
+          <em>Applet</em>
+          <ul>
+            <li>Reorder sequences mirrored in cDNA/Protein split
+              frame</li>
             <li>Applet with Jmol examples not loading correctly</li>
-            </ul>
+          </ul>
         </div>
       </td>
     </tr>
     <tr>
       <td><div align="center">
           <strong><a name="Jalview.2.8.0b1">2.8.0b1</a><br />
-          <em>30/1/2014</em></strong>
+            <em>30/1/2014</em></strong>
         </div></td>
       <td>
         <ul>
         <ul>
           <li>URL links generated from description line for
             regular-expression based URL links (applet and application)
+
           
           <li>Non-positional feature URL links are shown in link
             menu</li>
             between different screens.</li>
           <li>New preference items for sequence ID tooltip and
             consensus annotation</li>
-          <li>Client to submit sequences and IDs to <a
-            href="webServices/index.html#envision2">Envision2</a>
-            Workflows
-          </li>
+          <li>Client to submit sequences and IDs to Envision2 Workflows</li>
           <li><em>Vamsas Capabilities</em>
             <ul>
               <li>Improved VAMSAS synchronization (Jalview archive
           <li>Cancel button for DAS Feature Fetching
           <li>PCA and PDB Viewers zoom via mouse roller
           <li>User-defined sub-tree colours and sub-tree selection
+
           
           <li>'New Window' button on the 'Output to Text box'
         </ul>
           <li>Fixed Remove Empty Columns Bug (empty columns at end
             of alignment)
           <li>Slowed DAS Feature Fetching for increased robustness.
+
           
           <li>Made angle brackets in ASCII feature descriptions
             display correctly
           <li>WsDbFetch query/result association resolved
           <li>Tree leaf to sequence mapping improved
           <li>Smooth fonts switch moved to FontChooser dialog box.
+
           
         </ul>
       </td>
index 5dd4472..6d4a461 100644 (file)
@@ -32,7 +32,7 @@
       Function, and Genetics</em> 43(2): 227-241. <a
       href="http://www.ncbi.nlm.nih.gov/pubmed/12112692"
     >PubMed</a> or available on the <a
-      href="http://www.well.ox.ac.uk/~valdar/publications.html"
+      href="http://valdarlab.unc.edu/publications.html"
     >Valdar Group publications page</a>), but the SMERFs score was
     developed later and described by Manning et al. in 2008 (<a
       href="http://www.biomedcentral.com/1471-2105/9/51"
index 04ccd8f..b03bb9d 100755 (executable)
@@ -88,7 +88,7 @@
     >REST</a> web services exposing sequence alignment, analysis, and
     secondary structure prediction programs. Originally, Jalview 2's
     services were maintained by the Barton group at the University of
-    Dundee, and ran programs on the Life Sciences High-performace
+    Dundee, and ran programs on the Life Sciences High-performance
     Computing Cluster. With the advent of <a
       href="http://www.compbio.dundee.ac.uk/JABAWS"
     >JABAWS</a>, however, it is possible for anyone to host Jalview web
index b685576..6266036 100644 (file)
       from the input</li>
     <li><em>realignment</em> - where any aligned sequences will be
       used by the service to construct a profile based alignment of the
-      remaining unaligned sequences.</li>
+      remaining unaligned sequences</li>
   </ul>
   <strong>JABAWS Alignment services</strong>
   <br> Most alignment services are provided by the
   <a href="JABAWS.html">JABAWS framework</a>, which allows you to
   customise the precise parameters used when running each alignment
-  prgoram. In addition to the 'Default settings', you may choose from a
+  program. In addition to the 'Default settings', you may choose from a
   range of alignment preset settings, or create your own using the
   <a href="webServicesParams.html">'Edit Settings And Run ..' dialog
     box</a>.
@@ -58,7 +58,7 @@
   <ul>
     <li><a href="http://www.clustal.org/">Clustal Omega and
         Clustal W</a> (version 2.0.12)</li>
-    <li><a href="http://align.bmr.kyushu-u.ac.jp/mafft/software/">Mafft</a>
+    <li><a href="http://mafft.cbrc.jp/alignment/software/">Mafft</a>
       (version 6.8.57b)</li>
     <li><a href="http://www.drive5.com/muscle">Muscle</a> (version
       3.8.31)</li>
index de0f8cd..7a23d58 100644 (file)
@@ -83,7 +83,7 @@
     <em>Please Note:
       <ul>
         <li>The regular expressions supported by Jalview are those
-          provided by the <a href="www.javaregex.com">Stevesoft
+          provided by the <a href="http://www.javaregex.com">Stevesoft
             javaregex package</a>.
         </li>
         <li>Some characters must be escaped when specifying them as
index f77f5f0..1470745 100644 (file)
Binary files a/lib/Jmol-14.2.14_2015.06.11.jar and b/lib/Jmol-14.2.14_2015.06.11.jar differ
index b73b58d..9d41f6b 100644 (file)
Binary files a/lib/VARNAv3-93.jar and b/lib/VARNAv3-93.jar differ
index 1cfc700..5070435 100644 (file)
Binary files a/lib/castor-1.1-cycle-xml.jar and b/lib/castor-1.1-cycle-xml.jar differ
diff --git a/lib/groovy-all-1.8.2.jar b/lib/groovy-all-1.8.2.jar
deleted file mode 100755 (executable)
index 85af249..0000000
Binary files a/lib/groovy-all-1.8.2.jar and /dev/null differ
diff --git a/lib/groovy-all-2.4.6-indy.jar b/lib/groovy-all-2.4.6-indy.jar
new file mode 100644 (file)
index 0000000..5f3d51c
Binary files /dev/null and b/lib/groovy-all-2.4.6-indy.jar differ
index 7ad030a..ea5a1f4 100644 (file)
Binary files a/lib/min-jabaws-client-2.1.0.jar and b/lib/min-jabaws-client-2.1.0.jar differ
index 429fe77..182e0da 100644 (file)
Binary files a/lib/quaqua-filechooser-only-8.0.jar and b/lib/quaqua-filechooser-only-8.0.jar differ
old mode 100755 (executable)
new mode 100644 (file)
index ccbde5e..01b921a 100644 (file)
 <!--
        History: Originally created from EMBL_common_V1.0
        Updated on 24th April 2007 for WsDBFetch Service move to EMBL_Services_V1.1.xsd
+       Updated May 2016 for EMBL XML 1.2 JAL-2113 JAL-2114
+         see ftp://ftp.sra.ebi.ac.uk/meta/xsd/sra_1_5/ENA.embl.xsd
+         see http://www.ebi.ac.uk/ena/submit/data-formats
        -->
        <class name="jalview.datamodel.xdb.embl.EmblFile">
-               <map-to xml="EMBL_Services"/>
+               <map-to xml="ROOT"/>
                <field name="entries" type="jalview.datamodel.xdb.embl.EmblEntry" collection="vector">
                        <bind-xml name="entry"/>
                </field>
-               
                <field name="errors" type="jalview.datamodel.xdb.embl.EmblError" collection="vector">
                        <bind-xml name="Error"/>
                </field>
        </class>
        <class name="jalview.datamodel.xdb.embl.EmblEntry">
                <field name="accession" type="string">
-                       <bind-xml location="accession" node="attribute"/>
+                       <bind-xml name="accession" node="attribute"/>
                </field>
-               <!--  May 2015 changed from last-updated to match xml -->
-               <field name="lastUpdated" type="string">
-                       <bind-xml location="lastUpdated" node="attribute"/>
+               <!-- 
+                   in EMBL XML 1.2 sequence/@version became entry/version 
+                   entry/@version became entry/@entryVersion
+               -->
+               <field name="sequenceVersion" type="string">
+                       <bind-xml name="version" node="attribute"/>
                </field>
-               <field name="version" type="string">
-                       <bind-xml location="version" node="attribute"/>
+               <field name="entryVersion" type="string">
+                       <bind-xml name="entryVersion" node="attribute"/>
+               </field>
+               <field name="dataClass" type="string">
+                       <bind-xml name="dataClass" node="attribute"/>
+               </field>
+               <field name="taxonomicDivision" type="string">
+                       <bind-xml name="taxonomicDivision" node="attribute"/>
+               </field>
+               <field name="moleculeType" type="string">
+                       <bind-xml name="moleculeType" node="attribute"/>
+               </field>
+               <field name="sequenceLength" type="string">
+                       <bind-xml name="sequenceLength" node="attribute"/>
+               </field>
+               <field name="topology" type="string">
+                       <bind-xml name="topology" node="attribute" location="type"/>
+               </field>
+               <field name="firstPublicDate" type="string">
+                       <bind-xml name="firstPublic" node="attribute"/>
                </field>
-               <field name="rCreated" type="string">
-                       <bind-xml location="releaseCreated" node="attribute"/>
+               <field name="firstPublicRelease" type="string">
+                       <bind-xml name="firstPublicRelease" node="attribute"/>
                </field>
-               <field name="rLastUpdated" type="string">
-                       <bind-xml location="releaseLastUpdated" node="attribute"/>
+               <field name="lastUpdatedDate" type="string">
+                       <bind-xml name="lastUpdated" node="attribute"/>
                </field>
-               <field name="desc" type="string">
+               <field name="lastUpdatedRelease" type="string">
+                       <bind-xml name="lastUpdatedRelease" node="attribute"/>
+               </field>
+               <field name="description" type="string">
                        <bind-xml name="description" node="element"/>
                </field>
                <field name="keywords" type="string" collection="vector">
                        <bind-xml name="feature"/>
                </field>
                <field name="dbRefs" type="jalview.datamodel.DBRefEntry" collection="vector">
-                       <bind-xml name="dbreference" />
+                       <bind-xml name="xref" />
                </field>
                <field name="sequence" type="jalview.datamodel.xdb.embl.EmblSequence">
                        <bind-xml name="sequence"/>
                </field>
        </class>
        <class name="jalview.datamodel.xdb.embl.EmblSequence">
-               <field name="type" type="string">
-                       <bind-xml name="type" node="attribute" location="type"/>
-               </field>
-               <field name="version" type="string">
-                       <bind-xml name="version" node="attribute" location="version"/>
-               </field>
                <field name="sequence" type="string">
                        <bind-xml node="text"/>
                </field>
                <field name="name" type="string">
                        <bind-xml name="name" node="attribute"/>
                </field>
+               <field name="location" type="string">
+                       <bind-xml name="location" node="attribute"/>
+               </field>
                <field name="dbRefs" type="jalview.datamodel.DBRefEntry" collection="vector">
-                       <bind-xml name="dbreference" node="element"/>
+                       <bind-xml name="xref" node="element"/>
                </field>
                <field name="qualifiers" type="jalview.datamodel.xdb.embl.Qualifier" collection="vector">
                        <bind-xml name="qualifier"/>
                </field>                                        
-               <field name="locations" type="jalview.datamodel.xdb.embl.EmblFeatureLocations" collection="vector">
-                       <bind-xml name="location"/>
-               </field>
        </class>
        <class name="jalview.datamodel.DBRefEntry" verify-constructable="false">
                <field name="accessionId" type="java.lang.String">
-                       <bind-xml name="primary" node="attribute"/>
+                       <bind-xml name="id" node="attribute"/>
                </field>
                <field name="source" type="java.lang.String"> 
                        <bind-xml name="db" node="attribute"/>
                </field>
                <field name="version" type="string">
-                       <bind-xml name="secondary" node="attribute"/>
+                       <bind-xml name="secondaryId" node="attribute"/>
                </field>
        </class>
        <class  name="jalview.datamodel.xdb.embl.Qualifier" verify-constructable="false">
                        <bind-xml name="value" node="element"/>
                </field>
        </class>
-       <class name="jalview.datamodel.xdb.embl.EmblFeatureLocations">
-               <field name="locationType" type="string">
-                       <bind-xml name="type" node="attribute"/>
-               </field>
-               <field name="locationComplement" type="boolean">
-                       <bind-xml name="complement" node="attribute"/>
-               </field>
-               <field name="locElements" type="jalview.datamodel.xdb.embl.EmblFeatureLocElement" collection="vector">
-                       <bind-xml name="locationElement"/>
-               </field>
-       </class>
-       <class name="jalview.datamodel.xdb.embl.EmblFeatureLocElement">
-               <field name="type" type="string">
-                       <bind-xml name="type" node="attribute"/>
-               </field>
-               <field name="accession" type="string">
-                       <bind-xml name="accession" node="attribute"/>                   
-               </field>
-               <field name="version" type="string">
-                       <bind-xml name="version" node="attribute"/>
-               </field>
-               <field name="complement" type="boolean">
-                       <bind-xml name="complement"/>
-               </field>
-               <field name="basePositions" type="jalview.datamodel.xdb.embl.BasePosition" collection="array">
-                       <bind-xml name="basePosition" node="element"/>
-               </field>
-       </class>
-       <class name="jalview.datamodel.xdb.embl.BasePosition">
-               <field name="type">
-                       <bind-xml name="type" node="attribute"/>
-               </field>
-               <field name="pos">
-                       <bind-xml node="text"/>
-               </field>
-       </class>
 </mapping>
similarity index 75%
rename from resources/fts/pdb_data_columns.conf
rename to resources/fts/pdb_data_columns.txt
index 95f2dd1..5ac50bb 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+
 pdb_data_columns
 #
 _group.id
@@ -6,9 +27,9 @@ _group.sort_order
 g1;Quality Measures;1
 g2;Cross References;2
 g3;Names & Taxonomy;3
-g4;Procedures & Softwares;4
+g4;Procedures & Software;4
 g5;Date Of;5
-g6;Miscellenous;6
+g6;Miscellaneous;6
 #
 _data_column.primary_key;pdb_id
 _data_column.default_response_page_size;100
@@ -16,7 +37,7 @@ _data_column.default_response_page_size;100
 _data_column.name
 _data_column.code
 _data_column.group_id
-_data_column.data_type
+_data_column.data_type | _data_column.isFormated | _data_column.significantDigit
 _data_column.min_col_width
 _data_column.max_col_width
 _data_column.preferred_col_width
@@ -35,17 +56,17 @@ UniProt Id;uniprot_id;String;g2;50;400;95;false;true
 UniProt Accession;uniprot_accession;String;g2;50;400;95;false;false
 UniProt Coverage;uniprot_coverage;String;g6;50;400;95;false;false
 Uniprot Features;uniprot_features;String;g6;50;400;95;false;false
-R Factor;r_factor;Double;g1;50;150;85;false;false
-Resolution;resolution;Double;g1;50;150;85;true;false
-Data Quality;data_quality;Double;g1;50;150;85;false;false
-Overall Quality;overall_quality;Double;g1;50;150;85;false;false
+R Factor;r_factor;Double|T|3;g1;50;150;85;false;false
+Experimental Method;experimental_method;String;g4;50;400;105;true;false
+Resolution;resolution;Double|T|3;g1;50;150;85;true;false
+Data Quality;data_quality;Double|T|2;g1;50;150;85;false;false
+Overall Quality;overall_quality;Double|T|1;g1;50;150;85;false;false
 Number of Polymers;number_of_polymers;int;g6;50;400;95;false;false
 Number of Protein Chains;number_of_protein_chains;int;g6;50;400;95;false;false
 Number of Bound Molecule;number_of_bound_molecules;int;g6;50;400;95;false;false
 Number of Polymer Residue;number_of_polymer_residues;int;g6;50;400;95;false;false
 GENUS;genus;String;g3;50;400;95;false;true
 Gene Name;gene_name;String;g3;50;400;95;false;true
-Experimental Method;experimental_method;String;g4;50;400;95;false;false
 GO Id;go_id;String;g2;50;400;95;false;false
 Assembly Id;assembly_id;String;g2;50;400;95;false;false
 Assembly Form;assembly_form;String;g6;50;400;95;false;false
@@ -58,10 +79,10 @@ Interacting Entity Id;interacting_entity_id;String;g2;50;400;95;false;false
 Interacting Molecules;interacting_molecules;String;g6;50;400;95;false;false
 Pubmed Id;pubmed_id;int;g2;50;400;95;false;false
 Status;status;String;g6;50;400;95;false;false
-Model Quality;model_quality;Double;g1;50;150;85;false;false
-Pivot Resolution;pivot_resolution;Double;g1;50;150;85;false;false
+Model Quality;model_quality;Double|T|2;g1;50;150;85;false;false
+Pivot Resolution;pivot_resolution;Double|T|3;g1;50;150;85;false;false
 Data reduction software;data_reduction_software;String;g4;50;400;95;false;false
-Max observed residues;max_observed_residues;String;g6;50;400;95;false;false
+Max observed residues;max_observed_residues;Integer|F;g6;50;400;95;false;false
 Organism scientific name;organism_scientific_name;String;g3;50;400;95;false;false
 Super kingdom;superkingdom;String;g3;50;400;95;false;false
 Rank;rank;String;g3;50;400;95;false;false
@@ -86,7 +107,7 @@ Entry Authors;entry_authors;String;g6;50;400;95;false;false
 Citation Title;citation_title;String;g6;50;400;95;false;false
 Structure Solution Software;structure_solution_software;String;g4;50;400;95;false;false
 Entry Entity;entry_entity;String;g6;50;400;95;false;false
-R Free;r_free;Double;g1;50;150;85;false;false
+R Free;r_free;Double|T|3;g1;50;150;85;false;false
 Number of Polymer Entities;number_of_polymer_entities;int;g6;50;400;95;false;false
 Number of Bound Entities;number_of_bound_entities;int;g6;50;400;95;false;false
 Crystallisation Reservoir;crystallisation_reservoir;String;g6;50;400;95;false;false
@@ -103,7 +124,7 @@ Synchrotron Beamline;synchrotron_beamline;String;g6;50;400;95;false;false
 Entity Id; entity_id;String;g2;50;400;95;false;false
 Beam Source Name;beam_source_name;String;g3;50;400;95;false;false
 Processing Site;processing_site;String;g6;50;400;95;false;false
-Entity Weight;entity_weight;Double;g6;50;400;95;false;false
-Version;_version_;String;g6;50;400;95;false;false
+Entity Weight;entity_weight;Double|T|0;g6;50;400;95;false;false
+Version;_version_;Double|F|0;g6;50;400;95;false;false
 ALL;text;String;g6;50;400;95;false;true
 #
similarity index 74%
rename from resources/fts/uniprot_data_columns.conf
rename to resources/fts/uniprot_data_columns.txt
index 10f5043..f506648 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+
 uniprot_data_columns
 #
 _group.id
@@ -8,7 +29,7 @@ g2;Cross References;2
 g3;Names & Taxonomy;1
 g4;Procedures & Softwares;4
 g5;Date Of;5
-g6;Miscellenous;6
+g6;Miscellaneous;6
 g7;Sequences;7
 g8;Function;8
 g9;Interaction;9
@@ -22,11 +43,11 @@ g16;Publications;16
 g17;Date of;17
 g18;Family & Domain;18
 #
-_data_column.primary_key;entry name
-_data_column.default_response_page_size;100
+_data_column.primary_key;id
+_data_column.default_response_page_size;500
 #
 _data_column.name
-_data_column.code
+_data_column.code|_data_column.alt_code (optional: used for specifying search code when different from original code)
 _data_column.group_id
 _data_column.data_type
 _data_column.min_col_width
@@ -34,16 +55,17 @@ _data_column.max_col_width
 _data_column.preferred_col_width
 _data_column.is_shown_by_default
 _data_column.is_searchable
-Entry Name;entry name;String;g3;80;100;85;true;true
-Protein names;protein names;String;g3;300;1500;500;true;true
-Gene Names;genes;String;g3;50;1000;95;true;true
-Organism;organism;String;g3;50;1000;95;true;true
-Organism ID;organism-id;int;g3;60;100;80;false;true
-Proteomes;proteome;String;g3;50;1000;95;false;true
-Taxonomic lineage (ALL);lineage(ALL);String;g3;50;400;95;false;false
-Virus hosts;virus hosts;String;g3;50;1000;95;false;true
-Fragment;fragment;String;g7;50;1000;95;false;true
-Gene encoded by;encodedon;String;g7;50;1000;95;false;true
+Uniprot Id;id;String;g3;80;150;85;true;true
+Entry Name;entry name|mnemonic;String;g3;100;150;105;true;true
+Protein names;protein names|name;String;g3;300;1500;500;true;true
+Gene Names;genes|gene;String;g3;100;1000;145;true;true
+Organism;organism;String;g3;100;1000;200;true;true
+Organism ID;organism-id;int;g3;60;100;80;false;false
+Proteomes;proteome;String;g3;50;1000;95;false;false
+Taxonomic lineage (ALL);lineage(ALL)|taxonomy;String;g3;50;400;95;false;false
+Virus hosts;virus hosts|host;String;g3;50;1000;95;false;true
+Fragment;fragment;String;g7;50;1000;95;false;false
+Gene encoded by;encodedon;String;g7;50;1000;95;false;false
 Alternative products (isoforms);comment(ALTERNATIVE PRODUCTS);String;g7;50;1000;95;false;false
 Erroneous gene model prediction;comment(ERRONEOUS GENE MODEL PREDICTION);String;g7;50;1000;95;false;false
 Erroneous initiation;comment(ERRONEOUS INITIATION);String;g7;50;1000;95;false;false
@@ -53,9 +75,10 @@ Mass spectrometry;comment(MASS SPECTROMETRY);String;g7;50;1000;95;false;false
 Polymorphism;comment(POLYMORPHISM);String;g7;50;1000;95;false;false
 RNA editing;comment(RNA EDITING);String;g7;50;1000;95;false;false
 Sequence caution;comment(SEQUENCE CAUTION);String;g7;50;1000;95;false;false
-Length;length;int;g7;50;100;95;false;true
-Mass;mass;String;g7;50;100;80;false;true
-Sequence;sequence;String;g7;50;1000;95;false;true
+Status;reviewed;String;g6;50;100;95;true;true
+Length;length;int|T|0;g7;50;100;65;true;true
+Mass;mass;int|T|0;g7;50;100;80;false;true
+Sequence;sequence;String;g7;50;1000;95;false;false
 Alternative sequence;feature(ALTERNATIVE SEQUENCE);String;g7;50;1000;95;false;false
 Natural variant;feature(NATURAL VARIANT);String;g7;50;1000;95;false;false
 Non-adjacent residues;feature(NON ADJACENT RESIDUES);String;g7;50;1000;95;false;false
@@ -81,16 +104,15 @@ DNA binding;feature(DNA BINDING);String;g8;50;1000;95;false;false
 Metal binding;feature(METAL BINDING);String;g8;50;1000;95;false;false
 Nucleotide binding;feature(NP BIND);String;g8;50;1000;95;false;false
 Site;feature(SITE);String;g8;50;1000;95;false;false
-Annotation;annotation score;String;g6;50;1000;95;false;true
-Features;features;String;g6;50;1000;95;false;true
+Annotation;annotation score;String;g6;50;1000;95;false;false
+Features;features;String;g6;50;1000;95;false;false
 Caution;comment(CAUTION);String;g6;50;1000;95;false;false
 Miscellaneous [CC];comment(GENERAL);String;g6;50;1000;95;false;false
-Keywords;keywords;String;g6;50;1000;95;false;true
+Keywords;keywords|keyword;String;g6;50;1000;95;false;true
 Protein existence;existence;String;g6;50;1000;95;false;true
-Status;reviewed;String;g6;50;1000;95;false;true
-ALL;entry name;String;g7;50;1000;95;false;true;
+ALL;Search All;String;g7;50;1000;95;false;true
 Subunit structure [CC];comment(SUBUNIT);String;g9;50;1000;95;false;false
-Interacts with;interactor;String;g9;50;1000;95;false;true
+Interacts with;interactor;String;g9;50;1000;95;false;false
 Developmental stage;comment(DEVELOPMENTAL STAGE);String;g10;50;1000;95;false;false
 Induction;comment(INDUCTION);String;g10;50;1000;95;false;false
 Tissue specificity;comment(TISSUE SPECIFICITY);String;g10;50;1000;95;false;false
@@ -126,13 +148,13 @@ Beta strand;feature(BETA STRAND);String;g15;50;1000;95;false;false
 Helix;feature(HELIX);String;g15;50;1000;95;false;false
 Turn;feature(TURN);String;g15;50;1000;95;false;false
 PubMed ID;citation;String;g16;50;1000;95;false;true
-Date of creation;created;String;g17;80;150;100;true;true
-Date of last modification;last-modified;String;g17;80;150;100;true;true
+Date of creation;created;String;g17;80;150;100;false;true
+Date of last modification;last-modified;String;g17;80;150;100;false;true
 Date of last sequence modification;sequence-modified;String;g17;80;150;100;false;true
 Version (entry);version(entry);int;g17;80;100;80;false;false
-Domain [CC];comment(DOMAIN);String;g18;80;1000;95;false;false
+Domain [cc];comment(DOMAIN)|domain;String;g18;80;1000;95;false;true
 Sequence similarities;comment(SIMILARITY);String;g18;50;1000;95;false;false
-Protein families;families;String;g18;50;1000;95;false;true
+Protein families;families|family;String;g18;50;1000;95;false;true
 Coiled coil;feature(COILED COIL);String;g18;50;1000;95;false;false
 Compositional bias;feature(COMPOSITIONAL BIAS);String;g18;50;1000;95;false;false
 Domain [FT];feature(DOMAIN EXTENT);String;g18;50;1000;95;false;false
diff --git a/resources/images/blank_16x16_placeholder.png b/resources/images/blank_16x16_placeholder.png
new file mode 100644 (file)
index 0000000..885ad87
Binary files /dev/null and b/resources/images/blank_16x16_placeholder.png differ
index 3c79b58..c9d9e94 100644 (file)
@@ -675,7 +675,7 @@ label.view_all_representative_structures = View all {0} representative structure
 label.open_new_jmol_view_with_all_representative_structures_associated_current_selection_superimpose_using_alignment = Opens a new structure viewer with all representative structures\nassociated with the current selection\nsuperimposed with the current alignment.
 label.associate_structure_with_sequence = Associate Structure with Sequence
 label.from_file = From File
-label.enter_pdb_id = Enter PDB Id
+label.enter_pdb_id = Enter PDB Id (Note: Specific chains can be retrieved by appending the chain code to the PDB Id delimited with a colon i.e. 1abc:X)
 label.discover_pdb_ids = Discover PDB IDs
 label.text_colour = Text Colour
 action.set_text_colour = Text Colour...
@@ -790,7 +790,7 @@ label.select_backgroud_colour = Select Background Colour
 label.invalid_font = Invalid Font
 label.separate_multiple_accession_ids = Enter one or more accession IDs separated by a semi-colon ";"
 label.separate_multiple_query_values = Enter one or more {0}s separated by a semi-colon ";"
-label.search_all = Enter one or more search values separated by a semi-colon ";" (Note: This Searches the entire PDB database)
+label.search_all = Enter one or more search values separated by a semi-colon ";" (Note: This Searches the entire database)
 label.replace_commas_semicolons = Replace commas with semi-colons
 label.parsing_failed_syntax_errors_shown_below_param = Parsing failed. Syntax errors shown below {0}
 label.parsing_failed_unrecoverable_exception_thrown_param = \nParsing failed. An unrecoverable exception was thrown\:\n {0}
@@ -801,6 +801,8 @@ label.wswublast_client_credits = To display sequence features an exact Uniprot i
 label.blasting_for_unidentified_sequence = BLASTing for unidentified sequences
 label.select_columns_containing = Select columns containing
 label.select_columns_not_containing = Select columns that do not contain
+label.hide_columns_containing = Hide columns containing
+label.hide_columns_not_containing = Hide columns that do not contain
 option.trim_retrieved_seqs = Trim retrieved sequences
 label.trim_retrieved_sequences = When the reference sequence is longer than the sequence that you are working with, only keep the relevant subsequences.
 label.use_sequence_id_1 = Use $SEQUENCE_ID$ or $SEQUENCE_ID=/<regex>/=$
@@ -970,7 +972,6 @@ error.eps_generation_not_implemented = EPS Generation not yet implemented
 error.png_generation_not_implemented = PNG Generation not yet implemented
 error.try_join_vamsas_session_another = Trying to join a vamsas session when another is already connected
 error.invalid_vamsas_session_id = Invalid vamsas session id
-error.implementation_error_cannot_create_groovyshell = Implementation Error. Cannot create groovyShell without Groovy on the classpath!
 label.groovy_support_failed = Jalview Groovy Support Failed
 label.couldnt_create_groovy_shell = Couldn't create the groovy Shell. Check the error log for the details of what went wrong.
 error.unsupported_version_calcIdparam = Unsupported Version for calcIdparam {0}
@@ -1027,7 +1028,7 @@ error.implementation_error_need_to_have_httpresponse = Implementation Error: nee
 error.dbrefsource_implementation_exception =DBRefSource Implementation Exception
 error.implementation_error_dbinstance_must_implement_interface = Implmentation Error - getDbInstances must be given a class that implements jalview.ws.seqfetcher.DbSourceProxy (was given{0})
 error.implementation_error_must_init_dbsources =Implementation error. Must initialise dbSources
-label.view_controller_toggled_marked = {0} {1} columns {2} containing features of type {3}  across {4} sequence(s)
+label.view_controller_toggled_marked = {0} {1} columns containing features of type {2}  across {3} sequence(s)
 label.toggled = Toggled
 label.marked = Marked
 label.not = not
@@ -1279,20 +1280,31 @@ label.structure_chooser_filter_time = Structure Chooser - Filter time ({0})
 label.structure_chooser_no_of_structures = Structure Chooser - {0} Found ({1})
 info.no_pdb_entry_found_for = No PDB entry found for {0}
 exception.unable_to_detect_internet_connection = Jalview is unable to detect an internet connection
-exception.pdb_rest_service_no_longer_available = PDB rest services no longer available!
+exception.fts_rest_service_no_longer_available = {0} rest services no longer available!
 exception.resource_not_be_found = The requested resource could not be found
-exception.pdb_server_error = There seems to be an error from the PDB server
-exception.pdb_server_unreachable = Jalview is unable to reach the PDBe Solr server. \nPlease ensure that you are connected to the internet and try again.
+exception.fts_server_error = There seems to be an error from the {0} server
+exception.fts_server_unreachable = Jalview is unable to reach the {0} server. \nPlease ensure that you are connected to the internet and try again.
 label.nw_mapping = Needleman & Wunsch Alignment
 label.sifts_mapping = SIFTs Mapping
 label.mapping_method = Sequence \u27f7 Structure mapping method
-label.mapping_method = Sequence \u27f7 Structure mapping method
-status.waiting_for_user_to_select_output_file = Waiting for user to select {0} file.
-status.cancelled_image_export_operation = Cancelled {0} export operation.
-info.error_creating_file = Error creating {0} file.
+status.waiting_for_user_to_select_output_file = Waiting for user to select {0} file
+status.cancelled_image_export_operation = Cancelled {0} export operation
+info.error_creating_file = Error creating {0} file
 exception.outofmemory_loading_mmcif_file = Out of memory loading mmCIF File
-info.error_creating_file = Error creating {0} file.
 label.run_groovy = Run Groovy console script
 label.run_groovy_tip = Run the script in the Groovy console over this alignment
 label.couldnt_run_groovy_script = Failed to run Groovy script
-label.uniprot_sequence_fetcher = UniProt Sequence Fetcher
\ No newline at end of file
+label.uniprot_sequence_fetcher = UniProt Sequence Fetcher
+action.next_page= >> 
+action.prev_page= << 
+label.next_page_tooltip=Next Page
+label.prev_page_tooltip=Previous Page
+exception.bad_request=Bad request. There is a problem with your input.
+exception.service_not_available=Service not available. The server is being updated, try again later.
+status.launching_3d_structure_viewer = Launching 3D Structure viewer...
+status.fetching_3d_structures_for_selected_entries = Fetching 3D Structures for selected entries...
+status.fetching_dbrefs_for_sequences_without_valid_refs = Fetching db refs for {0} sequence(s) without valid db ref required for SIFTS mapping
+status.fetching_3d_structures_for = Fetching 3D Structure for {0}
+status.obtaining_mapping_with_sifts = Obtaining mapping with SIFTS
+status.obtaining_mapping_with_nw_alignment = Obtaining mapping with NW alignment
+status.exporting_alignment_as_x_file = Exporting alignment as {0} file
index 3535f4b..f814c97 100644 (file)
@@ -277,7 +277,7 @@ label.order_by_params = Ordenar por {0}
 label.html_content = <html>{0}</html>
 label.paste_pdb_file= Pegar tu fichero PDB aquí.
 label.paste_pdb_file_for_sequence = Pegar fichero PDB para la secuencia {0}
-label.could_not_parse_newick_file  = No se pudo analizar el fichero Newick\\\!\\n {0}
+label.could_not_parse_newick_file  = No se pudo analizar el fichero Newick\!\n {0}
 label.successfully_pasted_tcoffee_scores_to_alignment= Pegada exitosamente la puntuación T-Coffee al alineamiento.
 label.failed_add_tcoffee_scores = Fallo al añadir las puntuaciones T-Coffee: 
 label.successfully_pasted_annotation_to_alignment = Anotación pegada exitosamente al alineamiento.
@@ -321,7 +321,7 @@ action.save_vamsas_session = Guardar Sesi
 label.select_vamsas_session_opened_as_new_vamsas_session= Selecciones una sesión vamsas para abrirla como una nueva sesión.
 label.open_saved_vamsas_session = Abrir una sesión VAMSAS guardada
 label.groovy_console = Consola Groovy 
-label.lineart = lineart
+label.lineart = Lineart
 label.dont_ask_me_again = No volver a preguntar
 label.select_eps_character_rendering_style = Seleccionar el carácter EPS como estilo de visualización 
 label.invert_selection = Invertir selección
@@ -336,26 +336,26 @@ label.example = Ejemplo
 label.example_param = Ejemplo: {0}
 label.select_file_format_before_saving = Debe seleccionar un formato de fichero antes de guardar!
 label.file_format_not_specified = Formato de fichero no especificado
-label.alignment_contains_hidden_columns = El alineamiento contiene columnas ocultas.\\nQuieres guardar s\u00F3lo el alineamiento visible?
+label.alignment_contains_hidden_columns = El alineamiento contiene columnas ocultas.\nQuieres guardar s\u00F3lo el alineamiento visible?
 label.couldnt_save_file = No se pudo guardar el fichero: {0}
 label.error_saving_file = Error guardando el fichero
 label.remove_from_default_list = eliminar de la lista de defectuosos?
 label.remove_user_defined_colour = Eliminar el color definido por el usuario
 label.you_must_select_least_two_sequences = Debes seleccionar al menos 2 secuencias.
 label.invalid_selection = Selección inválida
-label.principal_component_analysis_must_take_least_four_input_sequences = El an\u00E1lisis de la componente principal debe tomar\\nal menos 4 secuencias de entrada.
+label.principal_component_analysis_must_take_least_four_input_sequences = El an\u00E1lisis de la componente principal debe tomar\nal menos 4 secuencias de entrada.
 label.sequence_selection_insufficient = Selección de secuencias insuficiente
 label.you_need_more_two_sequences_selected_build_tree = necesitas seleccionar más de dos secuencias para construir un Ã¡rbol!
 label.not_enough_sequences = No suficientes secuencias
-label.selected_region_to_tree_may_only_contain_residues_or_gaps = La regi\u00F3n seleccionada para construir un \u00E1rbol puede\\ncontener s\u00F3lo residuos o espacios.\\nPrueba usando la funci\u00F3n Pad en el men\u00FA de edici\u00F3n,\\n o uno de los m\u00FAltiples servicios web de alineamiento de secuencias.
+label.selected_region_to_tree_may_only_contain_residues_or_gaps = La regi\u00F3n seleccionada para construir un \u00E1rbol puede\ncontener s\u00F3lo residuos o espacios.\nPrueba usando la funci\u00F3n Pad en el men\u00FA de edici\u00F3n,\n o uno de los m\u00FAltiples servicios web de alineamiento de secuencias.
 label.sequences_selection_not_aligned = Las secuencias seleccionadas no están alineadas
-label.sequences_must_be_aligned_before_creating_tree = Las secuencias deben estar alineadas antes de crear el \u00E1rbol.\\nPrueba usando la funci\u00F3n Pad en el men\u00FA de editar,\\n o uno de los m\u00FAltiples servicios web de alineamiento de secuencias.
+label.sequences_must_be_aligned_before_creating_tree = Las secuencias deben estar alineadas antes de crear el \u00E1rbol.\nPrueba usando la funci\u00F3n Pad en el men\u00FA de editar,\n o uno de los m\u00FAltiples servicios web de alineamiento de secuencias.
 label.sequences_not_aligned = Secuencias no alineadas
 label.problem_reading_tree_file =  Problema al leer el fichero del Ã¡rbol
 label.possible_problem_with_tree_file = Posible problema con el fichero del Ã¡rbol
 label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation = Por favor seleccionar al menos tres bases de al menos una secuencia para poder realizar la traducción de cDNA.
 label.translation_failed = Translation Failed
-label.error_when_translating_sequences_submit_bug_report = Desafortunadamente, algo fue mal a la hora de traducir tus secuencias.\\nPor favor, revisa la consola Jalview java \\ny presenta un informe de error que incluya el seguimiento.
+label.error_when_translating_sequences_submit_bug_report = Desafortunadamente, algo fue mal a la hora de traducir tus secuencias.\nPor favor, revisa la consola Jalview java \ny presenta un informe de error que incluya el seguimiento.
 label.implementation_error  = Error de implementación:
 label.automatically_associate_pdb_files_with_sequences_same_name = Quieres asociar automáticamente los {0} ficheros PDB con las secuencias del alineamiento que tengan el mismo nombre?
 label.automatically_associate_pdb_files_by_name = Asociar los ficheros PDB por nombre automáticamente
@@ -364,11 +364,11 @@ label.ignore_unmatched_dropped_files = Ignorar los ficheros sin coincidencias?
 label.enter_view_name = Introducir nombre visible (¿?)
 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.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.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.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.
 label.no_pdb_id_in_file = No hay un Id PDB en el fichero
@@ -394,11 +394,11 @@ label.invalid_url = URL Invalido!
 label.error_loading_file = Error al cargar el fichero
 label.problems_opening_file = Encontrados problemas al abrir el fichero {0}!!
 label.file_open_error = Error al abrir el fichero
-label.no_das_sources_selected_warn = No han sido seleccionadas fuentes DAS.\\nPor favor, seleccione algunas fuentes y\\npruebe de nuevo.
+label.no_das_sources_selected_warn = No han sido seleccionadas fuentes DAS.\nPor favor, seleccione algunas fuentes y\npruebe de nuevo.
 label.no_das_sources_selected_title = No han sido seleccionadas fuentes DAS
-label.colour_scheme_exists_overwrite = El esquema de colores {0} ya existe.\\nContinuar guardando el esquema de colores como {1}?
+label.colour_scheme_exists_overwrite = El esquema de colores {0} ya existe.\nContinuar guardando el esquema de colores como {1}?
 label.duplicate_scheme_name = Duplicar nombre de esquema
-label.jalview_new_questionnaire = Hay un nuevo cuestionario disponible. Querr\u00EDa completarlo ahora ?\\n
+label.jalview_new_questionnaire = Hay un nuevo cuestionario disponible. Querr\u00EDa completarlo ahora ?\n
 label.jalview_user_survey = Encuesta de usuario Jalview 
 label.alignment_properties = Propiedades del alineamiento: {0}
 label.alignment_props = Propiedades del alineamiento
@@ -905,7 +905,6 @@ error.eps_generation_not_implemented = La generaci
 error.png_generation_not_implemented = La generación de PNG no se ha implementado todavía
 error.try_join_vamsas_session_another = Tratando de establecer una sesión VAMSAS cuando ya había otra conectada
 error.invalid_vamsas_session_id = Identificador de sesión VAMSAS no válido
-error.implementation_error_cannot_create_groovyshell = Error de implementación:no se puede crear groovyShell sin Groovy en el classpath
 label.groovy_support_failed = El soporte Groovy de Jalview ha fallado
 label.couldnt_create_groovy_shell = No es posible crear el shell de Groovy. Compruebe el fichero de log para conocer los detalles.
 error.unsupported_version_calcIdparam = Versión no soportada de {0}
@@ -962,7 +961,7 @@ error.implementation_error_need_to_have_httpresponse = Error de implementaci
 error.dbrefsource_implementation_exception = Excepción de implementación DBRefSource
 error.implementation_error_dbinstance_must_implement_interface = Error de Implementación- getDbInstances debe recibir una clase que implemente jalview.ws.seqfetcher.DbSourceProxy (recibió {0})
 error.implementation_error_must_init_dbsources =Error de implementación. Debe inicializar dbSources
-label.view_controller_toggled_marked = {0} {1} columnas {2} conteniendo características del tipo  {3} en {4} secuencia(s)
+label.view_controller_toggled_marked = {0} {1} columnas conteniendo características del tipo {2} en {3} secuencia(s)
 label.toggled = Invertida
 label.marked = Marcada
 label.not = no
@@ -1055,7 +1054,7 @@ error.implementation_error_cannot_find_service_url_in_given_set = Error de imple
 error.implementation_error_cannot_find_service_url_in_given_set_param_store = Error de implementación: la URL del servicio en el conjunto de URL  para este almacén de parámetros del servicio({0})
 exception.jobsubmission_invalid_params_set = Conjunto de parámetros no válido. Comprueba la implementación de Jalview
 exception.notvaliddata_group_contains_less_than_min_seqs = El grupo contiene menos de {0} secuencias.
-exception.outofmemory_loading_pdb_file = Sin menoria al cargar el fichero PDB
+exception.outofmemory_loading_pdb_file = Sin memoria al cargar el fichero PDB
 exception.eps_coudnt_write_output_file = No es posible escribir el fichero de salida: {0}
 exception.eps_method_not_supported = Método actualmente no suportado por la versión {0} de EpsGraphics2D
 exception.eps_unable_to_get_inverse_matrix = Imposible obtener la inversa de la matrix: {0}
@@ -1084,7 +1083,7 @@ status.fetching_pdb = Recuperando PDB {0}
 status.refreshing_news = Refrescando noticias
 status.importing_vamsas_session_from = Importando sesión VAMSAS de {0}
 status.opening_params = Abriendo {0}
-status.waiting_sequence_database_fetchers_init = Esperando la inicialización de los recuperadores de bases de datos de secuencias
+status.waiting_sequence_database_fetchers_init = Esperando inicialización de los recuperadores de bases de datos de secuencias
 status.init_sequence_database_fetchers = Inicializando recuperadores de bases de datos de secuencias
 status.fetching_sequence_queries_from = Recuperando {0} consultas de secuencias de {1}
 status.finshed_querying = Consulta finalizada
@@ -1281,3 +1280,36 @@ info.invalid_msa_input_mininfo=Necesita por lo menos dos secuencias con al menos
 label.chimera_missing=Visualizador de estructura Chimera no encontrado.<br/>Por favor, introduzca la ruta de Chimera,<br/>o descargar e instalar la UCSF Chimera.
 label.save_as_biojs_html=Guardar como HTML BioJs
 exception.pdb_rest_service_no_longer_available=Servicios Rest PDB ya no están disponibles!
+exception.fts_server_unreachable=Jalview no puede conectar con el servidor {0}. \nPor favor asegúrese de que está conectado a Internet y vuelva a intentarlo.
+exception.outofmemory_loading_mmcif_file=Sin memoria al cargar el fichero mmCIF
+label.hide_columns_not_containing=Ocultar las columnas que no contengan
+label.pdb_sequence_fetcher=Recuperador de secuencias PDB
+exception.fts_server_error=Parece que hay un error desde el servidor {0}
+exception.service_not_available=Servicio no disponible. El servidor se está actualizando, vuelva a intentarlo más tarde.
+status.waiting_for_user_to_select_output_file=Esperando que el usuario seleccione el fichero {0}
+action.prev_page=<< 
+status.cancelled_image_export_operation=Operación de exportación {0} cancelada
+label.couldnt_run_groovy_script=No se ha podido ejecutar el script Groovy
+exception.bad_request=Solicitud incorrecta. Hay un problema con su entrada.
+label.run_groovy=Ejecutar script Groovy desde la consola
+action.next_page=>> 
+label.uniprot_sequence_fetcher=Recuperador de secuencias UniProt
+label.prev_page_tooltip=Página anterior
+label.reverse=Invertir
+label.hide_columns_containing=Ocultar las columnas que contengan
+label.nucleotides=Nucleótidos
+label.run_groovy_tip = Ejecutar script Groovy desde la consola sobre este alineamiento
+label.nw_mapping=Alineamiento Needleman y Wunsch
+label.proteins=Proteína 
+label.reverse_complement=Invertir y complementar
+label.next_page_tooltip=Página siguiente
+label.sifts_mapping=Mapeado SIFTs
+label.mapping_method=Método de mapeo de secuencia \u27F7 estructura
+info.error_creating_file=Error al crear fichero {0}
+exception.fts_rest_service_no_longer_available= Servicios Rest {0} ya no están disponibles! 
+status.launching_3d_structure_viewer=Lanzando visualizador de estructura 3D...
+status.obtaining_mapping_with_sifts=Obteniendo mapeo por SIFTS
+status.fetching_3d_structures_for=Buscando la estructura 3D para {0}
+status.fetching_3d_structures_for_selected_entries=Buscando las estructuras 3D para entradas seleccionadas...
+status.fetching_dbrefs_for_sequences_without_valid_refs=Buscando referencias para {0} secuencia(s) sin referencia válida necesaria para mapeado SIFTS
+status.obtaining_mapping_with_nw_alignment=Obteniendo mapeo por alineamiento Needleman y Wunsch
\ No newline at end of file
index e032c7a..d5f0d0b 100755 (executable)
@@ -151,7 +151,7 @@ public class PDBViewer extends JInternalFrame implements Runnable
     {
       EBIFetchClient ebi = new EBIFetchClient();
       String query = "pdb:" + pdbentry.getId();
-      pdbentry.setFile(ebi.fetchDataAsFile(query, "default", "raw", ".xml")
+      pdbentry.setFile(ebi.fetchDataAsFile(query, "default", ".xml")
               .getAbsolutePath());
 
       if (pdbentry.getFile() != null)
index 4201f43..c0c7c46 100644 (file)
@@ -199,8 +199,9 @@ public class ChimeraManager
       return null;
     }
 
-    List<ChimeraModel> newModelList = getModelList();
-    for (ChimeraModel newModel : newModelList)
+    // patch for Jalview - set model name in Chimera
+    // TODO: find a variant that works for sub-models
+    for (ChimeraModel newModel : getModelList())
     {
       if (!modelList.contains(newModel))
       {
@@ -209,15 +210,12 @@ public class ChimeraManager
                 "setattr M name " + modelName + " #"
                         + newModel.getModelNumber(), false);
         modelList.add(newModel);
-
       }
     }
 
     // assign color and residues to open models
     for (ChimeraModel chimeraModel : modelList)
     {
-      // // patch for Jalview - set model name in Chimera
-      // // TODO: find a variant that works for sub-models
       // get model color
       Color modelColor = getModelColor(chimeraModel);
       if (modelColor != null)
@@ -731,7 +729,7 @@ public class ChimeraManager
    */
   public List<String> sendChimeraCommand(String command, boolean reply)
   {
-    // System.out.println("chimeradebug>> " + command);
+   // System.out.println("chimeradebug>> " + command);
     if (!isChimeraLaunched() || command == null
             || "".equals(command.trim()))
     {
index 42a1201..081f446 100644 (file)
@@ -40,6 +40,7 @@ import jalview.schemes.ResidueProperties;
 import jalview.util.Comparison;
 import jalview.util.MapList;
 import jalview.util.MappingUtils;
+import jalview.util.StringUtils;
 
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
@@ -1927,11 +1928,15 @@ public class AlignmentUtils
                     .codonTranslate(codon));
     if (trans != null && !trans.equals(residue))
     {
-      String desc = residue + "->" + trans;
+      String residue3Char = StringUtils
+              .toSentenceCase(ResidueProperties.aa2Triplet.get(residue));
+      String trans3Char = StringUtils
+              .toSentenceCase(ResidueProperties.aa2Triplet.get(trans));
+      String desc = "p." + residue3Char + peptidePos + trans3Char;
       // set score to 0f so 'graduated colour' option is offered! JAL-2060
       SequenceFeature sf = new SequenceFeature(
               SequenceOntologyI.SEQUENCE_VARIANT, desc, peptidePos,
-              peptidePos, 0f, null);
+              peptidePos, 0f, "Jalview");
       StringBuilder attributes = new StringBuilder(32);
       String id = (String) var.variant.getValue(ID);
       if (id != null)
@@ -2109,6 +2114,26 @@ public class AlignmentUtils
   {
     AlignmentI copy = new Alignment(new Alignment(seqs));
 
+    /*
+     * add mappings between sequences to the new alignment
+     */
+    AlignedCodonFrame mappings = new AlignedCodonFrame();
+    copy.addCodonFrame(mappings);
+    for (int i = 0; i < copy.getHeight(); i++)
+    {
+      SequenceI from = seqs[i];
+      SequenceI to = copy.getSequenceAt(i);
+      if (to.getDatasetSequence() != null)
+      {
+        to = to.getDatasetSequence();
+      }
+      int start = from.getStart();
+      int end = from.getEnd();
+      MapList map = new MapList(new int[] { start, end }, new int[] {
+          start, end }, 1, 1);
+      mappings.addMap(to, from, map);
+    }
+
     SequenceIdMatcher matcher = new SequenceIdMatcher(seqs);
     if (xrefs != null)
     {
index d4ae57d..7b3ce25 100755 (executable)
@@ -235,10 +235,7 @@ public class Conservation
               c = '-';
             }
 
-            if (!canonicaliseAa && 'a' <= c && c <= 'z')
-            {
-              c -= (32); // 32 = 'a' - 'A'
-            }
+            c = toUpperCase(c);
           }
           values[c]++;
         }
@@ -326,6 +323,7 @@ public class Conservation
       }
       else
       {
+        c = toUpperCase(c);
         nres++;
 
         if (nres == 1)
@@ -347,6 +345,22 @@ public class Conservation
   }
 
   /**
+   * Returns the upper-cased character if between 'a' and 'z', else the
+   * unchanged value
+   * 
+   * @param c
+   * @return
+   */
+  char toUpperCase(char c)
+  {
+    if ('a' <= c && c <= 'z')
+    {
+      c -= (32); // 32 = 'a' - 'A'
+    }
+    return c;
+  }
+
+  /**
    * Calculates the conservation sequence
    * 
    * @param consflag
index 3563eba..7e77fc1 100644 (file)
@@ -327,8 +327,8 @@ public class CrossRef
           }
           if (l > 0)
           {
-            System.out
-                    .println("Attempting to retrieve cross referenced sequences.");
+            // System.out
+            // .println("Attempting to retrieve cross referenced sequences.");
             DBRefEntry[] t = new DBRefEntry[l];
             l = 0;
             for (int r = 0; r < xrfs.length; r++)
index 70defb0..3fd0581 100755 (executable)
@@ -290,7 +290,7 @@ public class SequenceIdMatcher
     {
       if (s != null)
       {
-        id = new String(s);
+        id = new String(s.toLowerCase());
       }
       else
       {
@@ -314,13 +314,13 @@ public class SequenceIdMatcher
       }
       if (s instanceof SeqIdName)
       {
-        return this.equals(((SeqIdName) s).id);
+        return this.stringequals(((SeqIdName) s).id);
       }
       else
       {
         if (s instanceof String)
         {
-          return this.equals((String) s);
+          return this.stringequals(((String) s).toLowerCase());
         }
       }
 
@@ -344,7 +344,7 @@ public class SequenceIdMatcher
      * @param s
      * @return boolean
      */
-    public boolean equals(String s)
+    private boolean stringequals(String s)
     {
       if (id.length() > s.length())
       {
index 17a1563..26966ba 100644 (file)
@@ -64,7 +64,7 @@ public interface AlignViewControllerI
    * @return true if operation affected state
    */
   boolean markColumnsContainingFeatures(boolean invert,
-          boolean extendCurrent, boolean clearColumns, String featureType);
+          boolean extendCurrent, boolean toggle, String featureType);
 
   /**
    * sort the alignment or current selection by average score over the given set
index 45e77ba..8343f0b 100644 (file)
@@ -235,11 +235,30 @@ public interface AlignViewportI extends ViewStyleI
    * This method returns the visible alignment as text, as seen on the GUI, ie
    * if columns are hidden they will not be returned in the result. Use this for
    * calculating trees, PCA, redundancy etc on views which contain hidden
+   * columns. This method doesn't exclude hidden sequences from the output.
+   *
+   * @param selectedRegionOnly
+   *          - determines if only the selected region or entire alignment is
+   *          exported
+   * @return String[]
+   */
+  String[] getViewAsString(boolean selectedRegionOnly);
+  
+  /**
+   * This method returns the visible alignment as text, as seen on the GUI, ie
+   * if columns are hidden they will not be returned in the result. Use this for
+   * calculating trees, PCA, redundancy etc on views which contain hidden
    * columns.
    * 
+   * @param selectedRegionOnly
+   *          - determines if only the selected region or entire alignment is
+   *          exported
+   * @param isExportHiddenSeqs
+   *          - determines if hidden sequences would be exported or not.
+   * 
    * @return String[]
    */
-  String[] getViewAsString(boolean selectedRegionOnly);
+  String[] getViewAsString(boolean selectedRegionOnly, boolean isExportHiddenSeqs);
 
   void setSelectionGroup(SequenceGroup sg);
 
@@ -376,5 +395,6 @@ public interface AlignViewportI extends ViewStyleI
    */
   void setFollowHighlight(boolean b);
 
+
   public void applyFeaturesStyle(FeatureSettingsModelI featureSettings);
 }
index 9415745..2ce7e4a 100644 (file)
@@ -2,6 +2,7 @@ package jalview.api;
 
 import jalview.datamodel.Mapping;
 
+//JBPComment: this is a datamodel API - so it should be in datamodel (it's a peer of SequenceI)
 
 public interface DBRefEntryI
 {
@@ -72,5 +73,27 @@ public interface DBRefEntryI
    */
   public int getEndRes();
 
+  /**
+   * access a mapping, if present that can be used to map positions from the
+   * associated dataset sequence to the DBRef's sequence frame.
+   * 
+   * @return null or a valid mapping.
+   */
   public Mapping getMap();
+
+  /**
+   * Answers true if this object is either equivalent to, or can be 'improved'
+   * by, the given entry. Specifically, answers true if
+   * <ul>
+   * <li>source and accession are identical</li>
+   * <li>version is identical, or this version is of the format "someSource:0",
+   * in which case the version for the other entry replaces it</li>
+   * <li>mappings are not compared but if this entry has no mapping, replace
+   * with that for the other entry</li>
+   * </ul>
+   * 
+   * @param otherEntry
+   * @return
+   */
+  public boolean updateFrom(DBRefEntryI otherEntry);
 }
index 5b15cad..d9795a6 100644 (file)
@@ -143,12 +143,6 @@ public interface FeatureRenderer
   List<SequenceFeature> findFeaturesAtRes(SequenceI sequence, int res);
 
   /**
-   * 
-   * @return true if the rendering platform supports transparency
-   */
-  boolean isTransparencyAvailable();
-
-  /**
    * get current displayed types, in ordering of rendering (on top last)
    * 
    * @return a (possibly empty) list of feature types
index e2fac14..527ae17 100644 (file)
@@ -29,6 +29,8 @@ import jalview.xml.binding.sifts.Entry.Entity;
 import java.util.HashMap;
 import java.util.HashSet;
 
+// JBPComment: this isn't a top-level Jalview API - should be in its own package api
+
 public interface SiftsClientI
 {
   /**
index 5727e9c..b28ccc7 100755 (executable)
@@ -162,6 +162,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
     return row;
   }
 
+  @Override
   public void actionPerformed(ActionEvent evt)
   {
     AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
@@ -261,6 +262,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
 
   boolean resizePanel = false;
 
+  @Override
   public void mouseMoved(MouseEvent evt)
   {
     resizePanel = evt.getY() < 10 && evt.getX() < 14;
@@ -306,6 +308,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
     dragCancelled = true;
   }
 
+  @Override
   public void mouseDragged(MouseEvent evt)
   {
     if (dragCancelled)
@@ -365,10 +368,12 @@ public class AnnotationLabels extends Panel implements ActionListener,
     }
   }
 
+  @Override
   public void mouseClicked(MouseEvent evt)
   {
   }
 
+  @Override
   public void mouseReleased(MouseEvent evt)
   {
     if (!resizePanel && !dragCancelled)
@@ -400,6 +405,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
     ap.annotationPanel.repaint();
   }
 
+  @Override
   public void mouseEntered(MouseEvent evt)
   {
     if (evt.getY() < 10 && evt.getX() < 14)
@@ -409,6 +415,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
     }
   }
 
+  @Override
   public void mouseExited(MouseEvent evt)
   {
     dragCancelled = false;
@@ -427,6 +434,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
     repaint();
   }
 
+  @Override
   public void mousePressed(MouseEvent evt)
   {
     oldY = evt.getY();
@@ -522,6 +530,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
             final AlignmentAnnotation aaa = aa[selectedRow];
             cbmi.addItemListener(new ItemListener()
             {
+              @Override
               public void itemStateChanged(ItemEvent e)
               {
                 if (aaa.groupRef != null)
@@ -545,6 +554,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
                       aa[selectedRow].groupRef.isShowConsensusHistogram());
               chist.addItemListener(new ItemListener()
               {
+                @Override
                 public void itemStateChanged(ItemEvent e)
                 {
                   // TODO: pass on reference
@@ -564,6 +574,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
                       aa[selectedRow].groupRef.isShowSequenceLogo());
               cprofl.addItemListener(new ItemListener()
               {
+                @Override
                 public void itemStateChanged(ItemEvent e)
                 {
                   // TODO: pass on reference
@@ -585,6 +596,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
                       aa[selectedRow].groupRef.isNormaliseSequenceLogo());
               cprofn.addItemListener(new ItemListener()
               {
+                @Override
                 public void itemStateChanged(ItemEvent e)
                 {
                   // TODO: pass on reference
@@ -608,6 +620,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
                       av.isShowConsensusHistogram());
               chist.addItemListener(new ItemListener()
               {
+                @Override
                 public void itemStateChanged(ItemEvent e)
                 {
                   // TODO: pass on reference
@@ -631,6 +644,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
                       av.isShowSequenceLogo());
               cprof.addItemListener(new ItemListener()
               {
+                @Override
                 public void itemStateChanged(ItemEvent e)
                 {
                   // TODO: pass on reference
@@ -655,6 +669,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
                       av.isNormaliseSequenceLogo());
               cprofn.addItemListener(new ItemListener()
               {
+                @Override
                 public void itemStateChanged(ItemEvent e)
                 {
                   // TODO: pass on reference
@@ -697,11 +712,47 @@ public class AnnotationLabels extends Panel implements ActionListener,
             // todo: make the ap scroll to the selection - not necessary, first
             // click highlights/scrolls, second selects
             ap.seqPanel.ap.idPanel.highlightSearchResults(null);
-            ap.av.setSelectionGroup(// new SequenceGroup(
-            aa[selectedRow].groupRef); // );
-            ap.av.sendSelection();
+            // process modifiers
+            SequenceGroup sg = ap.av.getSelectionGroup();
+            if (sg == null
+                    || sg == aa[selectedRow].groupRef
+                    || !(jalview.util.Platform.isControlDown(evt) || evt
+                            .isShiftDown()))
+            {
+              if (jalview.util.Platform.isControlDown(evt)
+                      || evt.isShiftDown())
+              {
+                // clone a new selection group from the associated group
+                ap.av.setSelectionGroup(new SequenceGroup(
+                        aa[selectedRow].groupRef));
+              }
+              else
+              {
+                // set selection to the associated group so it can be edited
+                ap.av.setSelectionGroup(aa[selectedRow].groupRef);
+              }
+            }
+            else
+            {
+              // modify current selection with associated group
+              int remainToAdd = aa[selectedRow].groupRef.getSize();
+              for (SequenceI sgs : aa[selectedRow].groupRef.getSequences())
+              {
+                if (jalview.util.Platform.isControlDown(evt))
+                {
+                  sg.addOrRemove(sgs, --remainToAdd == 0);
+                }
+                else
+                {
+                  // notionally, we should also add intermediate sequences from
+                  // last added sequence ?
+                  sg.addSequence(sgs, --remainToAdd == 0);
+                }
+              }
+            }
             ap.paintAlignment(false);
             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
+            ap.av.sendSelection();
           }
           else
           {
@@ -728,7 +779,8 @@ public class AnnotationLabels extends Panel implements ActionListener,
               // we make a copy rather than edit the current selection if no
               // modifiers pressed
               // see Enhancement JAL-1557
-              if (!(evt.isControlDown() || evt.isShiftDown()))
+              if (!(jalview.util.Platform.isControlDown(evt) || evt
+                      .isShiftDown()))
               {
                 sg = new SequenceGroup(sg);
                 sg.clear();
@@ -736,7 +788,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
               }
               else
               {
-                if (evt.isControlDown())
+                if (jalview.util.Platform.isControlDown(evt))
                 {
                   sg.addOrRemove(aa[selectedRow].sequenceRef, true);
                 }
@@ -794,11 +846,13 @@ public class AnnotationLabels extends Panel implements ActionListener,
     }
   }
 
+  @Override
   public void update(Graphics g)
   {
     paint(g);
   }
 
+  @Override
   public void paint(Graphics g)
   {
     int w = getSize().width;
index 7ae333e..d774131 100644 (file)
@@ -63,8 +63,6 @@ public class FeatureRenderer extends
   {
     super(av);
 
-    setTransparencyAvailable(!System.getProperty("java.version")
-            .startsWith("1.1"));
   }
 
   static String lastFeatureAdded;
@@ -353,12 +351,6 @@ public class FeatureRenderer extends
     start.setText(features[0].getBegin() + "");
     end.setText(features[0].getEnd() + "");
     description.setText(features[0].getDescription());
-    Color col = getColour(name.getText());
-    if (col == null)
-    {
-      col = new jalview.schemes.UserColourScheme()
-              .createColourFromName(name.getText());
-    }
     Object fcol = getFeatureStyle(name.getText());
     // simply display the feature color in a box
     colourPanel.updateColor(fcol);
index 40a2ce5..7ae318c 100755 (executable)
@@ -95,14 +95,7 @@ public class FeatureSettings extends Panel implements ItemListener,
     transparency = new Scrollbar(Scrollbar.HORIZONTAL,
             100 - (int) (fr.getTransparency() * 100), 1, 1, 100);
 
-    if (fr.isTransparencyAvailable())
-    {
-      transparency.addAdjustmentListener(this);
-    }
-    else
-    {
-      transparency.setEnabled(false);
-    }
+    transparency.addAdjustmentListener(this);
 
     java.net.URL url = getClass().getResource("/images/link.gif");
     if (url != null)
@@ -134,17 +127,8 @@ public class FeatureSettings extends Panel implements ItemListener,
 
     Panel tPanel = new Panel(new BorderLayout());
 
-    if (fr.isTransparencyAvailable())
-    {
-      tPanel.add(transparency, BorderLayout.CENTER);
-      tPanel.add(new Label("Transparency"), BorderLayout.EAST);
-    }
-    else
-    {
-      tPanel.add(
-              new Label("Transparency not available in this web browser"),
-              BorderLayout.CENTER);
-    }
+    tPanel.add(transparency, BorderLayout.CENTER);
+    tPanel.add(new Label("Transparency"), BorderLayout.EAST);
 
     lowerPanel.add(tPanel, BorderLayout.SOUTH);
 
@@ -238,6 +222,7 @@ public class FeatureSettings extends Panel implements ItemListener,
 
     });
     men.add(dens);
+
     if (minmax != null)
     {
       final float[][] typeMinMax = minmax.get(type);
@@ -283,6 +268,57 @@ public class FeatureSettings extends Panel implements ItemListener,
         });
       }
     }
+
+    MenuItem selectContaining = new MenuItem(
+            MessageManager.getString("label.select_columns_containing"));
+    selectContaining.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        me.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
+                false, type);
+      }
+    });
+    men.add(selectContaining);
+
+    MenuItem selectNotContaining = new MenuItem(
+            MessageManager.getString("label.select_columns_not_containing"));
+    selectNotContaining.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        me.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
+                false, type);
+      }
+    });
+    men.add(selectNotContaining);
+
+    MenuItem hideContaining = new MenuItem(
+            MessageManager.getString("label.hide_columns_containing"));
+    hideContaining.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        hideFeatureColumns(type, true);
+      }
+    });
+    men.add(hideContaining);
+
+    MenuItem hideNotContaining = new MenuItem(
+            MessageManager.getString("label.hide_columns_not_containing"));
+    hideNotContaining.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        hideFeatureColumns(type, false);
+      }
+    });
+    men.add(hideNotContaining);
+
     this.featurePanel.add(men);
     men.show(this.featurePanel, x, y);
   }
@@ -794,4 +830,24 @@ public class FeatureSettings extends Panel implements ItemListener,
   {
   }
 
+  /**
+   * Hide columns containing (or not containing) a given feature type
+   * 
+   * @param type
+   * @param columnsContaining
+   */
+  void hideFeatureColumns(final String type,
+          boolean columnsContaining)
+  {
+    if (ap.alignFrame.avc.markColumnsContainingFeatures(
+            columnsContaining, false, false, type))
+    {
+      if (ap.alignFrame.avc.markColumnsContainingFeatures(
+              !columnsContaining, false, false, type))
+      {
+        ap.alignFrame.viewport.hideSelectedColumns();
+      }
+    }
+  }
+
 }
index 16bba0b..d72e91f 100755 (executable)
@@ -138,11 +138,13 @@ public class IdCanvas extends Panel
     repaint();
   }
 
+  @Override
   public void update(Graphics g)
   {
     paint(g);
   }
 
+  @Override
   public void paint(Graphics g)
   {
     if (getSize().height < 0 || getSize().width < 0)
@@ -378,7 +380,7 @@ public class IdCanvas extends Panel
     Font bold = new Font(av.getFont().getName(), Font.BOLD, av.getFont()
             .getSize());
 
-    if (av.isHiddenRepSequence(seq))
+    if (av.isReferenceSeq(seq) || av.isHiddenRepSequence(seq))
     {
       gg.setFont(bold);
       return true;
index 8f24f11..36c2199 100755 (executable)
@@ -100,6 +100,7 @@ public class IdPanel extends Panel implements MouseListener,
 
   Tooltip tooltip;
 
+  @Override
   public void mouseMoved(MouseEvent e)
   {
     int seq = alignPanel.seqPanel.findSeq(e);
@@ -188,6 +189,7 @@ public class IdPanel extends Panel implements MouseListener,
     tooltiptext = null;
   }
 
+  @Override
   public void mouseDragged(MouseEvent e)
   {
     mouseDragging = true;
@@ -207,6 +209,7 @@ public class IdPanel extends Panel implements MouseListener,
     alignPanel.paintAlignment(false);
   }
 
+  @Override
   public void mouseClicked(MouseEvent e)
   {
     if (e.getClickCount() < 2)
@@ -270,6 +273,7 @@ public class IdPanel extends Panel implements MouseListener,
     }
   }
 
+  @Override
   public void mouseEntered(MouseEvent e)
   {
     if (scrollThread != null)
@@ -278,6 +282,7 @@ public class IdPanel extends Panel implements MouseListener,
     }
   }
 
+  @Override
   public void mouseExited(MouseEvent e)
   {
     if (av.getWrapAlignment())
@@ -297,6 +302,7 @@ public class IdPanel extends Panel implements MouseListener,
     }
   }
 
+  @Override
   public void mousePressed(MouseEvent e)
   {
     if (e.getClickCount() > 1)
@@ -345,7 +351,8 @@ public class IdPanel extends Panel implements MouseListener,
     }
 
     if ((av.getSelectionGroup() == null)
-            || ((!e.isControlDown() && !e.isShiftDown()) && av
+            || ((!jalview.util.Platform.isControlDown(e) && !e
+                    .isShiftDown()) && av
                     .getSelectionGroup() != null))
     {
       av.setSelectionGroup(new SequenceGroup());
@@ -401,6 +408,7 @@ public class IdPanel extends Panel implements MouseListener,
 
   }
 
+  @Override
   public void mouseReleased(MouseEvent e)
   {
     if (scrollThread != null)
@@ -455,6 +463,7 @@ public class IdPanel extends Panel implements MouseListener,
       running = false;
     }
 
+    @Override
     public void run()
     {
       running = true;
index 479b746..31bf6a4 100644 (file)
@@ -1813,9 +1813,12 @@ public class SeqPanel extends Panel implements MouseMotionListener,
 
     // do we want to thread this ? (contention with seqsel and colsel locks, I
     // suspect)
-    // rules are: colsel is copied if there is a real intersection between
-    // sequence selection
-    boolean repaint = false, copycolsel = true;
+    /*
+     * only copy colsel if there is a real intersection between
+     * sequence selection and this panel's alignment
+     */
+    boolean repaint = false;
+    boolean copycolsel = false;
     if (av.getSelectionGroup() == null || !av.isSelectionGroupChanged(true))
     {
       SequenceGroup sgroup = null;
@@ -1832,11 +1835,9 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         }
         sgroup = seqsel.intersect(av.getAlignment(),
                 (av.hasHiddenRows()) ? av.getHiddenRepSequences() : null);
-        if ((sgroup == null || sgroup.getSize() == 0)
-                && (colsel == null || colsel.isEmpty()))
+        if ((sgroup != null && sgroup.getSize() > 0))
         {
-          // don't copy columns if the region didn't intersect.
-          copycolsel = false;
+          copycolsel = true;
         }
       }
       if (sgroup != null && sgroup.getSize() > 0)
@@ -1964,7 +1965,6 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
             av);
     av.setColumnSelection(cs);
-    av.isColSelChanged(true);
 
     ap.scalePanelHolder.repaint();
     ap.repaint();
diff --git a/src/jalview/bin/ArgsParser.java b/src/jalview/bin/ArgsParser.java
new file mode 100644 (file)
index 0000000..9c8d0df
--- /dev/null
@@ -0,0 +1,97 @@
+package jalview.bin;
+
+import java.net.URLDecoder;
+import java.util.Vector;
+
+/**
+ * Notes: this argParser does not distinguish between parameter switches,
+ * parameter values and argument text. If an argument happens to be identical to
+ * a parameter, it will be taken as such (even though it didn't have a '-'
+ * prefixing it).
+ * 
+ * @author Andrew Waterhouse and JBP documented.
+ * 
+ */
+public class ArgsParser
+{
+  Vector<String> vargs = null;
+
+  public ArgsParser(String[] args)
+  {
+    vargs = new Vector<String>();
+    for (int i = 0; i < args.length; i++)
+    {
+      String arg = args[i].trim();
+      if (arg.charAt(0) == '-')
+      {
+        arg = arg.substring(1);
+      }
+      vargs.addElement(arg);
+    }
+  }
+
+  /**
+   * check for and remove first occurence of arg+parameter in arglist.
+   * 
+   * @param arg
+   * @return return the argument following the given arg if arg was in list.
+   */
+  public String getValue(String arg)
+  {
+    return getValue(arg, false);
+  }
+
+  public String getValue(String arg, boolean utf8decode)
+  {
+    int index = vargs.indexOf(arg);
+    String dc = null, ret = null;
+    if (index != -1)
+    {
+      ret = vargs.elementAt(index + 1).toString();
+      vargs.removeElementAt(index);
+      vargs.removeElementAt(index);
+      if (utf8decode && ret != null)
+      {
+        try
+        {
+          dc = URLDecoder.decode(ret, "UTF-8");
+          ret = dc;
+        } catch (Exception e)
+        {
+          // TODO: log failure to decode
+        }
+      }
+    }
+    return ret;
+  }
+
+  /**
+   * check for and remove first occurence of arg in arglist.
+   * 
+   * @param arg
+   * @return true if arg was present in argslist.
+   */
+  public boolean contains(String arg)
+  {
+    if (vargs.contains(arg))
+    {
+      vargs.removeElement(arg);
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+  public String nextValue()
+  {
+    return vargs.remove(0);
+  }
+
+  public int getSize()
+  {
+    return vargs.size();
+  }
+
+}
\ No newline at end of file
index 7911cd5..38aa55f 100755 (executable)
@@ -426,7 +426,7 @@ public class Cache
     System.out
             .println("Jalview Version: " + codeVersion + codeInstallation);
 
-    Pdb.setCurrentDefaultFomart(jalview.bin.Cache.getDefault(
+    Pdb.setCurrentDefaultFormat(jalview.bin.Cache.getDefault(
             "DEFAULT_STRUCTURE_FORMAT", DEFAULT_STRUCTURE_FORMAT));
     // jnlpVersion will be null if we're using InstallAnywhere
     // Dont do this check if running in headless mode
index 8fe3bca..76ae3ff 100755 (executable)
  */
 package jalview.bin;
 
+import groovy.lang.Binding;
+import groovy.util.GroovyScriptEngine;
+
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
+import jalview.gui.PromptUserConfig;
+import jalview.io.AppletFormatAdapter;
 import jalview.io.BioJsHTMLOutput;
+import jalview.io.FileLoader;
+import jalview.io.FormatAdapter;
 import jalview.io.HtmlSvgOutput;
+import jalview.io.IdentifyFile;
+import jalview.io.NewickFile;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemeProperty;
+import jalview.schemes.UserColourScheme;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.ws.jws2.Jws2Discoverer;
 
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
-import java.lang.reflect.Constructor;
 import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URL;
-import java.net.URLDecoder;
 import java.security.AllPermission;
 import java.security.CodeSource;
 import java.security.PermissionCollection;
@@ -51,7 +60,6 @@ import java.util.Map;
 import java.util.Vector;
 
 import javax.swing.UIManager;
-import javax.swing.UnsupportedLookAndFeelException;
 
 /**
  * Main class for Jalview Application <br>
@@ -63,11 +71,21 @@ import javax.swing.UnsupportedLookAndFeelException;
  */
 public class Jalview
 {
+  /*
+   * singleton instance of this class
+   */
+  private static Jalview instance;
+
+  private Desktop desktop;
+
+  public static AlignFrame currentAlignFrame;
+
   static
   {
     // grab all the rights we can the JVM
     Policy.setPolicy(new Policy()
     {
+      @Override
       public PermissionCollection getPermissions(CodeSource codesource)
       {
         Permissions perms = new Permissions();
@@ -75,6 +93,7 @@ public class Jalview
         return (perms);
       }
 
+      @Override
       public void refresh()
       {
       }
@@ -82,6 +101,71 @@ public class Jalview
   }
 
   /**
+   * keep track of feature fetching tasks.
+   * 
+   * @author JimP
+   * 
+   */
+  class FeatureFetcher
+  {
+    /*
+     * TODO: generalise to track all jalview events to orchestrate batch
+     * processing events.
+     */
+
+    private int queued = 0;
+
+    private int running = 0;
+
+    public FeatureFetcher()
+    {
+
+    }
+
+    public void addFetcher(final AlignFrame af,
+            final Vector<String> dasSources)
+    {
+      final long id = System.currentTimeMillis();
+      queued++;
+      final FeatureFetcher us = this;
+      new Thread(new Runnable()
+      {
+
+        @Override
+        public void run()
+        {
+          synchronized (us)
+          {
+            queued--;
+            running++;
+          }
+
+          af.setProgressBar(MessageManager
+                  .getString("status.das_features_being_retrived"), id);
+          af.featureSettings_actionPerformed(null);
+          af.featureSettings.fetchDasFeatures(dasSources, true);
+          af.setProgressBar(null, id);
+          synchronized (us)
+          {
+            running--;
+          }
+        }
+      }).start();
+    }
+
+    public synchronized boolean allFinished()
+    {
+      return queued == 0 && running == 0;
+    }
+
+  }
+
+  public static Jalview getInstance()
+  {
+    return instance;
+  }
+
+  /**
    * main class for Jalview application
    * 
    * @param args
@@ -89,6 +173,16 @@ public class Jalview
    */
   public static void main(String[] args)
   {
+    instance = new Jalview();
+    instance.doMain(args);
+  }
+
+  /**
+   * @param args
+   */
+  void doMain(String[] args)
+  {
+    System.setSecurityManager(null);
     System.out.println("Java version: "
             + System.getProperty("java.version"));
     System.out.println(System.getProperty("os.arch") + " "
@@ -161,7 +255,7 @@ public class Jalview
     try
     {
       Cache.initLogger();
-    } catch (java.lang.NoClassDefFoundError error)
+    } catch (NoClassDefFoundError error)
     {
       error.printStackTrace();
       System.out
@@ -170,7 +264,7 @@ public class Jalview
       System.exit(0);
     }
 
-    Desktop desktop = null;
+    desktop = null;
 
     try
     {
@@ -178,7 +272,7 @@ public class Jalview
     } catch (Exception ex)
     {
     }
-    if (new Platform().isAMac())
+    if (Platform.isAMac())
     {
       System.setProperty("com.apple.mrj.application.apple.menu.about.name",
               "Jalview");
@@ -187,10 +281,10 @@ public class Jalview
       {
         UIManager.setLookAndFeel(ch.randelshofer.quaqua.QuaquaManager
                 .getLookAndFeel());
-      } catch (UnsupportedLookAndFeelException e)
+      } catch (Throwable e)
       {
-        // TODO Auto-generated catch block
-        e.printStackTrace();
+        System.err.println("Failed to set QuaQua look and feel: "
+                + e.toString());
       }
     }
 
@@ -251,8 +345,9 @@ public class Jalview
     }
 
     String file = null, protocol = null, format = null, data = null;
-    jalview.io.FileLoader fileLoader = new jalview.io.FileLoader(!headless);
-    Vector getFeatures = null; // vector of das source nicknames to fetch
+    FileLoader fileLoader = new FileLoader(!headless);
+    Vector<String> getFeatures = null; // vector of das source nicknames to
+                                       // fetch
     // features from
     // loading is done.
     String groovyscript = null; // script to execute after all loading is
@@ -266,8 +361,8 @@ public class Jalview
       System.out.println("No files to open!");
       System.exit(1);
     }
-    String vamsasImport = aparser.getValue("vdoc"), vamsasSession = aparser
-            .getValue("vsess");
+    String vamsasImport = aparser.getValue("vdoc");
+    String vamsasSession = aparser.getValue("vsess");
     if (vamsasImport != null || vamsasSession != null)
     {
       if (desktop == null || headless)
@@ -282,13 +377,13 @@ public class Jalview
       {
         try
         {
-          String viprotocol = jalview.io.AppletFormatAdapter
+          String viprotocol = AppletFormatAdapter
                   .checkProtocol(vamsasImport);
           if (viprotocol == jalview.io.FormatAdapter.FILE)
           {
             inSession = desktop.vamsasImport(new File(vamsasImport));
           }
-          else if (viprotocol == jalview.io.FormatAdapter.URL)
+          else if (viprotocol == FormatAdapter.URL)
           {
             inSession = desktop.vamsasImport(new URL(vamsasImport));
           }
@@ -365,7 +460,7 @@ public class Jalview
 
       if (!file.startsWith("http://"))
       {
-        if (!(new java.io.File(file)).exists())
+        if (!(new File(file)).exists())
         {
           System.out.println("Can't find " + file);
           if (headless)
@@ -375,9 +470,9 @@ public class Jalview
         }
       }
 
-      protocol = jalview.io.AppletFormatAdapter.checkProtocol(file);
+      protocol = AppletFormatAdapter.checkProtocol(file);
 
-      format = new jalview.io.IdentifyFile().identify(file, protocol);
+      format = new IdentifyFile().identify(file, protocol);
 
       AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
               format);
@@ -387,19 +482,18 @@ public class Jalview
       }
       else
       {
-        Desktop.setCurrentAlignFrame(af);
+        setCurrentAlignFrame(af);
         data = aparser.getValue("colour", true);
         if (data != null)
         {
           data.replaceAll("%20", " ");
 
-          jalview.schemes.ColourSchemeI cs = jalview.schemes.ColourSchemeProperty
-                  .getColour(af.getViewport().getAlignment(), data);
+          ColourSchemeI cs = ColourSchemeProperty.getColour(af
+                  .getViewport().getAlignment(), data);
 
           if (cs == null)
           {
-            jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
-                    "white");
+            UserColourScheme ucs = new UserColourScheme("white");
             ucs.parseAppletParameter(data);
             cs = ucs;
           }
@@ -416,7 +510,7 @@ public class Jalview
         if (data != null)
         {
           af.parseFeaturesFile(data,
-                  jalview.io.AppletFormatAdapter.checkProtocol(data));
+                  AppletFormatAdapter.checkProtocol(data));
           // System.out.println("Added " + data);
           System.out.println("CMD groups[-" + data
                   + "]  executed successfully!");
@@ -425,7 +519,7 @@ public class Jalview
         if (data != null)
         {
           af.parseFeaturesFile(data,
-                  jalview.io.AppletFormatAdapter.checkProtocol(data));
+                  AppletFormatAdapter.checkProtocol(data));
           // System.out.println("Added " + data);
           System.out.println("CMD [-features " + data
                   + "]  executed successfully!");
@@ -473,8 +567,8 @@ public class Jalview
           {
             System.out.println("CMD [-tree " + data
                     + "] executed successfully!");
-            fin = new jalview.io.NewickFile(data,
-                    jalview.io.AppletFormatAdapter.checkProtocol(data));
+            fin = new NewickFile(data,
+                    AppletFormatAdapter.checkProtocol(data));
             if (fin != null)
             {
               af.getViewport().setCurrentTree(
@@ -514,20 +608,10 @@ public class Jalview
         {
           // Execute the groovy script after we've done all the rendering stuff
           // and before any images or figures are generated.
-          if (jalview.bin.Cache.groovyJarsPresent())
-          {
-            System.out.println("Executing script " + groovyscript);
-            executeGroovyScript(groovyscript, new Object[] { desktop, af });
-
-            System.out.println("CMD groovy[" + groovyscript
-                    + "] executed successfully!");
-          }
-          else
-          {
-            System.err
-                    .println("Sorry. Groovy Support is not available, so ignoring the provided groovy script "
-                            + groovyscript);
-          }
+          System.out.println("Executing script " + groovyscript);
+          executeGroovyScript(groovyscript, af);
+          System.out.println("CMD groovy[" + groovyscript
+                  + "] executed successfully!");
           groovyscript = null;
         }
         String imageName = "unnamed.png";
@@ -538,14 +622,14 @@ public class Jalview
 
           if (format.equalsIgnoreCase("png"))
           {
-            af.createPNG(new java.io.File(file));
-            imageName = (new java.io.File(file)).getName();
+            af.createPNG(new File(file));
+            imageName = (new File(file)).getName();
             System.out.println("Creating PNG image: " + file);
             continue;
           }
           else if (format.equalsIgnoreCase("svg"))
           {
-            File imageFile = new java.io.File(file);
+            File imageFile = new File(file);
             imageName = imageFile.getName();
             af.createSVG(imageFile);
             System.out.println("Creating SVG image: " + file);
@@ -553,21 +637,21 @@ public class Jalview
           }
           else if (format.equalsIgnoreCase("html"))
           {
-            File imageFile = new java.io.File(file);
+            File imageFile = new File(file);
             imageName = imageFile.getName();
-            new HtmlSvgOutput(new java.io.File(file), af.alignPanel);
+            new HtmlSvgOutput(new File(file), af.alignPanel);
             System.out.println("Creating HTML image: " + file);
             continue;
           }
           else if (format.equalsIgnoreCase("imgMap"))
           {
-            af.createImageMap(new java.io.File(file), imageName);
+            af.createImageMap(new File(file), imageName);
             System.out.println("Creating image map: " + file);
             continue;
           }
           else if (format.equalsIgnoreCase("eps"))
           {
-            File outputFile = new java.io.File(file);
+            File outputFile = new File(file);
             System.out.println("Creating EPS file: "
                     + outputFile.getAbsolutePath());
             af.createEPS(outputFile);
@@ -627,7 +711,7 @@ public class Jalview
       }
       else
       {
-        format = new jalview.io.IdentifyFile().identify(file, protocol);
+        format = new IdentifyFile().identify(file, protocol);
       }
 
       startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
@@ -649,11 +733,10 @@ public class Jalview
     // Once all other stuff is done, execute any groovy scripts (in order)
     if (groovyscript != null)
     {
-      if (jalview.bin.Cache.groovyJarsPresent())
+      if (Cache.groovyJarsPresent())
       {
         System.out.println("Executing script " + groovyscript);
-        executeGroovyScript(groovyscript, new Object[] { desktop,
-            startUpAlframe });
+        executeGroovyScript(groovyscript, startUpAlframe);
       }
       else
       {
@@ -720,8 +803,8 @@ public class Jalview
     /**
      * start a User Config prompt asking if we can log usage statistics.
      */
-    jalview.gui.PromptUserConfig prompter = new jalview.gui.PromptUserConfig(
-            desktop.desktop,
+    PromptUserConfig prompter = new PromptUserConfig(
+            Desktop.desktop,
             "USAGESTATS",
             "Jalview Usage Statistics",
             "Do you want to help make Jalview better by enabling "
@@ -729,6 +812,7 @@ public class Jalview
                     + "\n\n(you can enable or disable usage tracking in the preferences)",
             new Runnable()
             {
+              @Override
               public void run()
               {
                 Cache.log
@@ -738,6 +822,7 @@ public class Jalview
               }
             }, new Runnable()
             {
+              @Override
               public void run()
               {
                 Cache.log.debug("Not enabling Google Tracking.");
@@ -755,14 +840,8 @@ public class Jalview
    *          the Jalview Desktop object passed in to the groovy binding as the
    *          'Jalview' object.
    */
-  private static void executeGroovyScript(String groovyscript,
-          Object[] jalviewContext)
+  private void executeGroovyScript(String groovyscript, AlignFrame af)
   {
-    if (jalviewContext == null)
-    {
-      System.err
-              .println("Sorry. Groovy support is currently only available when running with the Jalview GUI enabled.");
-    }
     /**
      * for scripts contained in files
      */
@@ -779,8 +858,8 @@ public class Jalview
         tfile = File.createTempFile("jalview", "groovy");
         PrintWriter outfile = new PrintWriter(new OutputStreamWriter(
                 new FileOutputStream(tfile)));
-        BufferedReader br = new BufferedReader(
-                new java.io.InputStreamReader(System.in));
+        BufferedReader br = new BufferedReader(new InputStreamReader(
+                System.in));
         String line = null;
         while ((line = br.readLine()) != null)
         {
@@ -844,75 +923,23 @@ public class Jalview
         }
       }
     }
-    boolean success = false;
     try
     {
-      /*
-       * The following code performs the GroovyScriptEngine invocation using
-       * reflection, and is equivalent to this fragment from the embedding
-       * groovy documentation on the groovy site: <code> import
-       * groovy.lang.Binding; import groovy.util.GroovyScriptEngine;
-       * 
-       * String[] roots = new String[] { "/my/groovy/script/path" };
-       * GroovyScriptEngine gse = new GroovyScriptEngine(roots); Binding binding
-       * = new Binding(); binding.setVariable("input", "world");
-       * gse.run("hello.groovy", binding); </code>
-       */
-      Class<?>[] bspec;
-      Object[] binding;
-      int blen = ((jalviewContext[0] == null) ? 0 : 1)
-              + ((jalviewContext[1] == null) ? 0 : 1);
-      String cnames[] = new String[] { "Jalview", "currentAlFrame" };
-      bspec = new Class[blen * 2];
-      binding = new Object[blen * 2];
-      blen = 0;
-      ClassLoader cl = null;
       Map<String, Object> vbinding = new HashMap<String, Object>();
-      for (int jc = 0; jc < jalviewContext.length; jc++)
+      vbinding.put("Jalview", this);
+      if (af != null)
       {
-        if (jalviewContext[jc] != null)
-        {
-          if (cl == null)
-          {
-            cl = jalviewContext[jc].getClass().getClassLoader();
-          }
-          bspec[blen * 2] = String.class;
-          bspec[blen * 2 + 1] = Object.class;
-          binding[blen * 2] = cnames[jc];
-          binding[blen * 2 + 1] = jalviewContext[jc];
-          vbinding.put(cnames[jc], jalviewContext[jc]);
-          blen++;
-        }
+        vbinding.put("currentAlFrame", af);
       }
-      Class<?> gbindingc = cl.loadClass("groovy.lang.Binding");
-      Constructor<?> gbcons;
-      Object gbinding;
-      try
-      {
-        gbcons = gbindingc.getConstructor(Map.class);
-        gbinding = gbcons.newInstance(vbinding);
-      } catch (NoSuchMethodException x)
+      Binding gbinding = new Binding(vbinding);
+      GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
+      gse.run(sfile.toString(), gbinding);
+      if ("STDIN".equals(groovyscript))
       {
-        // old style binding config - using series of string/object values to
-        // setVariable.
-        gbcons = gbindingc.getConstructor();
-        gbinding = gbcons.newInstance();
-        java.lang.reflect.Method setvar = gbindingc.getMethod(
-                "setVariable", bspec);
-        setvar.invoke(gbinding, binding);
+        // delete temp file that we made -
+        // only if it was successfully executed
+        tfile.delete();
       }
-
-      Class<?> gsec = cl.loadClass("groovy.util.GroovyScriptEngine");
-      Constructor<?> gseccons = gsec
-              .getConstructor(new Class[] { URL[].class }); // String[].class
-                                                            // });
-      Object gse = gseccons
-              .newInstance(new Object[] { new URL[] { sfile } }); // .toString()
-                                                                  // } });
-      java.lang.reflect.Method run = gsec.getMethod("run", new Class[] {
-          String.class, gbindingc });
-      run.invoke(gse, new Object[] { sfile.toString(), gbinding });
-      success = true;
     } catch (Exception e)
     {
       System.err.println("Exception Whilst trying to execute file " + sfile
@@ -920,12 +947,6 @@ public class Jalview
       e.printStackTrace(System.err);
 
     }
-    if (success && groovyscript.equals("STDIN"))
-    {
-      // delete temp file that we made - but only if it was successfully
-      // executed
-      tfile.delete();
-    }
   }
 
   /**
@@ -933,16 +954,15 @@ public class Jalview
    * 
    * @return vector of DAS source nicknames to retrieve from
    */
-  private static Vector checkDasArguments(ArgsParser aparser)
+  private static Vector<String> checkDasArguments(ArgsParser aparser)
   {
-    Vector source = null;
+    Vector<String> source = null;
     String data;
     String locsources = Cache.getProperty(Cache.DAS_LOCAL_SOURCE);
     while ((data = aparser.getValue("dasserver", true)) != null)
     {
       String nickname = null;
       String url = null;
-      boolean seq = false, feat = true;
       int pos = data.indexOf('=');
       // determine capabilities
       if (pos > 0)
@@ -972,7 +992,7 @@ public class Jalview
                         + nickname + "|" + url);
         if (source == null)
         {
-          source = new Vector();
+          source = new Vector<String>();
         }
         source.addElement(nickname);
       }
@@ -990,7 +1010,7 @@ public class Jalview
       System.out.println("adding source '" + data + "'");
       if (source == null)
       {
-        source = new Vector();
+        source = new Vector<String>();
       }
       source.addElement(data);
     }
@@ -1002,7 +1022,8 @@ public class Jalview
    * 
    * @param dasSources
    */
-  private static FeatureFetcher startFeatureFetching(final Vector dasSources)
+  private FeatureFetcher startFeatureFetching(
+          final Vector<String> dasSources)
   {
     FeatureFetcher ff = new FeatureFetcher();
     AlignFrame afs[] = Desktop.getAlignFrames();
@@ -1026,173 +1047,37 @@ public class Jalview
     }
     return false;
   }
-}
-
-/**
- * Notes: this argParser does not distinguish between parameter switches,
- * parameter values and argument text. If an argument happens to be identical to
- * a parameter, it will be taken as such (even though it didn't have a '-'
- * prefixing it).
- * 
- * @author Andrew Waterhouse and JBP documented.
- * 
- */
 
-class rnabuttonlistener implements ActionListener
-{
-  public void actionPerformed(ActionEvent arg0)
+  public AlignFrame[] getAlignFrames()
   {
-    System.out.println("Good idea ! ");
+    return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
+            : Desktop.getAlignFrames();
 
   }
-}
-
-class pbuttonlistener implements ActionListener
-{
-  public void actionPerformed(ActionEvent arg0)
-  {
-
-  }
-}
-
-class ArgsParser
-{
-  Vector vargs = null;
-
-  public ArgsParser(String[] args)
-  {
-    vargs = new Vector();
-    for (int i = 0; i < args.length; i++)
-    {
-      String arg = args[i].trim();
-      if (arg.charAt(0) == '-')
-      {
-        arg = arg.substring(1);
-      }
-      vargs.addElement(arg);
-    }
-  }
 
   /**
-   * check for and remove first occurence of arg+parameter in arglist.
-   * 
-   * @param arg
-   * @return return the argument following the given arg if arg was in list.
-   */
-  public String getValue(String arg)
-  {
-    return getValue(arg, false);
-  }
-
-  public String getValue(String arg, boolean utf8decode)
-  {
-    int index = vargs.indexOf(arg);
-    String dc = null, ret = null;
-    if (index != -1)
-    {
-      ret = vargs.elementAt(index + 1).toString();
-      vargs.removeElementAt(index);
-      vargs.removeElementAt(index);
-      if (utf8decode && ret != null)
-      {
-        try
-        {
-          dc = URLDecoder.decode(ret, "UTF-8");
-          ret = dc;
-        } catch (Exception e)
-        {
-          // TODO: log failure to decode
-        }
-      }
-    }
-    return ret;
-  }
-
-  /**
-   * check for and remove first occurence of arg in arglist.
-   * 
-   * @param arg
-   * @return true if arg was present in argslist.
+   * Quit method delegates to Desktop.quit - unless running in headless mode
+   * when it just ends the JVM
    */
-  public boolean contains(String arg)
+  public void quit()
   {
-    if (vargs.contains(arg))
+    if (desktop != null)
     {
-      vargs.removeElement(arg);
-      return true;
+      desktop.quit();
     }
     else
     {
-      return false;
+      System.exit(0);
     }
   }
 
-  public String nextValue()
+  public static AlignFrame getCurrentAlignFrame()
   {
-    return vargs.remove(0).toString();
+    return Jalview.currentAlignFrame;
   }
 
-  public int getSize()
+  public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
   {
-    return vargs.size();
+    Jalview.currentAlignFrame = currentAlignFrame;
   }
-
-}
-
-/**
- * keep track of feature fetching tasks.
- * 
- * @author JimP
- * 
- */
-class FeatureFetcher
-{
-  /*
-   * TODO: generalise to track all jalview events to orchestrate batch
-   * processing events.
-   */
-
-  private int queued = 0;
-
-  private int running = 0;
-
-  public FeatureFetcher()
-  {
-
-  }
-
-  public void addFetcher(final AlignFrame af, final Vector dasSources)
-  {
-    final long id = System.currentTimeMillis();
-    queued++;
-    final FeatureFetcher us = this;
-    new Thread(new Runnable()
-    {
-
-      public void run()
-      {
-        synchronized (us)
-        {
-          queued--;
-          running++;
-        }
-
-        af.setProgressBar(MessageManager
-                .getString("status.das_features_being_retrived"), id);
-        af.featureSettings_actionPerformed(null);
-        af.featureSettings.fetchDasFeatures(dasSources, true);
-        af.setProgressBar(null, id);
-        synchronized (us)
-        {
-          running--;
-        }
-      }
-    }).start();
-  }
-
-  public synchronized boolean allFinished()
-  {
-    return queued == 0 && running == 0;
-  }
-
 }
index ca2ae6d..24439ca 100644 (file)
@@ -238,6 +238,7 @@ public class AlignViewController implements AlignViewControllerI
     ColumnSelection cs = viewport.getColumnSelection();
     if (bs.cardinality() > 0 || invert)
     {
+      boolean changed = false;
       if (cs == null)
       {
         cs = new ColumnSelection();
@@ -246,6 +247,7 @@ public class AlignViewController implements AlignViewControllerI
       {
         if (!extendCurrent)
         {
+          changed = !cs.isEmpty();
           cs.clear();
         }
       }
@@ -257,6 +259,7 @@ public class AlignViewController implements AlignViewControllerI
         {
           if (ibs < 0 || i < ibs)
           {
+            changed = true;
             if (toggle && cs.contains(i))
             {
               cs.removeElement(i++);
@@ -278,6 +281,7 @@ public class AlignViewController implements AlignViewControllerI
         for (int i = bs.nextSetBit(alStart); i >= alStart; i = bs
                 .nextSetBit(i + 1))
         {
+          changed = true;
           if (toggle && cs.contains(i))
           {
             cs.removeElement(i);
@@ -288,18 +292,21 @@ public class AlignViewController implements AlignViewControllerI
           }
         }
       }
-      viewport.setColumnSelection(cs);
-      alignPanel.paintAlignment(true);
-      avcg.setStatus(MessageManager.formatMessage(
-              "label.view_controller_toggled_marked",
-              new String[] {
-                  (toggle ? MessageManager.getString("label.toggled")
-                          : MessageManager.getString("label.marked")),
-                  (invert ? (Integer.valueOf((alw - alStart)
-                          - bs.cardinality()).toString()) : (Integer
-                          .valueOf(bs.cardinality()).toString())),
-                  featureType, Integer.valueOf(nseq).toString() }));
-      return true;
+      if (changed)
+      {
+        viewport.setColumnSelection(cs);
+        alignPanel.paintAlignment(true);
+        avcg.setStatus(MessageManager.formatMessage(
+                "label.view_controller_toggled_marked",
+                new String[] {
+                    (toggle ? MessageManager.getString("label.toggled")
+                            : MessageManager.getString("label.marked")),
+                    (invert ? (Integer.valueOf((alw - alStart)
+                            - bs.cardinality()).toString()) : (Integer
+                            .valueOf(bs.cardinality()).toString())),
+                    featureType, Integer.valueOf(nseq).toString() }));
+        return true;
+      }
     }
     else
     {
@@ -311,8 +318,8 @@ public class AlignViewController implements AlignViewControllerI
         cs.clear();
         alignPanel.paintAlignment(true);
       }
-      return false;
     }
+    return false;
   }
 
   @Override
index a9b0d53..f14539b 100755 (executable)
@@ -30,6 +30,7 @@ import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -1287,6 +1288,22 @@ public class Alignment implements AlignmentI
     }
   }
 
+  /**
+   * adds a set of mappings (while ignoring any duplicates)
+   */
+  @Override
+  public void addCodonFrames(Iterable<AlignedCodonFrame> codons)
+  {
+    if (codons != null)
+    {
+      Iterator<AlignedCodonFrame> it = codons.iterator();
+      while (it.hasNext())
+      {
+        addCodonFrame(it.next());
+      }
+    }
+  }
+
   /*
    * (non-Javadoc)
    * 
index 76d1a48..4ae8ba2 100755 (executable)
@@ -363,6 +363,14 @@ public interface AlignmentI extends AnnotatedCollectionI
   void addCodonFrame(AlignedCodonFrame codons);
 
   /**
+   * add a set of aligned codons mappings for this alignment, apart from any
+   * duplicates which are ignored
+   * 
+   * @param codons
+   */
+  void addCodonFrames(Iterable<AlignedCodonFrame> codons);
+
+  /**
    * remove a particular codon frame reference from this alignment
    * 
    * @param codons
index c23b772..aaf70b8 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.datamodel;
 
+import jalview.util.Comparison;
 import jalview.util.ShiftList;
 import jalview.viewmodel.annotationfilter.AnnotationFilterParameter;
 import jalview.viewmodel.annotationfilter.AnnotationFilterParameter.SearchableAnnotationField;
@@ -31,10 +32,14 @@ import java.util.List;
 import java.util.Vector;
 
 /**
- * NOTE: Columns are zero based.
+ * Data class holding the selected columns and hidden column ranges for a view.
+ * Ranges are base 1.
  */
 public class ColumnSelection
 {
+  /**
+   * A class to hold an efficient representation of selected columns
+   */
   private class IntList
   {
     /*
@@ -204,9 +209,27 @@ public class ColumnSelection
       }
       return rlist;
     }
+
+    @Override
+    public int hashCode()
+    {
+      // TODO Auto-generated method stub
+      return selected.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+      if (obj instanceof IntList)
+      {
+        return ((IntList) obj).selected.equals(selected);
+      }
+      return false;
+    }
   }
 
-  IntList selected = new IntList();
+  IntList selection = new IntList();
+
   /*
    * list of hidden column [start, end] ranges; the list is maintained in
    * ascending start column order
@@ -221,7 +244,7 @@ public class ColumnSelection
    */
   public void addElement(int col)
   {
-    selected.add(col);
+    selection.add(col);
   }
 
   /**
@@ -229,7 +252,7 @@ public class ColumnSelection
    */
   public void clear()
   {
-    selected.clear();
+    selection.clear();
   }
 
   /**
@@ -240,7 +263,7 @@ public class ColumnSelection
    */
   public void removeElement(int col)
   {
-    selected.remove(col);
+    selection.remove(col);
   }
 
   /**
@@ -257,9 +280,9 @@ public class ColumnSelection
     for (int i = start; i < end; i++)
     {
       colInt = new Integer(i);
-      if (selected.contains(colInt))
+      if (selection.contains(colInt))
       {
-        selected.remove(colInt);
+        selection.remove(colInt);
       }
     }
   }
@@ -271,7 +294,7 @@ public class ColumnSelection
    */
   public List<Integer> getSelected()
   {
-    return selected.getList();
+    return selection.getList();
   }
 
   /**
@@ -280,7 +303,7 @@ public class ColumnSelection
    */
   public List<int[]> getSelectedRanges()
   {
-    return selected.getRanges();
+    return selection.getRanges();
   }
 
   /**
@@ -292,7 +315,7 @@ public class ColumnSelection
    */
   public boolean contains(int col)
   {
-    return (col > -1) ? selected.isSelected(col) : false;
+    return (col > -1) ? selection.isSelected(col) : false;
   }
 
   /**
@@ -300,7 +323,7 @@ public class ColumnSelection
    */
   public boolean isEmpty()
   {
-    return selected == null || selected.isEmpty();
+    return selection == null || selection.isEmpty();
   }
 
   /**
@@ -310,11 +333,11 @@ public class ColumnSelection
    */
   public int getMax()
   {
-    if (selected.isEmpty())
+    if (selection.isEmpty())
     {
       return -1;
     }
-    return selected.getMaxColumn();
+    return selection.getMaxColumn();
   }
 
   /**
@@ -324,11 +347,11 @@ public class ColumnSelection
    */
   public int getMin()
   {
-    if (selected.isEmpty())
+    if (selection.isEmpty())
     {
       return 1000000000;
     }
-    return selected.getMinColumn();
+    return selection.getMinColumn();
   }
 
   /**
@@ -342,7 +365,7 @@ public class ColumnSelection
   public List<int[]> compensateForEdit(int start, int change)
   {
     List<int[]> deletedHiddenColumns = null;
-    selected.compensateForEdits(start, change);
+    selection.compensateForEdits(start, change);
 
     if (hiddenColumns != null)
     {
@@ -392,7 +415,7 @@ public class ColumnSelection
   private void compensateForDelEdits(int start, int change)
   {
 
-    selected.compensateForEdits(start, change);
+    selection.compensateForEdits(start, change);
 
     if (hiddenColumns != null)
     {
@@ -569,12 +592,12 @@ public class ColumnSelection
             hiddenColumns = null;
           }
         }
-        if (selected != null && selected.size() > 0)
+        if (selection != null && selection.size() > 0)
         {
-          selected.pruneColumnList(shifts);
-          if (selected != null && selected.size() == 0)
+          selection.pruneColumnList(shifts);
+          if (selection != null && selection.size() == 0)
           {
-            selected = null;
+            selection = null;
           }
         }
         // and shift the rest.
@@ -598,7 +621,7 @@ public class ColumnSelection
    * Return absolute column index for a visible column index
    * 
    * @param column
-   *          int column index in alignment view
+   *          int column index in alignment view (count from zero)
    * @return alignment column index for column
    */
   public int adjustForHiddenColumns(int column)
@@ -741,12 +764,13 @@ public class ColumnSelection
 
   public void hideSelectedColumns()
   {
-    synchronized (selected) {
-      for (int[] selregions:selected.getRanges())
+    synchronized (selection)
+    {
+      for (int[] selregions : selection.getRanges())
       {
         hideColumns(selregions[0], selregions[1]);
       }
-      selected.clear();
+      selection.clear();
     }
 
   }
@@ -806,7 +830,7 @@ public class ColumnSelection
     /*
      * remaining case is that the new range follows everything else
      */
-      hiddenColumns.addElement(new int[] { start, end });
+    hiddenColumns.addElement(new int[] { start, end });
   }
 
   /**
@@ -924,12 +948,12 @@ public class ColumnSelection
   {
     if (copy != null)
     {
-      if (copy.selected != null)
+      if (copy.selection != null)
       {
-        selected = new IntList();
-        for (int i = 0, j = copy.selected.size(); i < j; i++)
+        selection = new IntList();
+        for (int i = 0, j = copy.selection.size(); i < j; i++)
         {
-          selected.add(copy.selected.elementAt(i));
+          selection.add(copy.selection.elementAt(i));
         }
       }
       if (copy.hiddenColumns != null)
@@ -1077,6 +1101,84 @@ public class ColumnSelection
   }
 
   /**
+   * Locate the first and last position visible for this sequence. if seq isn't
+   * visible then return the position of the left and right of the hidden
+   * boundary region, and the corresponding alignment column indices for the
+   * extent of the sequence
+   * 
+   * @param seq
+   * @return int[] { visible start, visible end, first seqpos, last seqpos,
+   *         alignment index for seq start, alignment index for seq end }
+   */
+  public int[] locateVisibleBoundsOfSequence(SequenceI seq)
+  {
+    int fpos=seq.getStart(),lpos= seq.getEnd();
+    int start = 0;
+    
+    if (hiddenColumns == null || hiddenColumns.size() == 0)
+    {
+      int ifpos = seq.findIndex(fpos) - 1, ilpos = seq.findIndex(lpos) - 1;
+      return new int[] { ifpos, ilpos, fpos, lpos, ifpos, ilpos };
+    }
+
+    // Simply walk along the sequence whilst watching for hidden column
+    // boundaries
+    List<int[]> regions = getHiddenColumns();
+    int spos = fpos, lastvispos = -1, rcount = 0, hideStart = seq
+            .getLength(), hideEnd = -1;
+    int visPrev = 0, visNext = 0, firstP = -1, lastP = -1;
+    boolean foundStart = false;
+    for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd()
+            && p < pLen; p++)
+    {
+      if (!Comparison.isGap(seq.getCharAt(p)))
+      {
+        // keep track of first/last column
+        // containing sequence data regardless of visibility
+        if (firstP == -1)
+        {
+          firstP = p;
+        }
+        lastP = p;
+        // update hidden region start/end
+        while (hideEnd < p && rcount < regions.size())
+        {
+          int[] region = regions.get(rcount++);
+          visPrev = visNext;
+          visNext += region[0] - visPrev;
+          hideStart = region[0];
+          hideEnd = region[1];
+        }
+        if (hideEnd < p)
+        {
+          hideStart = seq.getLength();
+        }
+        // update visible boundary for sequence
+        if (p < hideStart)
+        {
+          if (!foundStart)
+          {
+            fpos = spos;
+            start = p;
+            foundStart = true;
+          }
+          lastvispos = p;
+          lpos = spos;
+        }
+        // look for next sequence position
+        spos++;
+      }
+    }
+    if (foundStart)
+    {
+      return new int[] { findColumnPosition(start),
+          findColumnPosition(lastvispos), fpos, lpos, firstP, lastP };
+    }
+    // otherwise, sequence was completely hidden
+    return new int[] { visPrev, visNext, 0, 0, firstP, lastP };
+  }
+
+  /**
    * delete any columns in alignmentAnnotation that are hidden (including
    * sequence associated annotation).
    * 
@@ -1226,7 +1328,7 @@ public class ColumnSelection
       {
         if (hiddenColumns != null && isVisible(col.intValue()))
         {
-          selected.add(col);
+          selection.add(col);
         }
       }
     }
@@ -1240,8 +1342,8 @@ public class ColumnSelection
    */
   public void setElementsFrom(ColumnSelection colsel)
   {
-    selected = new IntList();
-    if (colsel.selected != null && colsel.selected.size() > 0)
+    selection = new IntList();
+    if (colsel.selection != null && colsel.selection.size() > 0)
     {
       if (hiddenColumns != null && hiddenColumns.size() > 0)
       {
@@ -1408,7 +1510,7 @@ public class ColumnSelection
    */
   public boolean hasSelectedColumns()
   {
-    return (selected != null && selected.size() > 0);
+    return (selection != null && selection.size() > 0);
   }
 
   /**
@@ -1447,6 +1549,8 @@ public class ColumnSelection
   public boolean filterAnnotations(Annotation[] annotations,
           AnnotationFilterParameter filterParams)
   {
+    // JBPNote - this method needs to be refactored to become independent of
+    // viewmodel package
     this.revealAllHiddenColumns();
     this.clear();
     int count = 0;
@@ -1528,4 +1632,75 @@ public class ColumnSelection
     } while (count < annotations.length);
     return false;
   }
+
+  /**
+   * Returns a hashCode built from selected columns and hidden column ranges
+   */
+  @Override
+  public int hashCode()
+  {
+    int hashCode = selection.hashCode();
+    if (hiddenColumns != null)
+    {
+      for (int[] hidden : hiddenColumns)
+      {
+        hashCode = 31 * hashCode + hidden[0];
+        hashCode = 31 * hashCode + hidden[1];
+      }
+    }
+    return hashCode;
+  }
+
+  /**
+   * Answers true if comparing to a ColumnSelection with the same selected
+   * columns and hidden columns, else false
+   */
+  @Override
+  public boolean equals(Object obj)
+  {
+    if (!(obj instanceof ColumnSelection))
+    {
+      return false;
+    }
+    ColumnSelection that = (ColumnSelection) obj;
+
+    /*
+     * check columns selected are either both null, or match
+     */
+    if (this.selection == null)
+    {
+      if (that.selection != null)
+      {
+        return false;
+      }
+    }
+    if (!this.selection.equals(that.selection))
+    {
+      return false;
+    }
+
+    /*
+     * check hidden columns are either both null, or match
+     */
+    if (this.hiddenColumns == null)
+    {
+      return (that.hiddenColumns == null);
+    }
+    if (that.hiddenColumns == null
+            || that.hiddenColumns.size() != this.hiddenColumns.size())
+    {
+      return false;
+    }
+    int i = 0;
+    for (int[] thisRange : hiddenColumns)
+    {
+      int[] thatRange = that.hiddenColumns.get(i++);
+      if (thisRange[0] != thatRange[0] || thisRange[1] != thatRange[1])
+      {
+        return false;
+      }
+    }
+    return true;
+  }
+
 }
index 53642b5..66a075e 100755 (executable)
@@ -98,6 +98,82 @@ public class DBRefEntry implements DBRefEntryI
   }
 
   /**
+   * Answers true if this object is either equivalent to, or can be 'improved'
+   * by, the given entry. Specifically, answers true if
+   * <ul>
+   * <li>source and accession are identical (ignoring case)</li>
+   * <li>version is identical (ignoring case), or this version is of the format
+   * "someSource:0", in which case the version for the other entry replaces it</li>
+   * <li>mappings are not compared but if this entry has no mapping, replace
+   * with that for the other entry</li>
+   * </ul>
+   * 
+   * @param other
+   * @return
+   */
+  @Override
+  public boolean updateFrom(DBRefEntryI other)
+  {
+    if (other == null)
+    {
+      return false;
+    }
+    if (other == this)
+    {
+      return true;
+    }
+
+    /*
+     * source must either match or be both null
+     */
+    String otherSource = other.getSource();
+    if ((source == null && otherSource != null)
+            || (source != null && otherSource == null)
+            || (source != null && !source.equalsIgnoreCase(otherSource)))
+    {
+      return false;
+    }
+
+    /*
+     * accession id must either match or be both null
+     */
+    String otherAccession = other.getAccessionId();
+    if ((accessionId == null && otherAccession != null)
+            || (accessionId != null && otherAccession == null)
+            || (accessionId != null && !accessionId.equalsIgnoreCase(otherAccession)))
+    {
+      return false;
+    }
+
+    /*
+     * if my version is null, "0" or "source:0" then replace with other version,
+     * otherwise the versions have to match
+     */
+    String otherVersion = other.getVersion();
+    if ((version == null || version.equals("0") || version.endsWith(":0"))
+            && otherVersion != null)
+    {
+      setVersion(otherVersion);
+    }
+    else
+    {
+      if (!version.equalsIgnoreCase(otherVersion))
+      {
+        return false;
+      }
+    }
+
+    /*
+     * if I have no mapping, take that of the other dbref
+     */
+    if (map == null)
+    {
+      setMap(other.getMap());
+    }
+    return true;
+  }
+
+  /**
    * test for similar DBRef attributes, except for the map object.
    * 
    * @param entry
@@ -106,6 +182,7 @@ public class DBRefEntry implements DBRefEntryI
   @Override
   public boolean equalRef(DBRefEntryI entry)
   {
+    // TODO is this method and equals() not needed?
     if (entry == null)
     {
       return false;
index 91b49eb..a2243be 100755 (executable)
@@ -88,6 +88,8 @@ public class DBRefSource
    */
   public static final String ENSEMBL = "ENSEMBL";
 
+  public static final String ENSEMBLGENOMES = "ENSEMBLGENOMES";
+
   /**
    * List of databases whose sequences might have coding regions annotated
    */
index d25eb96..2306bec 100644 (file)
@@ -28,8 +28,7 @@ package jalview.datamodel;
  */
 public class FeatureProperties
 {
-
-  private static final String EMBL_CODING_FEATURE = "CDS";
+  public static final String EMBL_CODING_FEATURE = "CDS";
 
   public static final String EXONPOS = "exon number";
 
index a61f093..151d8c4 100755 (executable)
@@ -966,26 +966,25 @@ public class Sequence extends ASequence implements SequenceI
       dbrefs = new DBRefEntry[0];
     }
 
-    int i, iSize = dbrefs.length;
-
-    for (i = 0; i < iSize; i++)
+    for (DBRefEntryI dbr : dbrefs)
     {
-      if (dbrefs[i].equalRef(entry))
+      if (dbr.updateFrom(entry))
       {
-        if (entry.getMap() != null)
-        {
-          if (dbrefs[i].getMap() == null)
-          {
-            // overwrite with 'superior' entry that contains a mapping.
-            dbrefs[i] = entry;
-          }
-        }
+        /*
+         * found a dbref that either matched, or could be
+         * updated from, the new entry - no need to add it
+         */
         return;
       }
     }
 
-    DBRefEntry[] temp = new DBRefEntry[iSize + 1];
-    System.arraycopy(dbrefs, 0, temp, 0, iSize);
+    /*
+     * extend the array to make room for one more
+     */
+    // TODO use an ArrayList instead
+    int j = dbrefs.length;
+    DBRefEntry[] temp = new DBRefEntry[j + 1];
+    System.arraycopy(dbrefs, 0, temp, 0, j);
     temp[temp.length - 1] = entry;
 
     dbrefs = temp;
index f2eb8ac..c75d6f2 100755 (executable)
@@ -39,6 +39,9 @@ public class SequenceFeature
   // private key for Phase designed not to conflict with real GFF data
   private static final String PHASE = "!Phase";
 
+  // private key for ENA location designed not to conflict with real GFF data
+  private static final String LOCATION = "!Location";
+
   /*
    * ATTRIBUTES is reserved for the GFF 'column 9' data, formatted as
    * name1=value1;name2=value2,value3;...etc
@@ -55,6 +58,10 @@ public class SequenceFeature
 
   public String description;
 
+  /*
+   * a map of key-value pairs; may be populated from GFF 'column 9' data,
+   * other data sources (e.g. GenBank file), or programmatically
+   */
   public Map<String, Object> otherDetails;
 
   public Vector<String> links;
@@ -480,6 +487,26 @@ public class SequenceFeature
   }
 
   /**
+   * Sets the 'raw' ENA format location specifier e.g. join(12..45,89..121)
+   * 
+   * @param loc
+   */
+  public void setEnaLocation(String loc)
+  {
+    setValue(LOCATION, loc);
+  }
+
+  /**
+   * Gets the 'raw' ENA format location specifier e.g. join(12..45,89..121)
+   * 
+   * @param loc
+   */
+  public String getEnaLocation()
+  {
+    return (String) getValue(LOCATION);
+  }
+
+  /**
    * Readable representation, for debug only, not guaranteed not to change
    * between versions
    */
index 60040d8..69eb1d4 100755 (executable)
@@ -435,7 +435,21 @@ public interface SequenceI extends ASequenceI
    */
   public PDBEntry getPDBEntry(String pdbId);
 
+  /**
+   * Set the distinct source database, and accession number from which a
+   * sequence and its start-end data were derived from. This is very important
+   * for SIFTS mappings and must be set prior to performing SIFTS mapping.
+   * 
+   * @param dbRef
+   *          the source dbRef for the sequence
+   */
   public void setSourceDBRef(DBRefEntryI dbRef);
 
+  /**
+   * Get the distinct source database, and accession number from which a
+   * sequence and its start-end data were derived from.
+   * 
+   * @return
+   */
   public DBRefEntryI getSourceDBRef();
 }
diff --git a/src/jalview/datamodel/xdb/embl/BasePosition.java b/src/jalview/datamodel/xdb/embl/BasePosition.java
deleted file mode 100644 (file)
index 3737adc..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- * 
- * This file is part of Jalview.
- * 
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *  
- * Jalview is distributed in the hope that it will be useful, but 
- * WITHOUT ANY WARRANTY; without even the implied warranty 
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
- * PURPOSE.  See the GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.datamodel.xdb.embl;
-
-/**
- * Data model for a feature/location/locationElement/basePosition read from an
- * EMBL query reply
- * 
- * @see embl_mapping.xml
- */
-public class BasePosition
-{
-  String type;
-
-  String pos;
-
-  /**
-   * @return the pos
-   */
-  public String getPos()
-  {
-    return pos;
-  }
-
-  /**
-   * @param pos
-   *          the pos to set
-   */
-  public void setPos(String pos)
-  {
-    this.pos = pos;
-  }
-
-  /**
-   * @return the type
-   */
-  public String getType()
-  {
-    return type;
-  }
-
-  /**
-   * @param type
-   *          the type to set
-   */
-  public void setType(String type)
-  {
-    this.type = type;
-  }
-}
index 691a4c9..f8c0bbe 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.datamodel.xdb.embl;
 
 import jalview.analysis.SequenceIdMatcher;
+import jalview.bin.Cache;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.FeatureProperties;
@@ -29,10 +30,12 @@ import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.util.DBRefUtils;
+import jalview.util.DnaUtils;
 import jalview.util.MapList;
 import jalview.util.MappingUtils;
 import jalview.util.StringUtils;
 
+import java.text.ParseException;
 import java.util.Arrays;
 import java.util.Hashtable;
 import java.util.List;
@@ -57,17 +60,29 @@ public class EmblEntry
 
   String accession;
 
-  String version;
+  String entryVersion;
 
-  String taxDivision;
+  String sequenceVersion;
 
-  String desc;
+  String dataClass;
 
-  String rCreated;
+  String moleculeType;
 
-  String rLastUpdated;
+  String topology;
 
-  String lastUpdated;
+  String sequenceLength;
+
+  String taxonomicDivision;
+
+  String description;
+
+  String firstPublicDate;
+
+  String firstPublicRelease;
+
+  String lastUpdatedDate;
+
+  String lastUpdatedRelease;
 
   Vector<String> keywords;
 
@@ -112,23 +127,6 @@ public class EmblEntry
   }
 
   /**
-   * @return the desc
-   */
-  public String getDesc()
-  {
-    return desc;
-  }
-
-  /**
-   * @param desc
-   *          the desc to set
-   */
-  public void setDesc(String desc)
-  {
-    this.desc = desc;
-  }
-
-  /**
    * @return the features
    */
   public Vector<EmblFeature> getFeatures()
@@ -163,57 +161,6 @@ public class EmblEntry
   }
 
   /**
-   * @return the lastUpdated
-   */
-  public String getLastUpdated()
-  {
-    return lastUpdated;
-  }
-
-  /**
-   * @param lastUpdated
-   *          the lastUpdated to set
-   */
-  public void setLastUpdated(String lastUpdated)
-  {
-    this.lastUpdated = lastUpdated;
-  }
-
-  /**
-   * @return the releaseCreated
-   */
-  public String getRCreated()
-  {
-    return rCreated;
-  }
-
-  /**
-   * @param releaseCreated
-   *          the releaseCreated to set
-   */
-  public void setRCreated(String releaseCreated)
-  {
-    this.rCreated = releaseCreated;
-  }
-
-  /**
-   * @return the releaseLastUpdated
-   */
-  public String getRLastUpdated()
-  {
-    return rLastUpdated;
-  }
-
-  /**
-   * @param releaseLastUpdated
-   *          the releaseLastUpdated to set
-   */
-  public void setRLastUpdated(String releaseLastUpdated)
-  {
-    this.rLastUpdated = releaseLastUpdated;
-  }
-
-  /**
    * @return the sequence
    */
   public EmblSequence getSequence()
@@ -231,40 +178,6 @@ public class EmblEntry
   }
 
   /**
-   * @return the taxDivision
-   */
-  public String getTaxDivision()
-  {
-    return taxDivision;
-  }
-
-  /**
-   * @param taxDivision
-   *          the taxDivision to set
-   */
-  public void setTaxDivision(String taxDivision)
-  {
-    this.taxDivision = taxDivision;
-  }
-
-  /**
-   * @return the version
-   */
-  public String getVersion()
-  {
-    return version;
-  }
-
-  /**
-   * @param version
-   *          the version to set
-   */
-  public void setVersion(String version)
-  {
-    this.version = version;
-  }
-
-  /**
    * Recover annotated sequences from EMBL file
    * 
    * @param sourceDb
@@ -276,14 +189,15 @@ public class EmblEntry
   {
     SequenceI dna = new Sequence(sourceDb + "|" + accession,
             sequence.getSequence());
-    dna.setDescription(desc);
-    DBRefEntry retrievedref = new DBRefEntry(sourceDb, version, accession);
+    dna.setDescription(description);
+    DBRefEntry retrievedref = new DBRefEntry(sourceDb,
+            getSequenceVersion(), accession);
     dna.addDBRef(retrievedref);
     // add map to indicate the sequence is a valid coordinate frame for the
     // dbref
     retrievedref.setMap(new Mapping(null, new int[] { 1, dna.getLength() },
             new int[] { 1, dna.getLength() }, 1, 1));
-    // TODO: transform EMBL Database refs to canonical form
+
     if (dbRefs != null)
     {
       for (DBRefEntry dbref : dbRefs)
@@ -292,6 +206,7 @@ public class EmblEntry
       }
     }
 
+    SequenceIdMatcher matcher = new SequenceIdMatcher(peptides);
     try
     {
       for (EmblFeature feature : features)
@@ -305,7 +220,7 @@ public class EmblEntry
         }
         if (FeatureProperties.isCodingFeature(sourceDb, feature.getName()))
         {
-          parseCodingFeature(feature, sourceDb, dna, peptides);
+          parseCodingFeature(feature, sourceDb, dna, peptides, matcher);
         }
       }
     } catch (Exception e)
@@ -335,7 +250,7 @@ public class EmblEntry
    *          list of protein product sequences for Embl entry
    */
   void parseCodingFeature(EmblFeature feature, String sourceDb,
-          SequenceI dna, List<SequenceI> peptides)
+          SequenceI dna, List<SequenceI> peptides, SequenceIdMatcher matcher)
   {
     boolean isEmblCdna = sourceDb.equals(DBRefSource.EMBLCDS);
 
@@ -345,7 +260,6 @@ public class EmblEntry
     String prname = "";
     String prid = null;
     Map<String, String> vals = new Hashtable<String, String>();
-    SequenceIdMatcher matcher = new SequenceIdMatcher(peptides);
 
     /*
      * codon_start 1/2/3 in EMBL corresponds to phase 0/1/2 in CDS
@@ -369,13 +283,13 @@ public class EmblEntry
         }
         else if (qname.equals("protein_id"))
         {
-          prid = q.getValues()[0];
+          prid = q.getValues()[0].trim();
         }
         else if (qname.equals("codon_start"))
         {
           try
           {
-            codonStart = Integer.parseInt(q.getValues()[0]);
+            codonStart = Integer.parseInt(q.getValues()[0].trim());
           } catch (NumberFormatException e)
           {
             System.err.println("Invalid codon_start in XML for "
@@ -385,7 +299,7 @@ public class EmblEntry
         else if (qname.equals("product"))
         {
           // sometimes name is returned e.g. for V00488
-          prname = q.getValues()[0];
+          prname = q.getValues()[0].trim();
         }
         else
         {
@@ -479,7 +393,8 @@ public class EmblEntry
           DBRefEntry pcdnaref = new DBRefEntry();
           pcdnaref.setAccessionId(prid);
           pcdnaref.setSource(DBRefSource.EMBLCDS);
-          pcdnaref.setVersion(getVersion()); // same as parent EMBL version.
+          pcdnaref.setVersion(getSequenceVersion()); // same as parent EMBL
+                                                     // version.
           MapList mp = new MapList(new int[] { 1, prseq.length() },
                   new int[] { 1 + (codonStart - 1),
                       (codonStart - 1) + 3 * prseq.length() }, 1, 3);
@@ -499,6 +414,7 @@ public class EmblEntry
         SequenceFeature sf = makeCdsFeature(exon, xint, prname, prid, vals,
                 codonStart);
         sf.setType(feature.getName()); // "CDS"
+        sf.setEnaLocation(feature.getLocation());
         sf.setFeatureGroup(sourceDb);
         dna.addSequenceFeature(sf);
       }
@@ -559,7 +475,7 @@ public class EmblEntry
           if (map != null)
           {
             Mapping pmap = new Mapping(dna, map.getMap().getInverse());
-            pref = new DBRefEntry(sourceDb, getVersion(),
+            pref = new DBRefEntry(sourceDb, getSequenceVersion(),
                     this.getAccession());
             pref.setMap(pmap);
             if (map.getTo() != null)
@@ -578,7 +494,7 @@ public class EmblEntry
           protEMBLCDS = new DBRefEntry();
           protEMBLCDS.setAccessionId(prid);
           protEMBLCDS.setSource(DBRefSource.EMBLCDSProduct);
-          protEMBLCDS.setVersion(getVersion());
+          protEMBLCDS.setVersion(getSequenceVersion());
           protEMBLCDS
                   .setMap(new Mapping(product, map.getMap().getInverse()));
         }
@@ -650,7 +566,7 @@ public class EmblEntry
   }
 
   /**
-   * Returns the CDS positions as a list of [start, end, start, end...]
+   * Returns the CDS positions as a single array of [start, end, start, end...]
    * positions. If on the reverse strand, these will be in descending order.
    * 
    * @param feature
@@ -658,28 +574,41 @@ public class EmblEntry
    */
   protected int[] getCdsRanges(EmblFeature feature)
   {
-    if (feature.locations == null)
+    if (feature.location == null)
     {
       return new int[] {};
     }
-    int cdsBoundaryCount = 0; // count of all start/stop locations
-    int[][] cdsLocations = new int[feature.locations.size()][];
-    int locationNumber = 0;
-    for (EmblFeatureLocations loc : feature.locations)
+
+    try
     {
-      int[] locationRanges = loc.getElementRanges(accession);
-      cdsLocations[locationNumber++] = locationRanges;
-      cdsBoundaryCount += locationRanges.length;
-    }
-    int[] cdsRanges = new int[cdsBoundaryCount];
-    int copyTo = 0;
-    for (int[] ranges : cdsLocations)
+      List<int[]> ranges = DnaUtils.parseLocation(feature.location);
+      return listToArray(ranges);
+    } catch (ParseException e)
     {
-      System.arraycopy(ranges, 0, cdsRanges, copyTo, ranges.length);
-      copyTo += ranges.length;
+      Cache.log.warn(String.format(
+              "Not parsing inexact CDS location %s in ENA %s",
+              feature.location, this.accession));
+      return new int[] {};
     }
-    return cdsRanges;
+  }
 
+  /**
+   * Converts a list of [start, end] ranges to a single array of [start, end,
+   * start, end ...]
+   * 
+   * @param ranges
+   * @return
+   */
+  int[] listToArray(List<int[]> ranges)
+  {
+    int[] result = new int[ranges.size() * 2];
+    int i = 0;
+    for (int[] range : ranges)
+    {
+      result[i++] = range[0];
+      result[i++] = range[1];
+    }
+    return result;
   }
 
   /**
@@ -754,4 +683,124 @@ public class EmblEntry
     }
     return exon;
   }
+
+  public String getSequenceVersion()
+  {
+    return sequenceVersion;
+  }
+
+  public void setSequenceVersion(String sequenceVersion)
+  {
+    this.sequenceVersion = sequenceVersion;
+  }
+
+  public String getSequenceLength()
+  {
+    return sequenceLength;
+  }
+
+  public void setSequenceLength(String sequenceLength)
+  {
+    this.sequenceLength = sequenceLength;
+  }
+
+  public String getEntryVersion()
+  {
+    return entryVersion;
+  }
+
+  public void setEntryVersion(String entryVersion)
+  {
+    this.entryVersion = entryVersion;
+  }
+
+  public String getMoleculeType()
+  {
+    return moleculeType;
+  }
+
+  public void setMoleculeType(String moleculeType)
+  {
+    this.moleculeType = moleculeType;
+  }
+
+  public String getTopology()
+  {
+    return topology;
+  }
+
+  public void setTopology(String topology)
+  {
+    this.topology = topology;
+  }
+
+  public String getTaxonomicDivision()
+  {
+    return taxonomicDivision;
+  }
+
+  public void setTaxonomicDivision(String taxonomicDivision)
+  {
+    this.taxonomicDivision = taxonomicDivision;
+  }
+
+  public String getDescription()
+  {
+    return description;
+  }
+
+  public void setDescription(String description)
+  {
+    this.description = description;
+  }
+
+  public String getFirstPublicDate()
+  {
+    return firstPublicDate;
+  }
+
+  public void setFirstPublicDate(String firstPublicDate)
+  {
+    this.firstPublicDate = firstPublicDate;
+  }
+
+  public String getFirstPublicRelease()
+  {
+    return firstPublicRelease;
+  }
+
+  public void setFirstPublicRelease(String firstPublicRelease)
+  {
+    this.firstPublicRelease = firstPublicRelease;
+  }
+
+  public String getLastUpdatedDate()
+  {
+    return lastUpdatedDate;
+  }
+
+  public void setLastUpdatedDate(String lastUpdatedDate)
+  {
+    this.lastUpdatedDate = lastUpdatedDate;
+  }
+
+  public String getLastUpdatedRelease()
+  {
+    return lastUpdatedRelease;
+  }
+
+  public void setLastUpdatedRelease(String lastUpdatedRelease)
+  {
+    this.lastUpdatedRelease = lastUpdatedRelease;
+  }
+
+  public String getDataClass()
+  {
+    return dataClass;
+  }
+
+  public void setDataClass(String dataClass)
+  {
+    this.dataClass = dataClass;
+  }
 }
index 7e503c9..51d740b 100644 (file)
@@ -37,7 +37,7 @@ public class EmblFeature
 
   Vector<Qualifier> qualifiers;
 
-  Vector<EmblFeatureLocations> locations;
+  String location;
 
   /**
    * @return the dbRefs
@@ -57,20 +57,19 @@ public class EmblFeature
   }
 
   /**
-   * @return the locations
+   * @return the location
    */
-  public Vector<EmblFeatureLocations> getLocations()
+  public String getLocation()
   {
-    return locations;
+    return location;
   }
 
   /**
-   * @param locations
-   *          the locations to set
+   * @param loc
    */
-  public void setLocations(Vector<EmblFeatureLocations> locations)
+  public void setLocation(String loc)
   {
-    this.locations = locations;
+    this.location = loc;
   }
 
   /**
diff --git a/src/jalview/datamodel/xdb/embl/EmblFeatureLocElement.java b/src/jalview/datamodel/xdb/embl/EmblFeatureLocElement.java
deleted file mode 100644 (file)
index 134ce9e..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- * 
- * This file is part of Jalview.
- * 
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *  
- * Jalview is distributed in the hope that it will be useful, but 
- * WITHOUT ANY WARRANTY; without even the implied warranty 
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
- * PURPOSE.  See the GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.datamodel.xdb.embl;
-
-/**
- * Data model for a feature/location/locationElement read from an EMBL query
- * reply
- * 
- * @see embl_mapping.xml
- */
-public class EmblFeatureLocElement
-{
-  String type;
-
-  String accession;
-
-  String version;
-
-  boolean complement;
-
-  BasePosition basePositions[];
-
-  /**
-   * @return the accession
-   */
-  public String getAccession()
-  {
-    return accession;
-  }
-
-  /**
-   * @param accession
-   *          the accession to set
-   */
-  public void setAccession(String accession)
-  {
-    this.accession = accession;
-  }
-
-  /**
-   * @return the basePositions
-   */
-  public BasePosition[] getBasePositions()
-  {
-    return basePositions;
-  }
-
-  /**
-   * @param basePositions
-   *          the basePositions to set
-   */
-  public void setBasePositions(BasePosition[] basePositions)
-  {
-    this.basePositions = basePositions;
-  }
-
-  /**
-   * @return the complement
-   */
-  public boolean isComplement()
-  {
-    return complement;
-  }
-
-  /**
-   * @param complement
-   *          the complement to set
-   */
-  public void setComplement(boolean complement)
-  {
-    this.complement = complement;
-  }
-
-  /**
-   * @return the type
-   */
-  public String getType()
-  {
-    return type;
-  }
-
-  /**
-   * @param type
-   *          the type to set
-   */
-  public void setType(String type)
-  {
-    this.type = type;
-  }
-
-  /**
-   * @return the version
-   */
-  public String getVersion()
-  {
-    return version;
-  }
-
-  /**
-   * @param version
-   *          the version to set
-   */
-  public void setVersion(String version)
-  {
-    this.version = version;
-  }
-}
diff --git a/src/jalview/datamodel/xdb/embl/EmblFeatureLocations.java b/src/jalview/datamodel/xdb/embl/EmblFeatureLocations.java
deleted file mode 100644 (file)
index 9774004..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- * 
- * This file is part of Jalview.
- * 
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *  
- * Jalview is distributed in the hope that it will be useful, but 
- * WITHOUT ANY WARRANTY; without even the implied warranty 
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
- * PURPOSE.  See the GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.datamodel.xdb.embl;
-
-import jalview.bin.Cache;
-import jalview.util.ArrayUtils;
-
-import java.util.Arrays;
-import java.util.Vector;
-
-/**
- * Data model for a &lt;location&gt; child element of a &lt;feature&gt; read
- * from an EMBL query reply
- * 
- * @see embl_mapping.xml
- * @see http://www.insdc.org/files/feature_table.html#3.4.2
- */
-public class EmblFeatureLocations
-{
-  Vector<EmblFeatureLocElement> locElements;
-
-  String locationType;
-
-  boolean locationComplement;
-
-  /**
-   * @return the locationComplement
-   */
-  public boolean isLocationComplement()
-  {
-    return locationComplement;
-  }
-
-  /**
-   * @param locationComplement
-   *          the locationComplement to set
-   */
-  public void setLocationComplement(boolean locationComplement)
-  {
-    this.locationComplement = locationComplement;
-  }
-
-  /**
-   * @return the locationType
-   */
-  public String getLocationType()
-  {
-    return locationType;
-  }
-
-  /**
-   * @param locationType
-   *          the locationType to set
-   */
-  public void setLocationType(String locationType)
-  {
-    this.locationType = locationType;
-  }
-
-  /**
-   * @return the locElements
-   */
-  public Vector<EmblFeatureLocElement> getLocElements()
-  {
-    return locElements;
-  }
-
-  /**
-   * @param locElements
-   *          the locElements to set
-   */
-  public void setLocElements(Vector<EmblFeatureLocElement> locElements)
-  {
-    this.locElements = locElements;
-  }
-
-  /**
-   * Return all location elements as start-end pairs (without accessions) TODO:
-   * pass back complement and 'less than or more than' range information Note:
-   * do not use this since it throws away any accessionIds associated with each
-   * location!
-   * 
-   * @return int[] { start1, end1, ... }
-   */
-  public int[] getElementRanges()
-  {
-    return getElementRanges(null);
-  }
-
-  /**
-   * Return all location elements concerning given accession as start-end pairs.
-   * If the CDS feature is on the forward strand, then start <= end, if on the
-   * reverse strand then start > end.
-   * 
-   * @param accession
-   *          the accession string for which locations are requested, or null
-   *          for all locations
-   * @return int[] { start1, end1, ... }
-   */
-  int[] getElementRanges(String accession)
-  {
-    int sepos = 0;
-    int[] se = new int[locElements.size() * 2];
-    if ("single".equalsIgnoreCase(locationType)
-            || "join".equalsIgnoreCase(locationType))
-    {
-      for (EmblFeatureLocElement loce : locElements)
-      {
-        if (accession == null || loce.accession != null
-                && accession.equals(loce.accession))
-        {
-          BasePosition bp[] = loce.getBasePositions();
-          if (bp.length == 2)
-          {
-            try
-            {
-              int start = Integer.parseInt(bp[0].getPos());
-              int end = Integer.parseInt(bp[1].getPos());
-              se[sepos++] = start;
-              se[sepos++] = end;
-            } catch (NumberFormatException e)
-            {
-              System.err
-                      .println("format error in EMBL CDS location basePosition: "
-                              + e.getMessage());
-            }
-          }
-          else
-          {
-            System.err
-                    .println("format error in EMBL CDS location, basePosition count = "
-                            + bp.length);
-          }
-        }
-      }
-    }
-    else if (locationType != null)
-    {
-      if (Cache.log != null)
-      {
-        Cache.log
-                .error("EmblFeatureLocations.getElementRanges cannot deal with locationType=='"
-                        + locationType + "'");
-      }
-      else
-      {
-        System.err
-                .println("EmblFeatureLocations.getElementRanges cannot deal with locationType=='"
-                        + locationType + "'");
-      }
-    }
-
-    if (sepos != se.length)
-    {
-      /*
-       * we failed to parse something - trim off null values
-       */
-      se = Arrays.copyOf(se, sepos);
-    }
-
-    /*
-     * If on the complement, reverse the ranges to [end, start, ...end1, start1].
-     * For an example of a joined complement, see (tRNA feature) CAGL0B00165r on
-     * http://www.ebi.ac.uk/ena/data/view/CR380948&display=xml
-     * http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/embl/CR380948/emblxml
-     */
-    if (locationComplement)
-    {
-      ArrayUtils.reverseIntArray(se);
-    }
-    return se;
-  }
-}
index 2a6fa84..92c424b 100644 (file)
@@ -27,12 +27,8 @@ package jalview.datamodel.xdb.embl;
  */
 public class EmblSequence
 {
-  String version;
-
   String sequence;
 
-  String type;
-
   /**
    * @return the sequence
    */
@@ -47,40 +43,7 @@ public class EmblSequence
    */
   public void setSequence(String sequence)
   {
-    this.sequence = sequence;
-  }
-
-  /**
-   * @return the type
-   */
-  public String getType()
-  {
-    return type;
-  }
-
-  /**
-   * @param type
-   *          the type to set
-   */
-  public void setType(String type)
-  {
-    this.type = type;
-  }
-
-  /**
-   * @return the version
-   */
-  public String getVersion()
-  {
-    return version;
-  }
-
-  /**
-   * @param version
-   *          the version to set
-   */
-  public void setVersion(String version)
-  {
-    this.version = version;
+    // remove spaces introduced by unmarshalling of newline characters
+    this.sequence = sequence.replace(" ", "");
   }
 }
index 84b5dcf..4dd1bba 100644 (file)
@@ -11,7 +11,6 @@ import jalview.io.gff.SequenceOntologyI;
 import jalview.schemes.FeatureColourAdapter;
 import jalview.schemes.FeatureSettingsAdapter;
 import jalview.util.MapList;
-import jalview.util.StringUtils;
 
 import java.awt.Color;
 import java.io.UnsupportedEncodingException;
@@ -108,47 +107,84 @@ public class EnsemblGene extends EnsemblSeqProxy
   public AlignmentI getSequenceRecords(String query) throws Exception
   {
     /*
-     * if given a transcript id, look up its gene parent
+     * convert to a non-duplicated list of gene identifiers
      */
-    if (isTranscriptIdentifier(query))
+    List<String> geneIds = getGeneIds(query);
+
+    AlignmentI al = null;
+    for (String geneId : geneIds)
     {
-      query = new EnsemblLookup(getDomain()).getParent(query);
-      if (query == null)
+      /*
+       * fetch the gene sequence(s) with features and xrefs
+       */
+      AlignmentI geneAlignment = super.getSequenceRecords(geneId);
+
+      if (geneAlignment.getHeight() == 1)
       {
-        return null;
+        getTranscripts(geneAlignment, geneId);
+      }
+      if (al == null)
+      {
+        al = geneAlignment;
+      }
+      else
+      {
+        al.append(geneAlignment);
       }
     }
+    return al;
+  }
 
-    /*
-     * if given a gene or other external name, lookup and fetch 
-     * the corresponding gene for all model organisms 
-     */
-    if (!isGeneIdentifier(query))
+  /**
+   * Converts a query, which may contain one or more gene or transcript
+   * identifiers, into a non-redundant list of gene identifiers.
+   * 
+   * @param accessions
+   * @return
+   */
+  List<String> getGeneIds(String accessions)
+  {
+    List<String> geneIds = new ArrayList<String>();
+
+    for (String acc : accessions.split(getAccessionSeparator()))
     {
-      List<String> geneIds = new EnsemblSymbol(getDomain()).getIds(query);
-      if (geneIds.isEmpty())
+      if (isGeneIdentifier(acc))
       {
-        return null;
+        if (!geneIds.contains(acc))
+        {
+          geneIds.add(acc);
+        }
       }
-      String theIds = StringUtils.listToDelimitedString(geneIds,
-              getAccessionSeparator());
-      return getSequenceRecords(theIds);
-    }
 
-    /*
-     * fetch the gene sequence(s) with features and xrefs
-     */
-    AlignmentI al = super.getSequenceRecords(query);
+      /*
+       * if given a transcript id, look up its gene parent
+       */
+      else if (isTranscriptIdentifier(acc))
+      {
+        String geneId = new EnsemblLookup(getDomain()).getParent(acc);
+        if (geneId != null && !geneIds.contains(geneId))
+        {
+          geneIds.add(geneId);
+        }
+      }
 
-    /*
-     * if we retrieved a single gene, get its transcripts as well
-     */
-    if (al.getHeight() == 1)
-    {
-      getTranscripts(al, query);
+      /*
+       * if given a gene or other external name, lookup and fetch 
+       * the corresponding gene for all model organisms 
+       */
+      else
+      {
+        List<String> ids = new EnsemblSymbol(getDomain()).getIds(acc);
+        for (String geneId : ids)
+        {
+          if (!geneIds.contains(geneId))
+          {
+            geneIds.add(geneId);
+          }
+        }
+      }
     }
-
-    return al;
+    return geneIds;
   }
 
   /**
@@ -551,10 +587,4 @@ public class EnsemblGene extends EnsemblSeqProxy
     };
   }
 
-  @Override
-  public int getMaximumQueryCount()
-  {
-    return 1;
-  }
-
 }
diff --git a/src/jalview/ext/ensembl/EnsemblInfo.java b/src/jalview/ext/ensembl/EnsemblInfo.java
new file mode 100644 (file)
index 0000000..950b658
--- /dev/null
@@ -0,0 +1,71 @@
+package jalview.ext.ensembl;
+
+/**
+ * A data class to model the data and rest version of one Ensembl domain,
+ * currently for rest.ensembl.org and rest.ensemblgenomes.org
+ * 
+ * @author gmcarstairs
+ */
+class EnsemblInfo
+{
+  /*
+   * The http domain this object is holding data values for
+   */
+  String domain;
+
+  /*
+   * The latest version Jalview has tested for, e.g. "4.5"; a minor version change should be
+   * ok, a major version change may break stuff 
+   */
+  String expectedRestVersion;
+
+  /*
+   * Major / minor / point version e.g. "4.5.1"
+   * @see http://rest.ensembl.org/info/rest/?content-type=application/json
+   */
+  String restVersion;
+
+  /*
+   * data version
+   * @see http://rest.ensembl.org/info/data/?content-type=application/json
+   */
+  String dataVersion;
+
+  /*
+   * true when http://rest.ensembl.org/info/ping/?content-type=application/json
+   * returns response code 200
+   */
+  boolean restAvailable;
+
+  /*
+   * absolute time when availability was last checked
+   */
+  long lastAvailableCheckTime;
+
+  /*
+   * absolute time when version numbers were last checked
+   */
+  long lastVersionCheckTime;
+
+  // flag set to true if REST major version is not the one expected
+  boolean restMajorVersionMismatch;
+
+  /*
+   * absolute time to wait till if we overloaded the REST service
+   */
+  long retryAfter;
+
+  /**
+   * Constructor given expected REST version number e.g 4.5 or 3.4.3
+   * 
+   * @param restExpected
+   */
+  EnsemblInfo(String theDomain, String restExpected)
+  {
+    domain = theDomain;
+    expectedRestVersion = restExpected;
+    lastAvailableCheckTime = -1;
+    lastVersionCheckTime = -1;
+  }
+
+}
index 441ec7c..e651ddf 100644 (file)
@@ -1,6 +1,7 @@
 package jalview.ext.ensembl;
 
 import jalview.io.FileParse;
+import jalview.util.StringUtils;
 
 import java.io.BufferedReader;
 import java.io.DataOutputStream;
@@ -10,10 +11,16 @@ import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import javax.ws.rs.HttpMethod;
 
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+
 import com.stevesoft.pat.Regex;
 
 /**
@@ -23,14 +30,23 @@ import com.stevesoft.pat.Regex;
  */
 abstract class EnsemblRestClient extends EnsemblSequenceFetcher
 {
-  private final static String ENSEMBL_REST = "http://rest.ensembl.org";
+  /*
+   * update these constants when Jalview has been checked / updated for
+   * changes to Ensembl REST API
+   * @see https://github.com/Ensembl/ensembl-rest/wiki/Change-log
+   */
+  private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "4.4";
 
-  protected final static String ENSEMBL_GENOMES_REST = "http://rest.ensemblgenomes.org";
+  private static final String LATEST_ENSEMBL_REST_VERSION = "4.5";
+
+  private static Map<String, EnsemblInfo> domainData;
 
   // @see https://github.com/Ensembl/ensembl-rest/wiki/Output-formats
   private static final String PING_URL = "http://rest.ensembl.org/info/ping.json";
 
-  private final static long RETEST_INTERVAL = 10000L; // 10 seconds
+  private final static long AVAILABILITY_RETEST_INTERVAL = 10000L; // 10 seconds
+
+  private final static long VERSION_RETEST_INTERVAL = 1000L * 3600; // 1 hr
 
   private static final Regex TRANSCRIPT_REGEX = new Regex(
             "(ENS)([A-Z]{3}|)T[0-9]{11}$");
@@ -38,16 +54,14 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
   private static final Regex GENE_REGEX = new Regex(
             "(ENS)([A-Z]{3}|)G[0-9]{11}$");
 
-  private String domain = ENSEMBL_REST;
-
-  private static boolean ensemblRestAvailable = false;
-
-  private static long lastCheck = -1;
-
-  /*
-   * absolute time to wait till if we overloaded the REST service
-   */
-  private static long retryAfter;
+  static
+  {
+    domainData = new HashMap<String, EnsemblInfo>();
+    domainData.put(ENSEMBL_REST, new EnsemblInfo(ENSEMBL_REST,
+            LATEST_ENSEMBL_REST_VERSION));
+    domainData.put(ENSEMBL_GENOMES_REST, new EnsemblInfo(
+            ENSEMBL_GENOMES_REST, LATEST_ENSEMBLGENOMES_REST_VERSION));
+  }
 
   protected volatile boolean inProgress = false;
 
@@ -66,30 +80,28 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
    */
   public EnsemblRestClient(String d)
   {
-    domain = d;
+    setDomain(d);
   }
 
   /**
-   * Returns the domain name to query e.g. http://rest.ensembl.org or
-   * http://rest.ensemblgenomes.org
+   * Answers true if the query matches the regular expression pattern for an
+   * Ensembl transcript stable identifier
    * 
+   * @param query
    * @return
    */
-  String getDomain()
-  {
-    return domain;
-  }
-
-  void setDomain(String d)
-  {
-    domain = d;
-  }
-
   public boolean isTranscriptIdentifier(String query)
   {
     return query == null ? false : TRANSCRIPT_REGEX.search(query);
   }
 
+  /**
+   * Answers true if the query matches the regular expression pattern for an
+   * Ensembl gene stable identifier
+   * 
+   * @param query
+   * @return
+   */
   public boolean isGeneIdentifier(String query)
   {
     return query == null ? false : GENE_REGEX.search(query);
@@ -208,7 +220,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
      * POST method allows multiple queries in one request; it is supported for
      * sequence queries, but not for overlap
      */
-    boolean multipleIds = ids.size() > 1;// useGetRequest();
+    boolean multipleIds = ids != null && ids.size() > 1;
     connection.setRequestMethod(multipleIds ? HttpMethod.POST
             : HttpMethod.GET);
     connection.setRequestProperty("Content-Type",
@@ -270,13 +282,14 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     // to test:
     // retryDelay = "5";
 
+    EnsemblInfo info = domainData.get(getDomain());
     if (retryDelay != null)
     {
       System.err.println("Ensembl REST service rate limit exceeded, wait "
               + retryDelay + " seconds before retrying");
       try
       {
-        retryAfter = System.currentTimeMillis()
+        info.retryAfter = System.currentTimeMillis()
                 + (1000 * Integer.valueOf(retryDelay));
       } catch (NumberFormatException e)
       {
@@ -286,46 +299,64 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     }
     else
     {
-      retryAfter = 0;
+      info.retryAfter = 0;
       // debug:
       // System.out.println(String.format(
       // "%s Ensembl requests remaining of %s (reset in %ss)",
       // remaining, limit, reset));
     }
   }
+  
   /**
    * Rechecks if Ensembl is responding, unless the last check was successful and
    * the retest interval has not yet elapsed. Returns true if Ensembl is up,
-   * else false.
+   * else false. Also retrieves and saves the current version of Ensembl data
+   * and REST services at intervals.
    * 
    * @return
    */
   protected boolean isEnsemblAvailable()
   {
+    EnsemblInfo info = domainData.get(getDomain());
+
     long now = System.currentTimeMillis();
 
     /*
      * check if we are waiting for 'Retry-After' to expire
      */
-    if (retryAfter > now)
+    if (info.retryAfter > now)
     {
-      System.err.println("Still " + (1 + (retryAfter - now) / 1000)
+      System.err.println("Still " + (1 + (info.retryAfter - now) / 1000)
               + " secs to wait before retrying Ensembl");
       return false;
     }
     else
     {
-      retryAfter = 0;
+      info.retryAfter = 0;
+    }
+
+    /*
+     * recheck if Ensembl is up if it was down, or the recheck period has elapsed
+     */
+    boolean retestAvailability = (now - info.lastAvailableCheckTime) > AVAILABILITY_RETEST_INTERVAL;
+    if (!info.restAvailable || retestAvailability)
+    {
+      info.restAvailable = checkEnsembl();
+      info.lastAvailableCheckTime = now;
     }
 
-    boolean retest = now - lastCheck > RETEST_INTERVAL;
-    if (ensemblRestAvailable && !retest)
+    /*
+     * refetch Ensembl versions if the recheck period has elapsed
+     */
+    boolean refetchVersion = (now - info.lastVersionCheckTime) > VERSION_RETEST_INTERVAL;
+    if (refetchVersion)
     {
-      return true;
+      checkEnsemblRestVersion();
+      checkEnsemblDataVersion();
+      info.lastVersionCheckTime = now;
     }
-    ensemblRestAvailable = checkEnsembl();
-    lastCheck = now;
-    return ensemblRestAvailable;
+
+    return info.restAvailable;
   }
 
   /**
@@ -364,4 +395,104 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     wr.close();
   }
 
+  /**
+   * Fetches and checks Ensembl's REST version number
+   * 
+   * @return
+   */
+  private void checkEnsemblRestVersion()
+  {
+    EnsemblInfo info = domainData.get(getDomain());
+
+    JSONParser jp = new JSONParser();
+    URL url = null;
+    try
+    {
+      url = new URL(getDomain()
+              + "/info/rest?content-type=application/json");
+      BufferedReader br = getHttpResponse(url, null);
+      JSONObject val = (JSONObject) jp.parse(br);
+      String version = val.get("release").toString();
+      String majorVersion = version.substring(0, version.indexOf("."));
+      String expected = info.expectedRestVersion;
+      String expectedMajorVersion = expected.substring(0,
+              expected.indexOf("."));
+      info.restMajorVersionMismatch = false;
+      try
+      {
+        /*
+         * if actual REST major version is ahead of what we expect,
+         * record this in case we want to warn the user
+         */
+        if (Float.valueOf(majorVersion) > Float
+                .valueOf(expectedMajorVersion))
+        {
+          info.restMajorVersionMismatch = true;
+        }
+      } catch (NumberFormatException e)
+      {
+        System.err.println("Error in REST version: " + e.toString());
+      }
+
+      /*
+       * check if REST version is later than what Jalview has tested against,
+       * if so warn; we don't worry if it is earlier (this indicates Jalview has
+       * been tested in advance against the next pending REST version)
+       */
+      boolean laterVersion = StringUtils.compareVersions(version, expected) == 1;
+      if (laterVersion)
+      {
+        System.err.println(String.format(
+                "Expected %s REST version %s but found %s", getDbSource(),
+                expected,
+                version));
+      }
+      info.restVersion = version;
+    } catch (Throwable t)
+    {
+      System.err.println("Error checking Ensembl REST version: "
+              + t.getMessage());
+    }
+  }
+
+  public boolean isRestMajorVersionMismatch()
+  {
+    return domainData.get(getDomain()).restMajorVersionMismatch;
+  }
+
+  /**
+   * Fetches and checks Ensembl's data version number
+   * 
+   * @return
+   */
+  private void checkEnsemblDataVersion()
+  {
+    JSONParser jp = new JSONParser();
+    URL url = null;
+    try
+    {
+      url = new URL(getDomain()
+              + "/info/data?content-type=application/json");
+      BufferedReader br = getHttpResponse(url, null);
+      JSONObject val = (JSONObject) jp.parse(br);
+      JSONArray versions = (JSONArray) val.get("releases");
+      domainData.get(getDomain()).dataVersion = versions.get(0).toString();
+    } catch (Throwable t)
+    {
+      System.err.println("Error checking Ensembl data version: "
+              + t.getMessage());
+    }
+  }
+
+  public String getEnsemblDataVersion()
+  {
+    return domainData.get(getDomain()).dataVersion;
+  }
+
+  @Override
+  public String getDbVersion()
+  {
+    return getEnsemblDataVersion();
+  }
+
 }
index fb81e66..c86469f 100644 (file)
@@ -280,8 +280,8 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
         ds.setSourceDBRef(proteinSeq.getSourceDBRef());
 
         Mapping map = new Mapping(ds, mapList);
-        DBRefEntry dbr = new DBRefEntry(getDbSource(), getDbVersion(),
-                proteinSeq.getName(), map);
+        DBRefEntry dbr = new DBRefEntry(getDbSource(),
+                getEnsemblDataVersion(), proteinSeq.getName(), map);
         querySeq.getDatasetSequence().addDBRef(dbr);
         
         /*
@@ -327,7 +327,8 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
     /*
      * and add a reference to itself
      */
-    DBRefEntry self = new DBRefEntry(getDbSource(), "0", seq.getName());
+    DBRefEntry self = new DBRefEntry(getDbSource(),
+            getEnsemblDataVersion(), seq.getName());
     seq.addDBRef(self);
   }
 
@@ -386,7 +387,8 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
         if (ids.contains(name)
                 || ids.contains(name.replace("ENSP", "ENST")))
         {
-          DBRefUtils.parseToDbRef(sq, DBRefSource.ENSEMBL, "0", name);
+          DBRefUtils.parseToDbRef(sq, getDbSource(),
+                  getEnsemblDataVersion(), name);
         }
       }
       if (alignment == null)
index 9a4952e..dd1739b 100644 (file)
@@ -20,6 +20,10 @@ abstract class EnsemblSequenceFetcher extends DbSourceProxyImpl
   private static final Regex ACCESSION_REGEX = new Regex(
           "(ENS([A-Z]{3}|)[GTEP]{1}[0-9]{11}$)" + "|" + "(CCDS[0-9.]{3,}$)");
 
+  protected static final String ENSEMBL_GENOMES_REST = "http://rest.ensemblgenomes.org";
+
+  protected static final String ENSEMBL_REST = "http://rest.ensembl.org";
+
   /*
    * possible values for the 'feature' parameter of the /overlap REST service
    * @see http://rest.ensembl.org/documentation/info/overlap_id
@@ -31,17 +35,17 @@ abstract class EnsemblSequenceFetcher extends DbSourceProxyImpl
     constrained, regulatory
   }
 
+  private String domain = ENSEMBL_REST;
+
   @Override
   public String getDbSource()
   {
     // NB ensure Uniprot xrefs are canonicalised from "Ensembl" to "ENSEMBL"
-    return DBRefSource.ENSEMBL; // "ENSEMBL"
-  }
-
-  @Override
-  public String getDbVersion()
-  {
-    return "0";
+    if (ENSEMBL_GENOMES_REST.equals(getDomain()))
+    {
+      return DBRefSource.ENSEMBLGENOMES;
+    }
+    return DBRefSource.ENSEMBL;
   }
 
   @Override
@@ -90,4 +94,20 @@ abstract class EnsemblSequenceFetcher extends DbSourceProxyImpl
   {
     return true;
   }
+
+  /**
+   * Returns the domain name to query e.g. http://rest.ensembl.org or
+   * http://rest.ensemblgenomes.org
+   * 
+   * @return
+   */
+  protected String getDomain()
+  {
+    return domain;
+  }
+
+  protected void setDomain(String d)
+  {
+    domain = d;
+  }
 }
index 3f0847b..2133f2b 100644 (file)
@@ -176,6 +176,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     // and shut down jmol
     viewer.evalStringQuiet("zap");
     viewer.setJmolStatusListener(null);
+    viewer.dispose();
     lastCommand = null;
     viewer = null;
     releaseUIResources();
index 85c84ab..5b75206 100644 (file)
@@ -45,13 +45,20 @@ import org.json.simple.parser.ParseException;
  * 
  * @author jimp
  * 
- *         History: v1.0 revised from original due to refactoring of
- *         paradise-ubmc.u-strasbg.fr/webservices/annotate3d to
- *         http://arn-ibmc.in2p3.fr/api/compute/2d?tool=rnaview
+ * @version v1.0 revised from original due to refactoring of
+ *          paradise-ubmc.u-strasbg.fr/webservices/annotate3d to
+ *          http://arn-ibmc.in2p3.fr/api/compute/2d?tool=rnaview <br/>
+ *          See also testing URL from fjossinet:<br/>
+ *          http://charn2-ibmc.u-strasbg.fr:8080/api/compute/2d <br/>
+ *          If in doubt, check against the REST client at:
+ *          https://github.com/fjossinet/RNA-Science
+ *          -Toolbox/blob/master/pyrna/restclient.py
  */
 public class Annotate3D
 {
-  private static String twoDtoolsURL = "http://arn-ibmc.in2p3.fr/api/compute/2d";
+  // also test with
+  // "http://charn2-ibmc.u-strasbg.fr:8080/api/compute/2d";
+  private static String twoDtoolsURL = "http://arn-ibmc.in2p3.fr/api/compute/2d?tool=rnaview";
 
   private static ContentHandler createContentHandler()
   {
index 1ce0d2b..944ef52 100644 (file)
@@ -101,17 +101,13 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
 
   private String lastCommand;
 
-  private boolean loadedInline;
-
-  /**
+  /*
    * current set of model filenames loaded
    */
   String[] modelFileNames = null;
 
   String lastHighlightCommand;
 
-  private List<String> lastReply;
-
   /*
    * incremented every time a load notification is successfully handled -
    * lightweight mechanism for other threads to detect when they can start
@@ -617,7 +613,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     if (lastCommand == null || !lastCommand.equals(command))
     {
       // trim command or it may never find a match in the replyLog!!
-      lastReply = viewer.sendChimeraCommand(command.trim(), logResponse);
+      List<String> lastReply = viewer.sendChimeraCommand(command.trim(),
+              logResponse);
       if (logResponse && debug)
       {
         log("Response from command ('" + command + "') was:\n" + lastReply);
@@ -715,17 +712,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   // End StructureListener
   // //////////////////////////
 
-  public Color getColour(int atomIndex, int pdbResNum, String chain,
-          String pdbfile)
-  {
-    if (getModelNum(pdbfile) < 0)
-    {
-      return null;
-    }
-    log("get model / residue colour attribute unimplemented");
-    return null;
-  }
-
   /**
    * returns the current featureRenderer that should be used to colour the
    * structures
@@ -795,15 +781,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   }
 
   /**
-   * map from string to applet
-   */
-  public Map getRegistryInfo()
-  {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  /**
    * returns the current sequenceRenderer that should be used to colour the
    * structures
    * 
@@ -815,20 +792,18 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
           AlignmentViewPanel alignment);
 
   /**
-   * Construct and send a command to highlight zero, one or more atoms.
-   * 
-   * <pre>
-   * Done by generating a command like (to 'highlight' positions 44 and 46)
-   *   show #0:44,46.C
-   * </pre>
+   * Construct and send a command to highlight zero, one or more atoms. We do
+   * this by sending an "rlabel" command to show the residue label at that
+   * position.
    */
   @Override
   public void highlightAtoms(List<AtomSpec> atoms)
   {
-    if (atoms == null)
+    if (atoms == null || atoms.size() == 0)
     {
       return;
     }
+
     StringBuilder cmd = new StringBuilder(128);
     boolean first = true;
     boolean found = false;
@@ -843,7 +818,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
       {
         if (first)
         {
-          cmd.append("show #").append(cms.get(0).getModelNumber())
+          cmd.append("rlabel #").append(cms.get(0).getModelNumber())
                   .append(":");
         }
         else
@@ -851,7 +826,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
           cmd.append(",");
         }
         first = false;
-        cmd.append(cms.get(0).getModelNumber()).append(":");
         cmd.append(pdbResNum);
         if (!chain.equals(" "))
         {
@@ -863,19 +837,24 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     String command = cmd.toString();
 
     /*
-     * Avoid repeated commands for the same residue
+     * avoid repeated commands for the same residue
      */
     if (command.equals(lastHighlightCommand))
     {
       return;
     }
 
-    viewerCommandHistory(false);
+    /*
+     * unshow the label for the previous residue
+     */
+    if (lastHighlightCommand != null)
+    {
+      viewer.sendChimeraCommand("~" + lastHighlightCommand, false);
+    }
     if (found)
     {
-      viewer.sendChimeraCommand(command.toString(), false);
+      viewer.sendChimeraCommand(command, false);
     }
-    viewerCommandHistory(true);
     this.lastHighlightCommand = command;
   }
 
index ea30d01..80990b4 100644 (file)
@@ -44,6 +44,13 @@ public interface FTSDataColumnI
   public String getCode();
 
   /**
+   * Returns the alternative code value for the data column
+   * 
+   * @return the data column's code
+   */
+  public String getAltCode();
+
+  /**
    * Returns the minimum width of the data column
    * 
    * @return the data column's minimum width
@@ -86,18 +93,18 @@ public interface FTSDataColumnI
   public boolean isVisibleByDefault();
 
   /**
-   * Returns the data column's data type class
+   * Returns the data column's FTS data column group
    * 
-   * @return the Class for the data column's data type
+   * @return the FTSDataColumnGroupI for the column
    */
-  public Class getDataColumnClass();
+  public FTSDataColumnGroupI getGroup();
 
   /**
-   * Returns the data colum's FTS data column group
+   * Returns the data columns data type POJO
    * 
-   * @return the FTSDataColumnGroupI for the column
+   * @return the DataTypeI for the column
    */
-  public FTSDataColumnGroupI getGroup();
+  public DataTypeI getDataType();
 
   /**
    * This interface provides a model for the dynamic data column group
@@ -126,4 +133,29 @@ public interface FTSDataColumnI
      */
     public int getSortOrder();
   }
+
+  public interface DataTypeI
+  {
+    /**
+     * Returns the data column's data type class
+     * 
+     * @return the Class for the data column's data type
+     */
+    public Class getDataTypeClass();
+
+    /**
+     * Checks if the numeric data column's data will be formated
+     * 
+     * @return true means the numeric data column shall be formatted
+     */
+    public boolean isFormtted();
+
+    /**
+     * Returns the number of significant figure to be used for the numeric value
+     * formatting
+     * 
+     * @return the number of significant figures
+     */
+    public int getSignificantFigures();
+  }
 }
index 2266ca0..3701c76 100644 (file)
@@ -115,7 +115,7 @@ public interface FTSRestClientI
    * 
    * @return list of columns to display by default
    */
-  public Collection<FTSDataColumnI> getAllDefaulDisplayedDataColumns();
+  public Collection<FTSDataColumnI> getAllDefaultDisplayedFTSDataColumns();
 
   /**
    * Return list of FTSDataColumnI objects that can be used to perform a search
index 46121fc..ce63576 100644 (file)
@@ -33,8 +33,12 @@ public interface GFTSPanelI
 
   /**
    * Action performed when a text is entered in the search field.
+   * 
+   * @param isFreshSearch
+   *          if true a fresh search is executed else a pagination search is
+   *          executed
    */
-  public void searchAction();
+  public void searchAction(boolean isFreshSearch);
 
   /**
    * Action performed when search results are selected and the 'ok' button is
@@ -92,4 +96,35 @@ public interface GFTSPanelI
    * @param isSearchInProgress
    */
   public void setSearchInProgress(Boolean isSearchInProgress);
+
+  /**
+   * Action performed when previous page (<<) button is pressed pressed.
+   */
+  public void prevPageAction();
+
+  /**
+   * Action performed when next page (>>) button is pressed pressed.
+   */
+  public void nextPageAction();
+
+  /**
+   * Checks if the current service's search result is paginate-able
+   * 
+   * @return true means the service provides paginated results
+   */
+  public boolean isPaginationEnabled();
+
+  /**
+   * Updates the 'enabled' state for the previous page button
+   * 
+   * @param isEnabled
+   */
+  public void setPrevPageButtonEnabled(boolean isEnabled);
+
+  /**
+   * Updates the 'enabled' state for the next page button
+   * 
+   * @param isEnabled
+   */
+  public void setNextPageButtonEnabled(boolean isEnabled);
 }
diff --git a/src/jalview/fts/core/DecimalFormatTableCellRenderer.java b/src/jalview/fts/core/DecimalFormatTableCellRenderer.java
new file mode 100644 (file)
index 0000000..3642721
--- /dev/null
@@ -0,0 +1,60 @@
+package jalview.fts.core;
+
+import java.awt.Component;
+import java.text.DecimalFormat;
+
+import javax.swing.JLabel;
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableCellRenderer;
+
+/**
+ * The class to handle the formatting of the double values for JTable cells.
+ */
+public class DecimalFormatTableCellRenderer extends
+        DefaultTableCellRenderer
+{
+  private DecimalFormat formatter;
+
+  public DecimalFormatTableCellRenderer(boolean isFormated,
+          int significantFigures)
+  {
+    String integerFormater = isFormated ? "###,##0" : "0";
+    String fractionFormater = isFormated ? "###,##0." : "0.";
+    if (significantFigures > 0)
+    {
+      StringBuilder significantFigureBuilder = new StringBuilder();
+      for (int x = 1; x <= significantFigures; ++x)
+      {
+        significantFigureBuilder.append("0");
+      }
+      formatter = new DecimalFormat(fractionFormater
+              + significantFigureBuilder.toString());
+    }
+    else
+    {
+      formatter = new DecimalFormat(integerFormater);
+    }
+    super.setHorizontalAlignment(JLabel.RIGHT);
+  }
+
+  public DecimalFormatTableCellRenderer()
+  {
+    super.setHorizontalAlignment(JLabel.RIGHT);
+  }
+
+  @Override
+  public Component getTableCellRendererComponent(JTable table,
+          Object value, boolean isSelected, boolean hasFocus, int row,
+          int column)
+  {
+    if (value == null)
+    {
+      return null;
+    }
+
+    value = formatter.format(value);
+
+    return super.getTableCellRendererComponent(table, value, isSelected,
+            hasFocus, row, column);
+  }
+}
\ No newline at end of file
index cddcc8e..eb7455e 100644 (file)
@@ -23,6 +23,7 @@ package jalview.fts.core;
 import jalview.fts.api.FTSDataColumnI;
 import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
 import jalview.fts.api.FTSRestClientI;
+import jalview.fts.service.pdb.PDBFTSRestClient;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -67,11 +68,12 @@ public class FTSDataColumnPreferences extends JScrollPane
           FTSRestClientI ftsRestClient)
   {
     this.ftsRestClient = ftsRestClient;
-    Collection<FTSDataColumnI> defaultCols = ftsRestClient
-            .getAllDefaulDisplayedDataColumns();
-
-    structSummaryColumns.addAll(defaultCols);
-
+    if (source.equals(PreferenceSource.STRUCTURE_CHOOSER)
+            || source.equals(PreferenceSource.PREFERENCES))
+    {
+    structSummaryColumns = ((PDBFTSRestClient) ftsRestClient)
+              .getAllDefaultDisplayedStructureDataColumns();
+    }
     allFTSDataColumns.addAll(ftsRestClient.getAllFTSDataColumns());
 
     tbl_FTSDataColumnPrefs.setAutoCreateRowSorter(true);
@@ -109,7 +111,7 @@ public class FTSDataColumnPreferences extends JScrollPane
       {
       case SEARCH_SUMMARY:
         data[x++] = new Object[] {
-            ftsRestClient.getAllDefaulDisplayedDataColumns()
+            ftsRestClient.getAllDefaultDisplayedFTSDataColumns()
                     .contains(field),
             field.getName(), field.getGroup() };
         break;
@@ -119,7 +121,7 @@ public class FTSDataColumnPreferences extends JScrollPane
         break;
       case PREFERENCES:
         data[x++] = new Object[] { field.getName(),
-            ftsRestClient.getAllDefaulDisplayedDataColumns()
+            ftsRestClient.getAllDefaultDisplayedFTSDataColumns()
                     .contains(field),
             structSummaryColumns.contains(field) };
         break;
@@ -300,7 +302,7 @@ public class FTSDataColumnPreferences extends JScrollPane
       if (currentSource == PreferenceSource.SEARCH_SUMMARY)
       {
         updatePrefs(ftsRestClient
-                .getAllDefaulDisplayedDataColumns(), ftsDataColumn,
+                .getAllDefaultDisplayedFTSDataColumns(), ftsDataColumn,
                 selected);
       }
       else if (currentSource == PreferenceSource.STRUCTURE_CHOOSER)
@@ -312,7 +314,7 @@ public class FTSDataColumnPreferences extends JScrollPane
         if (col == 1)
         {
           updatePrefs(ftsRestClient
-                  .getAllDefaulDisplayedDataColumns(), ftsDataColumn,
+                  .getAllDefaultDisplayedFTSDataColumns(), ftsDataColumn,
                   selected);
         }
         else if (col == 2)
index f611d5b..00a081b 100644 (file)
@@ -3,10 +3,12 @@ package jalview.fts.core;
 import jalview.fts.api.FTSDataColumnI;
 import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
 import jalview.fts.api.FTSRestClientI;
+import jalview.util.MessageManager;
 
 import java.io.BufferedReader;
-import java.io.FileReader;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Objects;
@@ -43,7 +45,10 @@ public abstract class FTSRestClient implements FTSRestClientI
   public void parseDataColumnsConfigFile()
   {
     String fileName = getColumnDataConfigFileName();
-    try (BufferedReader br = new BufferedReader(new FileReader(fileName)))
+    
+    InputStream in = getClass().getResourceAsStream(fileName); 
+    
+    try (BufferedReader br = new BufferedReader(new InputStreamReader(in)))
     {
       String line;
       while ((line = br.readLine()) != null)
@@ -127,25 +132,73 @@ public abstract class FTSRestClient implements FTSRestClientI
               @Override
               public String getCode()
               {
-                return lineData[1];
+                return lineData[1].split("\\|")[0];
+              }
+
+              @Override
+              public String getAltCode()
+              {
+                return lineData[1].split("\\|").length > 1 ? lineData[1]
+                        .split("\\|")[1] : getCode();
               }
 
               @Override
-              public Class<?> getDataColumnClass()
+              public DataTypeI getDataType()
               {
-                String classString = lineData[2];
-                classString = classString.toUpperCase();
-                switch (classString)
+                final String[] dataTypeString = lineData[2].split("\\|");
+                final String classString = dataTypeString[0].toUpperCase();
+
+                return new DataTypeI()
                 {
-                case "INT":
-                case "INTEGER":
-                  return Integer.class;
-                case "DOUBLE":
-                  return Double.class;
-                case "STRING":
-                default:
-                  return String.class;
-                }
+
+                  @Override
+                  public boolean isFormtted()
+                  {
+                    if (dataTypeString.length > 1
+                            && dataTypeString[1] != null)
+                    {
+                      switch (dataTypeString[1].toUpperCase())
+                      {
+                      case "T":
+                      case "TRUE":
+                        return true;
+                      case "F":
+                      case "False":
+                      default:
+                        return false;
+                      }
+                    }
+                    return false;
+                  }
+
+                  @Override
+                  public int getSignificantFigures()
+                  {
+                    if (dataTypeString.length > 2
+                            && dataTypeString[2] != null)
+                    {
+                      return Integer.valueOf(dataTypeString[2]);
+                    }
+                    return 0;
+                  }
+
+                  @Override
+                  public Class getDataTypeClass()
+                  {
+                    switch (classString)
+                    {
+                    case "INT":
+                    case "INTEGER":
+                      return Integer.class;
+                    case "DOUBLE":
+                      return Double.class;
+                    case "STRING":
+                    default:
+                      return String.class;
+                    }
+                  }
+                };
+
               }
 
               @Override
@@ -216,6 +269,7 @@ public abstract class FTSRestClient implements FTSRestClientI
                         && this.getGroup().equals(that.getGroup());
               }
 
+
             };
             dataColumns.add(dataCol);
 
@@ -291,31 +345,6 @@ public abstract class FTSRestClient implements FTSRestClientI
     return result;
   }
 
-  /**
-   * Takes a collection of FTSDataColumnI and converts its 'code' values into a
-   * tab delimited string.
-   * 
-   * @param dataColumnFields
-   *          the collection of FTSDataColumnI to process
-   * @return the generated comma delimited string from the supplied
-   *         FTSDataColumnI collection
-   */
-  public String getDataColumnsFieldsAsTabDelimitedString(
-          Collection<FTSDataColumnI> dataColumnFields)
-  {
-    String result = "";
-    if (dataColumnFields != null && !dataColumnFields.isEmpty())
-    {
-      StringBuilder returnedFields = new StringBuilder();
-      for (FTSDataColumnI field : dataColumnFields)
-      {
-        returnedFields.append("\t").append(field.getName());
-      }
-      returnedFields.deleteCharAt(0);
-      result = returnedFields.toString();
-    }
-    return result;
-  }
 
   @Override
   public Collection<FTSDataColumnI> getAllFTSDataColumns()
@@ -338,7 +367,7 @@ public abstract class FTSRestClient implements FTSRestClientI
   }
 
   @Override
-  public Collection<FTSDataColumnI> getAllDefaulDisplayedDataColumns()
+  public Collection<FTSDataColumnI> getAllDefaultDisplayedFTSDataColumns()
   {
     if (defaulDisplayedDataColumns == null
             || defaulDisplayedDataColumns.isEmpty())
@@ -397,6 +426,42 @@ public abstract class FTSRestClient implements FTSRestClientI
     throw new Exception("Couldn't find data column group with id : " + id);
   }
 
+  public String getMessageByHTTPStatusCode(int code, String service)
+  {
+    String message = "";
+    switch (code)
+    {
+    case 400:
+      message = MessageManager
+              .getString("exception.bad_request");
+      break;
+      
+    case 410:
+      message = MessageManager.formatMessage(
+              "exception.fts_rest_service_no_longer_available", service);
+      break;
+    case 403:
+    case 404:
+      message = MessageManager.getString("exception.resource_not_be_found");
+      break;
+    case 408:
+    case 409:
+    case 500:
+    case 501:
+    case 502:
+    case 504:
+    case 505:
+      message = MessageManager.getString("exception.fts_server_error");
+      break;
+    case 503:
+      message = MessageManager.getString("exception.service_not_available");
+      break;
+    default:
+      break;
+    }
+    return message;
+  }
+
   protected String getResourceFile(String fileName)
   {
     String result = "";
@@ -414,6 +479,10 @@ public abstract class FTSRestClient implements FTSRestClientI
   @Override
   public int getDefaultResponsePageSize()
   {
+    if (dataColumns == null || dataColumns.isEmpty())
+    {
+      parseDataColumnsConfigFile();
+    }
     return defaultResponsePageSize;
   }
 
index 68068d7..164b102 100644 (file)
@@ -56,6 +56,8 @@ public class FTSRestRequest
 
   private int responseSize;
 
+  private int offSet;
+
   private boolean isSortAscending;
 
   private Collection<FTSDataColumnI> wantedFields;
@@ -176,4 +178,14 @@ public class FTSRestRequest
   {
     this.facetPivotMinCount = facetPivotMinCount;
   }
+
+  public int getOffSet()
+  {
+    return offSet;
+  }
+
+  public void setOffSet(int offSet)
+  {
+    this.offSet = offSet;
+  }
 }
index c56b8c8..8078d43 100644 (file)
@@ -107,7 +107,8 @@ public class FTSRestResponse
         {
           return String.class;
         }
-        return cols[columnIndex - colOffset].getDataColumnClass();
+        return cols[columnIndex - colOffset].getDataType()
+                .getDataTypeClass();
       }
 
     };
@@ -135,14 +136,6 @@ public class FTSRestResponse
   public static void configureTableColumn(JTable tbl_summary,
           Collection<FTSDataColumnI> wantedFields)
   {
-    try
-    {
-      // wait for table model initialisation to complete
-      Thread.sleep(1200);
-    } catch (InterruptedException e1)
-    {
-      e1.printStackTrace();
-    }
     for (FTSDataColumnI wantedField : wantedFields)
     {
       try
@@ -157,6 +150,20 @@ public class FTSRestResponse
       {
         e.printStackTrace();
       }
+      if (wantedField.getDataType().getDataTypeClass() == Double.class)
+      {
+        DecimalFormatTableCellRenderer dfr = new DecimalFormatTableCellRenderer(
+                wantedField.getDataType().isFormtted(),
+                wantedField.getDataType().getSignificantFigures());
+        tbl_summary.getColumn(wantedField.getName()).setCellRenderer(dfr);
+      }
+      else if (wantedField.getDataType().getDataTypeClass() == Integer.class)
+      {
+        DecimalFormatTableCellRenderer dfr = new DecimalFormatTableCellRenderer(
+                wantedField.getDataType().isFormtted(),
+                wantedField.getDataType().getSignificantFigures());
+        tbl_summary.getColumn(wantedField.getName()).setCellRenderer(dfr);
+      }
     }
   }
 
index cae271d..b288aa5 100644 (file)
@@ -41,11 +41,13 @@ import java.awt.event.KeyAdapter;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
+import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashSet;
 import java.util.List;
 
 import javax.swing.ImageIcon;
@@ -65,6 +67,7 @@ import javax.swing.event.ChangeListener;
 import javax.swing.event.DocumentEvent;
 import javax.swing.event.DocumentListener;
 import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableColumn;
 
 /**
  * This class provides the swing GUI layout for FTS Panel and implements most of
@@ -90,14 +93,107 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
 
   protected JButton btn_cancel = new JButton();
 
-  protected JTextField txt_search = new JTextField(20);
+  protected JTextField txt_search = new JTextField(30);
 
   protected SequenceFetcher seqFetcher;
 
   protected Collection<FTSDataColumnI> wantedFields;
 
+  private String lastSearchTerm = "";
+
+  protected JButton btn_next_page = new JButton();
+
+  protected JButton btn_prev_page = new JButton();
+
+  protected StringBuilder errorWarning = new StringBuilder();
+
+  protected ImageIcon warningImage = new ImageIcon(getClass().getResource(
+          "/images/warning.gif"));
+
+  protected ImageIcon loadingImage = new ImageIcon(getClass().getResource(
+          "/images/loading.gif"));
+
+  protected ImageIcon balnkPlaceholderImage = new ImageIcon(getClass()
+          .getResource("/images/blank_16x16_placeholder.png"));
+
+  protected JLabel lbl_warning = new JLabel(warningImage);
+
+  protected JLabel lbl_loading = new JLabel(loadingImage);
+
+  protected JLabel lbl_blank = new JLabel(balnkPlaceholderImage);
+
+  private JTabbedPane tabbedPane = new JTabbedPane();
+
+  private JPanel pnl_actions = new JPanel();
+
+  private JPanel pnl_results = new JPanel(new CardLayout());
+
+  private JPanel pnl_inputs = new JPanel();
+
+  private BorderLayout mainLayout = new BorderLayout();
+
+  protected Object[] previousWantedFields;
+
+  protected int resultSetCount;
+
+  protected int totalResultSetCount;
+
+  protected int offSet;
+
+  protected int pageLimit;
+
+  protected HashSet<String> paginatorCart = new HashSet<String>();
+
+  protected static final DecimalFormat totalNumberformatter = new DecimalFormat(
+          "###,###");
+
   private JTable tbl_summary = new JTable()
   {
+    private boolean inLayout;
+
+    @Override
+    public boolean getScrollableTracksViewportWidth()
+    {
+      return hasExcessWidth();
+
+    }
+
+    @Override
+    public void doLayout()
+    {
+      if (hasExcessWidth())
+      {
+        autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
+      }
+      inLayout = true;
+      super.doLayout();
+      inLayout = false;
+      autoResizeMode = AUTO_RESIZE_OFF;
+    }
+
+    protected boolean hasExcessWidth()
+    {
+      return getPreferredSize().width < getParent().getWidth();
+    }
+
+    @Override
+    public void columnMarginChanged(ChangeEvent e)
+    {
+      if (isEditing())
+      {
+        removeEditor();
+      }
+      TableColumn resizingColumn = getTableHeader().getResizingColumn();
+      // Need to do this here, before the parent's
+      // layout manager calls getPreferredSize().
+      if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF
+              && !inLayout)
+      {
+        resizingColumn.setPreferredWidth(resizingColumn.getWidth());
+      }
+      resizeAndRepaint();
+    }
+
     @Override
     public String getToolTipText(MouseEvent evt)
     {
@@ -126,33 +222,8 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
       return toolTipText;
     }
   };
-
-  protected StringBuilder errorWarning = new StringBuilder();
-
   protected JScrollPane scrl_searchResult = new JScrollPane(tbl_summary);
 
-  protected ImageIcon warningImage = new ImageIcon(getClass().getResource(
-          "/images/warning.gif"));
-
-  protected ImageIcon loadingImage = new ImageIcon(getClass().getResource(
-          "/images/loading.gif"));
-
-  protected JLabel lbl_warning = new JLabel(warningImage);
-
-  protected JLabel lbl_loading = new JLabel(loadingImage);
-
-  private JTabbedPane tabbedPane = new JTabbedPane();
-
-  private JPanel pnl_actions = new JPanel();
-
-  private JPanel pnl_results = new JPanel(new CardLayout());
-
-  private JPanel pnl_inputs = new JPanel();
-
-  private BorderLayout mainLayout = new BorderLayout();
-
-  protected Object[] previousWantedFields;
-
   public GFTSPanel()
   {
     try
@@ -177,8 +248,9 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     lbl_warning.setFont(new java.awt.Font("Verdana", 0, 12));
     lbl_loading.setVisible(false);
     lbl_loading.setFont(new java.awt.Font("Verdana", 0, 12));
+    lbl_blank.setVisible(true);
+    lbl_blank.setFont(new java.awt.Font("Verdana", 0, 12));
 
-    tbl_summary.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
     tbl_summary.setAutoCreateRowSorter(true);
     tbl_summary.getTableHeader().setReorderingAllowed(false);
     tbl_summary.addMouseListener(new MouseAdapter()
@@ -274,6 +346,66 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
         }
       }
     });
+    btn_next_page.setEnabled(false);
+    btn_next_page.setToolTipText(MessageManager
+            .getString("label.next_page_tooltip"));
+    btn_next_page.setFont(new java.awt.Font("Verdana", 0, 12));
+    btn_next_page.setText(MessageManager.getString("action.next_page"));
+    btn_next_page.addActionListener(new java.awt.event.ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        nextPageAction();
+      }
+    });
+    btn_next_page.addKeyListener(new KeyAdapter()
+    {
+      @Override
+      public void keyPressed(KeyEvent evt)
+      {
+        if (evt.getKeyCode() == KeyEvent.VK_ENTER)
+        {
+          nextPageAction();
+        }
+      }
+    });
+
+    btn_prev_page.setEnabled(false);
+    btn_prev_page.setToolTipText(MessageManager
+            .getString("label.prev_page_tooltip"));
+    btn_prev_page.setFont(new java.awt.Font("Verdana", 0, 12));
+    btn_prev_page.setText(MessageManager.getString("action.prev_page"));
+    btn_prev_page.addActionListener(new java.awt.event.ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        prevPageAction();
+      }
+    });
+    btn_prev_page.addKeyListener(new KeyAdapter()
+    {
+      @Override
+      public void keyPressed(KeyEvent evt)
+      {
+        if (evt.getKeyCode() == KeyEvent.VK_ENTER)
+        {
+          prevPageAction();
+        }
+      }
+    });
+
+    if (isPaginationEnabled())
+    {
+      btn_prev_page.setVisible(true);
+      btn_next_page.setVisible(true);
+    }
+    else
+    {
+      btn_prev_page.setVisible(false);
+      btn_next_page.setVisible(false);
+    }
 
     btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12));
     btn_cancel.setText(MessageManager.getString("action.cancel"));
@@ -296,10 +428,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
         }
       }
     });
-
-    scrl_searchResult.setPreferredSize(new Dimension(500, 300));
-    scrl_searchResult
-            .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+    scrl_searchResult.setPreferredSize(new Dimension(800, 400));
 
     cmb_searchTarget.setFont(new java.awt.Font("Verdana", 0, 12));
     cmb_searchTarget.addActionListener(new ActionListener()
@@ -328,7 +457,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
         }
         txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
                 tooltipText));
-        searchAction();
+        searchAction(true);
       }
     });
 
@@ -348,7 +477,9 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
           {
             return;
           }
-          if ("pdb id".equalsIgnoreCase(getCmbSearchTarget()
+          String primaryKeyName = getFTSRestClient().getPrimaryKeyColumn()
+                  .getName();
+          if (primaryKeyName.equalsIgnoreCase(getCmbSearchTarget()
                   .getSelectedItem().toString()))
           {
             transferToSequenceFetcher(txt_search.getText());
@@ -358,13 +489,18 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     });
 
     final DeferredTextInputListener listener = new DeferredTextInputListener(
-            500,
+            1500,
             new ActionListener()
             {
               @Override
               public void actionPerformed(ActionEvent e)
               {
-                searchAction();
+                if (!getTypedText().equalsIgnoreCase(lastSearchTerm))
+                {
+                  searchAction(true);
+                  paginatorCart.clear();
+                  lastSearchTerm = getTypedText();
+                }
               }
             }, false);
     txt_search.getDocument().addDocumentListener(listener);
@@ -379,7 +515,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
       @Override
       public void focusLost(FocusEvent e)
       {
-        listener.stop();
+//        listener.stop();
       }
     });
 
@@ -407,17 +543,25 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
           btn_back.setEnabled(false);
           btn_cancel.setEnabled(false);
           btn_ok.setEnabled(false);
+          btn_next_page.setEnabled(false);
+          btn_prev_page.setEnabled(false);
+          txt_search.setEnabled(false);
+          cmb_searchTarget.setEnabled(false);
           previousWantedFields = getFTSRestClient()
-                  .getAllDefaulDisplayedDataColumns()
+                  .getAllDefaultDisplayedFTSDataColumns()
                   .toArray(new Object[0]);
         }
         if (sourceTabbedPane.getTitleAt(index).equals(searchTabTitle))
         {
           btn_back.setEnabled(true);
           btn_cancel.setEnabled(true);
+          refreshPaginatorState();
+          txt_search.setEnabled(true);
+          cmb_searchTarget.setEnabled(true);
           if (wantedFieldsUpdated())
           {
-            searchAction();
+            searchAction(true);
+            paginatorCart.clear();
           }
           else
           {
@@ -427,7 +571,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
       }
     };
     tabbedPane.addChangeListener(changeListener);
-    tabbedPane.setPreferredSize(new Dimension(500, 300));
+    tabbedPane.setPreferredSize(new Dimension(800, 400));
     tabbedPane.add(searchTabTitle, scrl_searchResult);
     tabbedPane.add(configureCols, new FTSDataColumnPreferences(
             PreferenceSource.SEARCH_SUMMARY, getFTSRestClient()));
@@ -441,6 +585,9 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     pnl_inputs.add(txt_search);
     pnl_inputs.add(lbl_loading);
     pnl_inputs.add(lbl_warning);
+    pnl_inputs.add(lbl_blank);
+    pnl_inputs.add(btn_prev_page);
+    pnl_inputs.add(btn_next_page);
 
     this.setLayout(mainLayout);
     this.add(pnl_inputs, java.awt.BorderLayout.NORTH);
@@ -449,7 +596,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     mainFrame.setVisible(true);
     mainFrame.setContentPane(this);
     mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
-    Desktop.addInternalFrame(mainFrame, getFTSFrameTitle(), 800, 400);
+    Desktop.addInternalFrame(mainFrame, getFTSFrameTitle(), 900, 500);
   }
 
   public class DeferredTextInputListener implements DocumentListener
@@ -501,7 +648,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     }
 
     return Arrays.equals(getFTSRestClient()
-            .getAllDefaulDisplayedDataColumns()
+            .getAllDefaultDisplayedFTSDataColumns()
             .toArray(new Object[0]), previousWantedFields) ? false
             : true;
 
@@ -509,7 +656,8 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
 
   public void validateSelection()
   {
-    if (tbl_summary.getSelectedRows().length > 0)
+    if (tbl_summary.getSelectedRows().length > 0
+            || !paginatorCart.isEmpty())
     {
       btn_ok.setEnabled(true);
     }
@@ -558,9 +706,11 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
   protected void checkForErrors()
   {
     lbl_warning.setVisible(false);
+    lbl_blank.setVisible(true);
     if (errorWarning.length() > 0)
     {
       lbl_loading.setVisible(false);
+      lbl_blank.setVisible(false);
       lbl_warning.setToolTipText(JvSwingUtils.wrapTooltip(true,
               errorWarning.toString()));
       lbl_warning.setVisible(true);
@@ -642,6 +792,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     lbl_loading.setVisible(false);
     errorWarning.setLength(0);
     lbl_warning.setVisible(false);
+    lbl_blank.setVisible(true);
     btn_ok.setEnabled(false);
     mainFrame.setTitle(getFTSFrameTitle());
     referesh();
@@ -650,6 +801,18 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
   }
 
   @Override
+  public void setPrevPageButtonEnabled(boolean isEnabled)
+  {
+    btn_prev_page.setEnabled(isEnabled);
+  }
+
+  @Override
+  public void setNextPageButtonEnabled(boolean isEnabled)
+  {
+    btn_next_page.setEnabled(isEnabled);
+  }
+
+  @Override
   public void setErrorMessage(String message)
   {
     errorWarning.append(message);
@@ -664,8 +827,115 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
   @Override
   public void setSearchInProgress(Boolean isSearchInProgress)
   {
+    lbl_blank.setVisible(!isSearchInProgress);
     lbl_loading.setVisible(isSearchInProgress);
   }
+
+  @Override
+  public void prevPageAction()
+  {
+    updatePaginatorCart();
+    if (offSet >= pageLimit)
+    {
+      offSet = offSet - pageLimit;
+      searchAction(false);
+    }
+    else
+    {
+      refreshPaginatorState();
+    }
+  }
+
+  @Override
+  public void nextPageAction()
+  {
+    updatePaginatorCart();
+    offSet = offSet + pageLimit;
+    searchAction(false);
+  }
+
+  public void updatePaginatorCart()
+  {
+    int primaryKeyColIndex = 0;
+    JTable resultTable = getResultTable();
+    int totalRows = resultTable.getRowCount();
+    try
+    {
+      primaryKeyColIndex = getFTSRestClient().getPrimaryKeyColumIndex(
+              wantedFields, false);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+
+    for (int row = 0; row < totalRows; row++)
+    {
+      String id = (String) resultTable.getValueAt(row, primaryKeyColIndex);
+      if (paginatorCart.contains(id))
+      {
+        paginatorCart.remove(id);
+      }
+    }
+    int[] selectedRows = resultTable.getSelectedRows();
+    for (int summaryRow : selectedRows)
+    {
+      String idStr = resultTable.getValueAt(summaryRow,
+              primaryKeyColIndex).toString();
+      paginatorCart.add(idStr);
+    }
+    // System.out.println("Paginator shopping cart size : "
+    // + paginatorCart.size());
+  }
+
+  public void updateSummaryTableSelections()
+  {
+    JTable resultTable = getResultTable();
+    if (paginatorCart.isEmpty())
+    {
+      return;
+    }
+    int primaryKeyColIndex = 0;
+    try
+    {
+      primaryKeyColIndex = getFTSRestClient().getPrimaryKeyColumIndex(
+              wantedFields, false);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    // System.out.println(">>>>>> got here : 1");
+    int totalRows = resultTable.getRowCount();
+    // resultTable.clearSelection();
+    for (int row = 0; row < totalRows; row++)
+    {
+      String id = (String) resultTable.getValueAt(row, primaryKeyColIndex);
+      if (paginatorCart.contains(id))
+      {
+        resultTable.addRowSelectionInterval(row, row);
+      }
+    }
+    validateSelection();
+  }
+  public void refreshPaginatorState()
+  {
+    // System.out.println("resultSet count : " + resultSetCount);
+    // System.out.println("offSet : " + offSet);
+    // System.out.println("page limit : " + pageLimit);
+    setPrevPageButtonEnabled(false);
+    setNextPageButtonEnabled(false);
+    if (resultSetCount == 0 && pageLimit == 0)
+    {
+      return;
+    }
+    if (resultSetCount >= pageLimit)
+    {
+      setNextPageButtonEnabled(true);
+    }
+    if (offSet >= pageLimit)
+    {
+      setPrevPageButtonEnabled(true);
+    }
+  }
   public void referesh()
   {
     mainFrame.setTitle(getFTSFrameTitle());
index 826a505..32c171e 100644 (file)
@@ -41,6 +41,7 @@ public class PDBFTSPanel extends GFTSPanel
 
   public PDBFTSPanel(SequenceFetcher seqFetcher)
   {
+    pageLimit = PDBFTSRestClient.getInstance().getDefaultResponsePageSize();
     this.seqFetcher = seqFetcher;
     this.progressIdicator = (seqFetcher == null) ? null : seqFetcher
             .getProgressIndicator();
@@ -48,8 +49,12 @@ public class PDBFTSPanel extends GFTSPanel
 
 
   @Override
-  public void searchAction()
+  public void searchAction(boolean isFreshSearch)
   {
+    if (isFreshSearch)
+    {
+      offSet = 0;
+    }
     new Thread()
     {
       @Override
@@ -66,7 +71,7 @@ public class PDBFTSPanel extends GFTSPanel
           String searchTarget = ((FTSDataColumnI) cmb_searchTarget
                   .getSelectedItem()).getCode();
           wantedFields = PDBFTSRestClient.getInstance()
-                  .getAllDefaulDisplayedDataColumns();
+                  .getAllDefaultDisplayedFTSDataColumns();
           String searchTerm = decodeSearchTerm(txt_search.getText(),
                   searchTarget);
 
@@ -75,6 +80,7 @@ public class PDBFTSPanel extends GFTSPanel
           request.setResponseSize(100);
           request.setFieldToSearchBy("(" + searchTarget + ":");
           request.setSearchTerm(searchTerm + ")");
+          request.setOffSet(offSet);
           request.setWantedFields(wantedFields);
           FTSRestClientI pdbRestCleint = PDBFTSRestClient.getInstance();
           FTSRestResponse resultList;
@@ -100,14 +106,36 @@ public class PDBFTSPanel extends GFTSPanel
           }
 
           long endTime = System.currentTimeMillis();
-          int resultSetCount = resultList.getNumberOfItemsFound();
-          String result = (resultSetCount > 1) ? MessageManager
+          totalResultSetCount = resultList.getNumberOfItemsFound();
+          resultSetCount = resultList.getSearchSummary() == null ? 0
+                  : resultList.getSearchSummary().size();
+          String result = (resultSetCount > 0) ? MessageManager
                   .getString("label.results") : MessageManager
                   .getString("label.result");
-          updateSearchFrameTitle(defaultFTSFrameTitle + " - "
-                  + resultSetCount + " " + result + " ("
-                  + (endTime - startTime) + " milli secs)");
+         
+          if (isPaginationEnabled() && resultSetCount > 0)
+          {
+            updateSearchFrameTitle(defaultFTSFrameTitle + " - " + result
+                    + " "
+                    + totalNumberformatter.format((Number) (offSet + 1))
+                    + " to "
+                    + totalNumberformatter
+                            .format((Number) (offSet + resultSetCount))
+                    + " of "
+                    + totalNumberformatter
+                            .format((Number) totalResultSetCount)
+                    + " " + " (" + (endTime - startTime) + " milli secs)");
+          }
+          else
+          {
+            updateSearchFrameTitle(defaultFTSFrameTitle + " - "
+                    + resultSetCount + " " + result + " ("
+                    + (endTime - startTime) + " milli secs)");
+          }
+          
           setSearchInProgress(false);
+          refreshPaginatorState();
+          updateSummaryTableSelections();
         }
       }
     }.start();
@@ -164,16 +192,20 @@ public class PDBFTSPanel extends GFTSPanel
               false);
     } catch (Exception e)
     {
-      // TODO Auto-generated catch block
       e.printStackTrace();
     }
     int[] selectedRows = getResultTable().getSelectedRows();
+    String searchTerm = txt_search.getText();
     for (int summaryRow : selectedRows)
     {
       String idStr = getResultTable().getValueAt(summaryRow,
               primaryKeyColIndex)
               .toString();
-      String searchTerm = txt_search.getText();
+      selectedIdsSet.add(getPDBIdwithSpecifiedChain(idStr, searchTerm));
+    }
+
+    for (String idStr : paginatorCart)
+    {
       selectedIdsSet.add(getPDBIdwithSpecifiedChain(idStr, searchTerm));
     }
 
@@ -217,8 +249,6 @@ public class PDBFTSPanel extends GFTSPanel
     return pdbIdWithChainCode;
   }
 
-
-
   @Override
   public FTSRestClientI getFTSRestClient()
   {
@@ -231,5 +261,10 @@ public class PDBFTSPanel extends GFTSPanel
     return ftsFrameTitle;
   }
 
+  @Override
+  public boolean isPaginationEnabled()
+  {
+    return true;
+  }
 
 }
index 8e63463..219d6d6 100644 (file)
@@ -86,6 +86,7 @@ public class PDBFTSRestClient extends FTSRestClient
               .getWantedFields());
       int responseSize = (pdbRestRequest.getResponseSize() == 0) ? getDefaultResponsePageSize()
               : pdbRestRequest.getResponseSize();
+      int offSet = pdbRestRequest.getOffSet();
       String sortParam = null;
       if (pdbRestRequest.getFieldToSortBy() == null
               || pdbRestRequest.getFieldToSortBy().trim().isEmpty())
@@ -128,6 +129,7 @@ public class PDBFTSRestClient extends FTSRestClient
                 .queryParam("wt", "json").queryParam("fl", wantedFields)
                 .queryParam("rows", String.valueOf(responseSize))
                 .queryParam("q", query)
+                .queryParam("start", String.valueOf(offSet))
                 .queryParam("sort", sortParam).queryParam("facet", "true")
                 .queryParam("facet.pivot", facetPivot)
                 .queryParam("facet.pivot.mincount", facetPivotMinCount);
@@ -137,6 +139,7 @@ public class PDBFTSRestClient extends FTSRestClient
         webResource = client.resource(PDB_SEARCH_ENDPOINT)
                 .queryParam("wt", "json").queryParam("fl", wantedFields)
                 .queryParam("rows", String.valueOf(responseSize))
+                .queryParam("start", String.valueOf(offSet))
                 .queryParam("q", query)
                 .queryParam("sort", sortParam);
       }
@@ -160,7 +163,7 @@ public class PDBFTSRestClient extends FTSRestClient
         else
         {
           errorMessage = getMessageByHTTPStatusCode(clientResponse
-                  .getStatus());
+.getStatus(), "PDB");
           throw new Exception(errorMessage);
         }
       }
@@ -185,9 +188,8 @@ public class PDBFTSRestClient extends FTSRestClient
       else if (exceptionMsg.contains("UnknownHostException"))
       {
         // The server 'www.ebi.ac.uk' is unreachable
-        throw new Exception(
-                MessageManager
-                        .getString("exception.pdb_server_unreachable"));
+        throw new Exception(MessageManager.formatMessage(
+                "exception.fts_server_unreachable", "PDB Solr"));
       }
       else
       {
@@ -196,35 +198,6 @@ public class PDBFTSRestClient extends FTSRestClient
     }
   }
 
-  public String getMessageByHTTPStatusCode(int code)
-  {
-    String message = "";
-    switch (code)
-    {
-    case 410:
-      message = MessageManager
-              .getString("exception.pdb_rest_service_no_longer_available");
-      break;
-    case 403:
-    case 404:
-      message = MessageManager.getString("exception.resource_not_be_found");
-      break;
-    case 408:
-    case 409:
-    case 500:
-    case 501:
-    case 502:
-    case 503:
-    case 504:
-    case 505:
-      message = MessageManager.getString("exception.pdb_server_error");
-      break;
-
-    default:
-      break;
-    }
-    return message;
-  }
 
   /**
    * Process error response from PDB server if/when one occurs.
@@ -353,11 +326,13 @@ public class PDBFTSRestClient extends FTSRestClient
       {
         try
         {
-          summaryRowData[colCounter++] = (field.getDataColumnClass() == Integer.class) ? Integer
+          summaryRowData[colCounter++] = (field.getDataType()
+                  .getDataTypeClass() == Integer.class) ? Integer
                   .valueOf(fieldData)
-                  : (field.getDataColumnClass() == Double.class) ? Double
+ : (field.getDataType()
+                  .getDataTypeClass() == Double.class) ? Double
                           .valueOf(fieldData)
-                          : fieldData;
+ : sanitiseData(fieldData);
         } catch (Exception e)
         {
           e.printStackTrace();
@@ -407,13 +382,27 @@ public class PDBFTSRestClient extends FTSRestClient
       {
         return Objects.hash(primaryKey1, this.toString());
       }
+
+      @Override
+      public boolean equals(Object that)
+      {
+        return this.toString().equals(that.toString());
+      }
     };
   }
 
+  private static String sanitiseData(String data)
+  {
+    String cleanData = data.replaceAll("\\[\"", "").replaceAll("\\]\"", "")
+            .replaceAll("\\[", "").replaceAll("\\]", "")
+            .replaceAll("\",\"", ", ").replaceAll("\"", "");
+    return cleanData;
+  }
+
   @Override
   public String getColumnDataConfigFileName()
   {
-    return getResourceFile("/fts/pdb_data_columns.conf");
+    return "/fts/pdb_data_columns.txt";
   }
 
 
@@ -425,4 +414,18 @@ public class PDBFTSRestClient extends FTSRestClient
     }
     return instance;
   }
+
+  private Collection<FTSDataColumnI> allDefaultDisplayedStructureDataColumns;
+
+  public Collection<FTSDataColumnI> getAllDefaultDisplayedStructureDataColumns()
+  {
+    if (allDefaultDisplayedStructureDataColumns == null
+            || allDefaultDisplayedStructureDataColumns.isEmpty())
+    {
+      allDefaultDisplayedStructureDataColumns = new ArrayList<FTSDataColumnI>();
+      allDefaultDisplayedStructureDataColumns.addAll(super
+              .getAllDefaultDisplayedFTSDataColumns());
+    }
+    return allDefaultDisplayedStructureDataColumns;
+  }
 }
index f920166..5ee518b 100644 (file)
@@ -27,6 +27,7 @@ import jalview.fts.api.FTSRestClientI;
 import jalview.fts.core.FTSRestClient;
 import jalview.fts.core.FTSRestRequest;
 import jalview.fts.core.FTSRestResponse;
+import jalview.util.MessageManager;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -49,49 +50,109 @@ public class UniProtFTSRestClient extends FTSRestClient
 
   @Override
   public FTSRestResponse executeRequest(FTSRestRequest uniportRestRequest)
+          throws Exception
   {
-    ClientConfig clientConfig = new DefaultClientConfig();
-    Client client = Client.create(clientConfig);
-
-    String wantedFields = getDataColumnsFieldsAsCommaDelimitedString(uniportRestRequest
-            .getWantedFields());
-    int responseSize = (uniportRestRequest.getResponseSize() == 0) ? getDefaultResponsePageSize()
-            : uniportRestRequest.getResponseSize();
-
-    String query = uniportRestRequest.getFieldToSearchBy() + ":"
-            + uniportRestRequest.getSearchTerm();
-    // + (uniportRestRequest.isAllowUnpublishedEntries() ? ""
-    // : " AND status:REL");
-    // System.out.println(">>>>> Query : " + query);
-    // System.out.println(">>>>> Columns : " + wantedFields);
-    WebResource webResource = null;
-    webResource = client.resource(UNIPROT_SEARCH_ENDPOINT)
-            .queryParam("format", "tab")
-            .queryParam("columns", wantedFields)
-            .queryParam("limit", String.valueOf(responseSize))
-            .queryParam("query", query);
-    // Execute the REST request
-    ClientResponse clientResponse = webResource
-            .accept(MediaType.TEXT_PLAIN).get(ClientResponse.class);
-    String uniProtTabDelimittedResponseString = clientResponse
-            .getEntity(String.class);
-    // Make redundant objects eligible for garbage collection to conserve
-    // memory
-    clientResponse = null;
-    client = null;
-    // System.out.println(">>>>> response : "
-    // + uniProtTabDelimittedResponseString);
-    return parseUniprotResponse(uniProtTabDelimittedResponseString,
-            uniportRestRequest);
+    try
+    {
+      ClientConfig clientConfig = new DefaultClientConfig();
+      Client client = Client.create(clientConfig);
+
+      String wantedFields = getDataColumnsFieldsAsCommaDelimitedString(uniportRestRequest
+              .getWantedFields());
+      int responseSize = (uniportRestRequest.getResponseSize() == 0) ? getDefaultResponsePageSize()
+              : uniportRestRequest.getResponseSize();
+
+      int offSet = uniportRestRequest.getOffSet();
+      String query;
+      if (isAdvancedQuery(uniportRestRequest.getSearchTerm()))
+      {
+        query = uniportRestRequest.getSearchTerm();
+      }
+      else
+      {
+        query = uniportRestRequest.getFieldToSearchBy().equalsIgnoreCase(
+                "Search All") ? uniportRestRequest.getSearchTerm()
+                + " or mnemonic:" + uniportRestRequest.getSearchTerm()
+                : uniportRestRequest.getFieldToSearchBy() + ":"
+                        + uniportRestRequest.getSearchTerm();
+      }
+
+      WebResource webResource = null;
+      webResource = client.resource(UNIPROT_SEARCH_ENDPOINT)
+              .queryParam("format", "tab")
+              .queryParam("columns", wantedFields)
+              .queryParam("limit", String.valueOf(responseSize))
+              .queryParam("offset", String.valueOf(offSet))
+              .queryParam("sort", "score").queryParam("query", query);
+      // Execute the REST request
+      ClientResponse clientResponse = webResource.accept(
+              MediaType.TEXT_PLAIN).get(ClientResponse.class);
+      String uniProtTabDelimittedResponseString = clientResponse
+              .getEntity(String.class);
+      // Make redundant objects eligible for garbage collection to conserve
+      // memory
+      // System.out.println(">>>>> response : "
+      // + uniProtTabDelimittedResponseString);
+      if (clientResponse.getStatus() != 200)
+      {
+        String errorMessage = getMessageByHTTPStatusCode(
+                clientResponse.getStatus(), "Uniprot");
+        throw new Exception(errorMessage);
+
+      }
+      int xTotalResults = Integer.valueOf(clientResponse.getHeaders()
+              .get("X-Total-Results").get(0));
+      clientResponse = null;
+      client = null;
+      return parseUniprotResponse(uniProtTabDelimittedResponseString,
+              uniportRestRequest, xTotalResults);
+    } catch (Exception e)
+    {
+      String exceptionMsg = e.getMessage();
+      if (exceptionMsg.contains("SocketException"))
+      {
+        // No internet connection
+        throw new Exception(
+                MessageManager
+                        .getString("exception.unable_to_detect_internet_connection"));
+      }
+      else if (exceptionMsg.contains("UnknownHostException"))
+      {
+        // The server 'http://www.uniprot.org' is unreachable
+        throw new Exception(MessageManager.formatMessage(
+                "exception.fts_server_unreachable", "Uniprot"));
+      }
+      else
+      {
+        throw e;
+      }
+    }
+  }
 
+  public boolean isAdvancedQuery(String query)
+  {
+    if (query.contains(" AND ") || query.contains(" OR ")
+            || query.contains(" NOT ") || query.contains(" ! ")
+            || query.contains(" || ") || query.contains(" && ")
+            || query.contains(":") || query.contains("-"))
+    {
+      return true;
+    }
+    return false;
   }
 
   public FTSRestResponse parseUniprotResponse(
           String uniProtTabDelimittedResponseString,
-          FTSRestRequest uniprotRestRequest)
+          FTSRestRequest uniprotRestRequest, int xTotalResults)
   {
     FTSRestResponse searchResult = new FTSRestResponse();
     List<FTSData> result = null;
+    if (uniProtTabDelimittedResponseString == null
+            || uniProtTabDelimittedResponseString.trim().isEmpty())
+    {
+      searchResult.setNumberOfItemsFound(0);
+      return searchResult;
+    }
     String[] foundDataRow = uniProtTabDelimittedResponseString.split("\n");
     if (foundDataRow != null && foundDataRow.length > 0)
     {
@@ -109,12 +170,45 @@ public class UniProtFTSRestClient extends FTSRestClient
         // System.out.println(dataRow);
         result.add(getFTSData(dataRow, uniprotRestRequest));
       }
-      searchResult.setNumberOfItemsFound(result.size());
+      searchResult.setNumberOfItemsFound(xTotalResults);
       searchResult.setSearchSummary(result);
     }
     return searchResult;
   }
 
+  /**
+   * Takes a collection of FTSDataColumnI and converts its 'code' values into a
+   * tab delimited string.
+   * 
+   * @param dataColumnFields
+   *          the collection of FTSDataColumnI to process
+   * @return the generated comma delimited string from the supplied
+   *         FTSDataColumnI collection
+   */
+  private String getDataColumnsFieldsAsTabDelimitedString(
+          Collection<FTSDataColumnI> dataColumnFields)
+  {
+    String result = "";
+    if (dataColumnFields != null && !dataColumnFields.isEmpty())
+    {
+      StringBuilder returnedFields = new StringBuilder();
+      for (FTSDataColumnI field : dataColumnFields)
+      {
+        if (field.getName().equalsIgnoreCase("Uniprot Id"))
+        {
+          returnedFields.append("\t").append("Entry");
+        }
+        else
+        {
+          returnedFields.append("\t").append(field.getName());
+        }
+      }
+      returnedFields.deleteCharAt(0);
+      result = returnedFields.toString();
+    }
+    return result;
+  }
+
   public static FTSData getFTSData(String tabDelimittedDataStr,
           FTSRestRequest request)
   {
@@ -144,9 +238,11 @@ public class UniProtFTSRestClient extends FTSRestClient
         {
           try
           {
-            summaryRowData[colCounter++] = (field.getDataColumnClass() == Integer.class) ? Integer
-                    .valueOf(fieldData)
-                    : (field.getDataColumnClass() == Double.class) ? Double
+            summaryRowData[colCounter++] = (field.getDataType()
+                    .getDataTypeClass() == Integer.class) ? Integer
+                    .valueOf(fieldData.replace(",", ""))
+ : (field.getDataType()
+                    .getDataTypeClass() == Double.class) ? Double
                             .valueOf(fieldData) : fieldData;
           } catch (Exception e)
           {
@@ -201,6 +297,12 @@ public class UniProtFTSRestClient extends FTSRestClient
       {
         return Objects.hash(primaryKey1, this.toString());
       }
+
+      @Override
+      public boolean equals(Object that)
+      {
+        return this.toString().equals(that.toString());
+      }
     };
   }
 
@@ -217,7 +319,7 @@ public class UniProtFTSRestClient extends FTSRestClient
   @Override
   public String getColumnDataConfigFileName()
   {
-    return getResourceFile("/fts/uniprot_data_columns.conf");
+    return "/fts/uniprot_data_columns.txt";
   }
 
 }
index dcef358..b1aa5f1 100644 (file)
@@ -40,16 +40,24 @@ public class UniprotFTSPanel extends GFTSPanel
 
   private String ftsFrameTitle = defaultFTSFrameTitle;
 
+
+
   public UniprotFTSPanel(SequenceFetcher seqFetcher)
   {
+    pageLimit = UniProtFTSRestClient.getInstance()
+            .getDefaultResponsePageSize();
     this.seqFetcher = seqFetcher;
     this.progressIdicator = (seqFetcher == null) ? null : seqFetcher
             .getProgressIndicator();
   }
 
   @Override
-  public void searchAction()
+  public void searchAction(boolean isFreshSearch)
   {
+    if (isFreshSearch)
+    {
+      offSet = 0;
+    }
     new Thread()
   {
       @Override
@@ -63,15 +71,17 @@ public class UniprotFTSPanel extends GFTSPanel
           long startTime = System.currentTimeMillis();
 
           String searchTarget = ((FTSDataColumnI) cmb_searchTarget
-                  .getSelectedItem()).getCode();
+                  .getSelectedItem()).getAltCode();
 
           wantedFields = UniProtFTSRestClient.getInstance()
-                  .getAllDefaulDisplayedDataColumns();
-          String searchTerm = txt_search.getText();
+                  .getAllDefaultDisplayedFTSDataColumns();
+          String searchTerm = decodeSearchTerm(txt_search.getText(),
+                  searchTarget);
 
           FTSRestRequest request = new FTSRestRequest();
           request.setFieldToSearchBy(searchTarget);
           request.setSearchTerm(searchTerm);
+          request.setOffSet(offSet);
           request.setWantedFields(wantedFields);
           FTSRestClientI uniProtRestCleint = UniProtFTSRestClient
                   .getInstance();
@@ -92,27 +102,81 @@ public class UniprotFTSPanel extends GFTSPanel
           {
             getResultTable().setModel(
                     FTSRestResponse.getTableModel(request,
-                    resultList.getSearchSummary()));
+                            resultList.getSearchSummary()));
             FTSRestResponse.configureTableColumn(getResultTable(),
                     wantedFields);
             getResultTable().setVisible(true);
           }
 
           long endTime = System.currentTimeMillis();
-          int resultSetCount = resultList.getNumberOfItemsFound();
-          String result = (resultSetCount > 1) ? MessageManager
+          totalResultSetCount = resultList.getNumberOfItemsFound();
+          resultSetCount = resultList.getSearchSummary() == null ? 0
+                  : resultList.getSearchSummary().size();
+          String result = (resultSetCount > 0) ? MessageManager
                   .getString("label.results") : MessageManager
                   .getString("label.result");
-          updateSearchFrameTitle(defaultFTSFrameTitle + " - "
-                  + resultSetCount + " " + result + " ("
-                  + (endTime - startTime) + " milli secs)");
+          if (isPaginationEnabled() && resultSetCount > 0)
+          {
+            updateSearchFrameTitle(defaultFTSFrameTitle + " - " + result
+                    + " "
+                    + totalNumberformatter.format((Number) (offSet + 1))
+                    + " to "
+                    + totalNumberformatter
+                            .format((Number) (offSet + resultSetCount))
+                    + " of "
+                    + totalNumberformatter
+                            .format((Number) totalResultSetCount)
+                    + " " + " (" + (endTime - startTime) + " milli secs)");
+          }
+          else
+          {
+            updateSearchFrameTitle(defaultFTSFrameTitle + " - "
+                    + resultSetCount + " " + result + " ("
+                    + (endTime - startTime) + " milli secs)");
+          }
           setSearchInProgress(false);
+          refreshPaginatorState();
+          updateSummaryTableSelections();
         }
       }
     }.start();
 
   }
 
+  public String decodeSearchTerm(String enteredText, String targetField)
+  {
+    int searchTargetLength = targetField.equalsIgnoreCase("Search All") ? 0
+            : targetField.length() + 1;
+    String searchTarget = targetField.equalsIgnoreCase("Search All") ? ""
+            : targetField + ":";
+    String foundSearchTerms = enteredText;
+    StringBuilder foundSearchTermsBuilder = new StringBuilder();
+    if (enteredText.contains(";"))
+    {
+      String[] searchTerms = enteredText.split(";");
+      for (String searchTerm : searchTerms)
+      {
+        foundSearchTermsBuilder.append(searchTarget).append(searchTerm)
+                .append(" OR ");
+      }
+      int endIndex = foundSearchTermsBuilder.lastIndexOf(" OR ");
+      foundSearchTerms = foundSearchTermsBuilder.toString();
+      if (foundSearchTerms.contains(" OR "))
+      {
+        foundSearchTerms = foundSearchTerms.substring(searchTargetLength,
+                endIndex);
+      }
+    }
+    return foundSearchTerms;
+  }
+
+
+  @Override
+  public boolean isPaginationEnabled()
+  {
+    return true;
+  }
+
   @Override
   public void okAction()
   {
@@ -135,7 +199,7 @@ public class UniprotFTSPanel extends GFTSPanel
               primaryKeyColIndex).toString();
       selectedIdsSet.add(idStr);
     }
-
+    selectedIdsSet.addAll(paginatorCart);
     for (String selectedId : selectedIdsSet)
     {
       selectedIds.append(selectedId).append(";");
index 44d1d94..bfbc969 100644 (file)
@@ -74,6 +74,7 @@ import jalview.io.JalviewFileView;
 import jalview.io.JnetAnnotationMaker;
 import jalview.io.NewickFile;
 import jalview.io.TCoffeeScoreFile;
+import jalview.io.gff.SequenceOntologyI;
 import jalview.jbgui.GAlignFrame;
 import jalview.schemes.Blosum62ColourScheme;
 import jalview.schemes.BuriedColourScheme;
@@ -112,7 +113,6 @@ import java.awt.datatransfer.Clipboard;
 import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.StringSelection;
 import java.awt.datatransfer.Transferable;
-import java.awt.dnd.DnDConstants;
 import java.awt.dnd.DropTargetDragEvent;
 import java.awt.dnd.DropTargetDropEvent;
 import java.awt.dnd.DropTargetEvent;
@@ -131,7 +131,6 @@ import java.awt.print.PageFormat;
 import java.awt.print.PrinterJob;
 import java.beans.PropertyChangeEvent;
 import java.io.File;
-import java.lang.reflect.Method;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -474,7 +473,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       @Override
       public void focusGained(FocusEvent e)
       {
-        Desktop.setCurrentAlignFrame(AlignFrame.this);
+        Jalview.setCurrentAlignFrame(AlignFrame.this);
       }
     });
 
@@ -1314,7 +1313,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     if (viewport.hasHiddenColumns() && !settings.isExportHiddenColumns())
     {
-      omitHidden = viewport.getViewAsString(false);
+      omitHidden = viewport.getViewAsString(false,
+              settings.isExportHiddenSequences());
     }
 
     int[] alignmentStartEnd = new int[2];
@@ -1325,17 +1325,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     else
     {
       alignmentToExport = viewport.getAlignment();
-      alignmentStartEnd = viewport.getAlignment()
-              .getVisibleStartAndEndIndex(
-                      viewport
-              .getColumnSelection().getHiddenColumns());
     }
+    alignmentStartEnd = alignmentToExport
+            .getVisibleStartAndEndIndex(viewport.getColumnSelection()
+                    .getHiddenColumns());
     AlignmentExportData ed = new AlignmentExportData(alignmentToExport,
             omitHidden, alignmentStartEnd, settings);
     return ed;
   }
 
-
   /**
    * DOCUMENT ME!
    * 
@@ -4682,6 +4680,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     return showp;
   }
 
+  /**
+   * Finds and displays cross-references for the selected sequences (protein
+   * products for nucleotide sequences, dna coding sequences for peptides).
+   * 
+   * @param sel
+   *          the sequences to show cross-references for
+   * @param dna
+   *          true if from a nucleotide alignment (so showing proteins)
+   * @param source
+   *          the database to show cross-references for
+   */
   protected void showProductsFor(final SequenceI[] sel, final boolean dna,
           final String source)
   {
@@ -4714,6 +4723,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
             AlignFrame newFrame = new AlignFrame(al, DEFAULT_WIDTH,
                     DEFAULT_HEIGHT);
+            if (Cache.getDefault("HIDE_INTRONS", true))
+            {
+              newFrame.hideFeatureColumns(SequenceOntologyI.EXON, false);
+            }
             String newtitle = String.format("%s %s %s",
                     MessageManager.getString(dna ? "label.proteins"
                             : "label.nucleotides"), MessageManager
@@ -4748,7 +4761,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 System.err.println("Failed to make CDS alignment");
               }
               al.getCodonFrames().clear();
-              al.getCodonFrames().addAll(copyAlignment.getCodonFrames());
+              al.addCodonFrames(copyAlignment.getCodonFrames());
+              al.addCodonFrames(cf);
 
               /*
                * pending getting Embl transcripts to 'align', 
@@ -4766,7 +4780,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             {
               copyAlignment = AlignmentUtils.makeCopyAlignment(
                       sequenceSelection, xrefs.getSequencesArray());
-              copyAlignment.getCodonFrames().addAll(cf);
+              copyAlignment.addCodonFrames(cf);
+              al.addCodonFrames(copyAlignment.getCodonFrames());
+              al.addCodonFrames(cf);
             }
             copyAlignment.setGapCharacter(AlignFrame.this.viewport
                     .getGapCharacter());
@@ -4841,15 +4857,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
         } catch (Exception e)
         {
-          Cache.log.error(
-                  "Exception when finding crossreferences", e);
+          Cache.log.error("Exception when finding crossreferences", e);
         } catch (OutOfMemoryError e)
         {
           new OOMWarning("whilst fetching crossreferences", e);
         } catch (Throwable e)
         {
-          Cache.log.error("Error when finding crossreferences",
-                  e);
+          Cache.log.error("Error when finding crossreferences", e);
         } finally
         {
           AlignFrame.this.setProgressBar(MessageManager.formatMessage(
@@ -4927,7 +4941,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               .getString("label.error_when_translating_sequences_submit_bug_report");
       final String errorTitle = MessageManager
               .getString("label.implementation_error")
-              + MessageManager.getString("translation_failed");
+              + MessageManager.getString("label.translation_failed");
       JOptionPane.showMessageDialog(Desktop.desktop, msg, errorTitle,
               JOptionPane.ERROR_MESSAGE);
       return;
@@ -5026,49 +5040,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void drop(DropTargetDropEvent evt)
   {
     Transferable t = evt.getTransferable();
-    java.util.List files = null;
+    java.util.List<String> files = new ArrayList<String>(), protocols = new ArrayList<String>();
 
     try
     {
-      DataFlavor uriListFlavor = new DataFlavor(
-              "text/uri-list;class=java.lang.String");
-      if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
-      {
-        // Works on Windows and MacOSX
-        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
-        files = (java.util.List) t
-                .getTransferData(DataFlavor.javaFileListFlavor);
-      }
-      else if (t.isDataFlavorSupported(uriListFlavor))
-      {
-        // This is used by Unix drag system
-        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
-        String data = (String) t.getTransferData(uriListFlavor);
-        files = new java.util.ArrayList(1);
-        for (java.util.StringTokenizer st = new java.util.StringTokenizer(
-                data, "\r\n"); st.hasMoreTokens();)
-        {
-          String s = st.nextToken();
-          if (s.startsWith("#"))
-          {
-            // the line is a comment (as per the RFC 2483)
-            continue;
-          }
-
-          java.net.URI uri = new java.net.URI(s);
-          // check to see if we can handle this kind of URI
-          if (uri.getScheme().toLowerCase().startsWith("http"))
-          {
-            files.add(uri.toString());
-          }
-          else
-          {
-            // otherwise preserve old behaviour: catch all for file objects
-            java.io.File file = new java.io.File(uri);
-            files.add(file.toString());
-          }
-        }
-      }
+      Desktop.transferFromDropTarget(files, protocols, evt, t);
     } catch (Exception e)
     {
       e.printStackTrace();
@@ -5543,8 +5519,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 AlignFrame.this.setMenusForViewport();
               }
             });
-            dbRefFetcher
-                    .fetchDBRefs(false);
+            dbRefFetcher.fetchDBRefs(false);
           }
         }).start();
 
@@ -6102,9 +6077,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     try
     {
       Dna dna = new Dna(viewport, viewport.getViewAsVisibleContigs(true));
-
       al = dna.reverseCdna(complement);
       viewport.addAlignment(al, "");
+      addHistoryItem(new EditCommand(
+              MessageManager.getString("label.add_sequences"),
+              Action.PASTE, al.getSequencesArray(), 0, al.getWidth(),
+              viewport.getAlignment()));
     } catch (Exception ex)
     {
       System.err.println(ex.getMessage());
@@ -6120,20 +6098,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   protected void runGroovy_actionPerformed()
   {
-    Desktop.setCurrentAlignFrame(this);
-    Object console = Desktop.instance.getGroovyConsole();
+    Jalview.setCurrentAlignFrame(this);
+    groovy.ui.Console console = Desktop.getGroovyConsole();
     if (console != null)
     {
-      /*
-       * use reflection here to avoid compile-time dependency
-       * on Groovy libraries
-       */
       try
       {
-        Class<?> gcClass = getClass().getClassLoader().loadClass(
-                "groovy.ui.Console");
-        Method runScript = gcClass.getMethod("runScript");
-        runScript.invoke(console);
+        console.runScript();
       } catch (Exception ex)
       {
         System.err.println((ex.toString()));
@@ -6150,6 +6121,31 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       System.err.println("Can't run Groovy script as console not found");
     }
   }
+
+  /**
+   * Hides columns containing (or not containing) a specified feature, provided
+   * that would not leave all columns hidden
+   * 
+   * @param featureType
+   * @param columnsContaining
+   * @return
+   */
+  public boolean hideFeatureColumns(String featureType,
+          boolean columnsContaining)
+  {
+    boolean notForHiding = avc.markColumnsContainingFeatures(
+            columnsContaining, false, false, featureType);
+    if (notForHiding)
+    {
+      if (avc.markColumnsContainingFeatures(!columnsContaining, false,
+              false, featureType))
+      {
+        getViewport().hideSelectedColumns();
+        return true;
+      }
+    }
+    return false;
+  }
 }
 
 class PrintThread extends Thread
index 692cd18..b1a4fee 100644 (file)
@@ -683,27 +683,42 @@ public class AlignViewport extends AlignmentViewport implements
     List<SequenceI[]> seqvectors = new ArrayList<SequenceI[]>();
     for (PDBEntry pdb : pdbEntries)
     {
-      List<SequenceI> seqs = new ArrayList<SequenceI>();
+      List<SequenceI> choosenSeqs = new ArrayList<SequenceI>();
       for (SequenceI sq : alignment.getSequences())
       {
-        Vector<PDBEntry> pdbs = sq.getDatasetSequence().getAllPDBEntries();
-        if (pdbs == null)
+        Vector<PDBEntry> pdbRefEntries = sq.getDatasetSequence().getAllPDBEntries();
+        if (pdbRefEntries == null)
         {
           continue;
         }
-        for (PDBEntry p1 : pdbs)
+        for (PDBEntry pdbRefEntry : pdbRefEntries)
         {
-          if (p1.getId().equals(pdb.getId()))
+          if (pdbRefEntry.getId().equals(pdb.getId()))
           {
-            if (!seqs.contains(sq))
+            if (pdbRefEntry.getChainCode() != null
+                    && pdb.getChainCode() != null)
             {
-              seqs.add(sq);
-              continue;
+              if (pdbRefEntry.getChainCode().equalsIgnoreCase(
+                      pdb.getChainCode())
+                      && !choosenSeqs.contains(sq))
+              {
+                choosenSeqs.add(sq);
+                continue;
+              }
             }
+            else
+            {
+              if (!choosenSeqs.contains(sq))
+              {
+                choosenSeqs.add(sq);
+                continue;
+              }
+            }
+
           }
         }
       }
-      seqvectors.add(seqs.toArray(new SequenceI[seqs.size()]));
+      seqvectors.add(choosenSeqs.toArray(new SequenceI[choosenSeqs.size()]));
     }
     return seqvectors.toArray(new SequenceI[seqvectors.size()][]);
   }
@@ -1103,6 +1118,7 @@ public class AlignViewport extends AlignmentViewport implements
    * 
    * @param featureSettings
    */
+  @Override
   public void applyFeaturesStyle(FeatureSettingsModelI featureSettings)
   {
     if (featureSettings == null)
index 7c5ae06..5b01b9b 100755 (executable)
@@ -327,17 +327,275 @@ public class AnnotationLabels extends JPanel implements MouseListener,
     return true;
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
   @Override
   public void mousePressed(MouseEvent evt)
   {
     getSelectedRow(evt.getY() - getScrollOffset());
     oldY = evt.getY();
+    if (!evt.isPopupTrigger())
+    {
+      return;
+    }
+    evt.consume();
+    // handle popup menu event
+    final AlignmentAnnotation[] aa = ap.av.getAlignment()
+            .getAlignmentAnnotation();
+
+    JPopupMenu pop = new JPopupMenu(
+            MessageManager.getString("label.annotations"));
+    JMenuItem item = new JMenuItem(ADDNEW);
+    item.addActionListener(this);
+    pop.add(item);
+    if (selectedRow < 0)
+    {
+      if (hasHiddenRows)
+      { // let the user make everything visible again
+        item = new JMenuItem(SHOWALL);
+        item.addActionListener(this);
+        pop.add(item);
+      }
+      pop.show(this, evt.getX(), evt.getY());
+      return;
+    }
+    item = new JMenuItem(EDITNAME);
+    item.addActionListener(this);
+    pop.add(item);
+    item = new JMenuItem(HIDE);
+    item.addActionListener(this);
+    pop.add(item);
+    // JAL-1264 hide all sequence-specific annotations of this type
+    if (selectedRow < aa.length)
+    {
+      if (aa[selectedRow].sequenceRef != null)
+      {
+        final String label = aa[selectedRow].label;
+        JMenuItem hideType = new JMenuItem();
+        String text = MessageManager.getString("label.hide_all") + " "
+                + label;
+        hideType.setText(text);
+        hideType.addActionListener(new ActionListener()
+        {
+          @Override
+          public void actionPerformed(ActionEvent e)
+          {
+            AlignmentUtils.showOrHideSequenceAnnotations(
+                    ap.av.getAlignment(), Collections.singleton(label),
+                    null, false, false);
+            // for (AlignmentAnnotation ann : ap.av.getAlignment()
+            // .getAlignmentAnnotation())
+            // {
+            // if (ann.sequenceRef != null && ann.label != null
+            // && ann.label.equals(label))
+            // {
+            // ann.visible = false;
+            // }
+            // }
+            refresh();
+          }
+        });
+        pop.add(hideType);
+      }
+    }
+    item = new JMenuItem(DELETE);
+    item.addActionListener(this);
+    pop.add(item);
+    if (hasHiddenRows)
+    {
+      item = new JMenuItem(SHOWALL);
+      item.addActionListener(this);
+      pop.add(item);
+    }
+    item = new JMenuItem(OUTPUT_TEXT);
+    item.addActionListener(this);
+    pop.add(item);
+    // TODO: annotation object should be typed for autocalculated/derived
+    // property methods
+    if (selectedRow < aa.length)
+    {
+      final String label = aa[selectedRow].label;
+      if (!aa[selectedRow].autoCalculated)
+      {
+        if (aa[selectedRow].graph == AlignmentAnnotation.NO_GRAPH)
+        {
+          // display formatting settings for this row.
+          pop.addSeparator();
+          // av and sequencegroup need to implement same interface for
+          item = new JCheckBoxMenuItem(TOGGLE_LABELSCALE,
+                  aa[selectedRow].scaleColLabel);
+          item.addActionListener(this);
+          pop.add(item);
+        }
+      }
+      else if (label.indexOf("Consensus") > -1)
+      {
+        pop.addSeparator();
+        // av and sequencegroup need to implement same interface for
+        final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem(
+                MessageManager.getString("label.ignore_gaps_consensus"),
+                (aa[selectedRow].groupRef != null) ? aa[selectedRow].groupRef
+                        .getIgnoreGapsConsensus() : ap.av
+                        .isIgnoreGapsConsensus());
+        final AlignmentAnnotation aaa = aa[selectedRow];
+        cbmi.addActionListener(new ActionListener()
+        {
+          @Override
+          public void actionPerformed(ActionEvent e)
+          {
+            if (aaa.groupRef != null)
+            {
+              // TODO: pass on reference to ap so the view can be updated.
+              aaa.groupRef.setIgnoreGapsConsensus(cbmi.getState());
+              ap.getAnnotationPanel().paint(
+                      ap.getAnnotationPanel().getGraphics());
+            }
+            else
+            {
+              ap.av.setIgnoreGapsConsensus(cbmi.getState(), ap);
+            }
+          }
+        });
+        pop.add(cbmi);
+        // av and sequencegroup need to implement same interface for
+        if (aaa.groupRef != null)
+        {
+          final JCheckBoxMenuItem chist = new JCheckBoxMenuItem(
+                  MessageManager.getString("label.show_group_histogram"),
+                  aa[selectedRow].groupRef.isShowConsensusHistogram());
+          chist.addActionListener(new ActionListener()
+          {
+            @Override
+            public void actionPerformed(ActionEvent e)
+            {
+              // TODO: pass on reference
+              // to ap
+              // so the
+              // view
+              // can be
+              // updated.
+              aaa.groupRef.setShowConsensusHistogram(chist.getState());
+              ap.repaint();
+              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
+            }
+          });
+          pop.add(chist);
+          final JCheckBoxMenuItem cprofl = new JCheckBoxMenuItem(
+                  MessageManager.getString("label.show_group_logo"),
+                  aa[selectedRow].groupRef.isShowSequenceLogo());
+          cprofl.addActionListener(new ActionListener()
+          {
+            @Override
+            public void actionPerformed(ActionEvent e)
+            {
+              // TODO: pass on reference
+              // to ap
+              // so the
+              // view
+              // can be
+              // updated.
+              aaa.groupRef.setshowSequenceLogo(cprofl.getState());
+              ap.repaint();
+              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
+            }
+          });
+          pop.add(cprofl);
+          final JCheckBoxMenuItem cproflnorm = new JCheckBoxMenuItem(
+                  MessageManager.getString("label.normalise_group_logo"),
+                  aa[selectedRow].groupRef.isNormaliseSequenceLogo());
+          cproflnorm.addActionListener(new ActionListener()
+          {
+            @Override
+            public void actionPerformed(ActionEvent e)
+            {
+
+              // TODO: pass on reference
+              // to ap
+              // so the
+              // view
+              // can be
+              // updated.
+              aaa.groupRef.setNormaliseSequenceLogo(cproflnorm.getState());
+              // automatically enable logo display if we're clicked
+              aaa.groupRef.setshowSequenceLogo(true);
+              ap.repaint();
+              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
+            }
+          });
+          pop.add(cproflnorm);
+        }
+        else
+        {
+          final JCheckBoxMenuItem chist = new JCheckBoxMenuItem(
+                  MessageManager.getString("label.show_histogram"),
+                  av.isShowConsensusHistogram());
+          chist.addActionListener(new ActionListener()
+          {
+            @Override
+            public void actionPerformed(ActionEvent e)
+            {
+              // TODO: pass on reference
+              // to ap
+              // so the
+              // view
+              // can be
+              // updated.
+              av.setShowConsensusHistogram(chist.getState());
+              ap.alignFrame.setMenusForViewport();
+              ap.repaint();
+              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
+            }
+          });
+          pop.add(chist);
+          final JCheckBoxMenuItem cprof = new JCheckBoxMenuItem(
+                  MessageManager.getString("label.show_logo"),
+                  av.isShowSequenceLogo());
+          cprof.addActionListener(new ActionListener()
+          {
+            @Override
+            public void actionPerformed(ActionEvent e)
+            {
+              // TODO: pass on reference
+              // to ap
+              // so the
+              // view
+              // can be
+              // updated.
+              av.setShowSequenceLogo(cprof.getState());
+              ap.alignFrame.setMenusForViewport();
+              ap.repaint();
+              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
+            }
+          });
+          pop.add(cprof);
+          final JCheckBoxMenuItem cprofnorm = new JCheckBoxMenuItem(
+                  MessageManager.getString("label.normalise_logo"),
+                  av.isNormaliseSequenceLogo());
+          cprofnorm.addActionListener(new ActionListener()
+          {
+            @Override
+            public void actionPerformed(ActionEvent e)
+            {
+              // TODO: pass on reference
+              // to ap
+              // so the
+              // view
+              // can be
+              // updated.
+              av.setShowSequenceLogo(true);
+              av.setNormaliseSequenceLogo(cprofnorm.getState());
+              ap.alignFrame.setMenusForViewport();
+              ap.repaint();
+              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
+            }
+          });
+          pop.add(cprofnorm);
+        }
+        final JMenuItem consclipbrd = new JMenuItem(COPYCONS_SEQ);
+        consclipbrd.addActionListener(this);
+        pop.add(consclipbrd);
+      }
+    }
+    pop.show(this, evt.getX(), evt.getY());
+
   }
 
   /**
@@ -529,18 +787,12 @@ public class AnnotationLabels extends JPanel implements MouseListener,
     }
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
   @Override
   public void mouseClicked(MouseEvent evt)
   {
     final AlignmentAnnotation[] aa = ap.av.getAlignment()
             .getAlignmentAnnotation();
-    if (SwingUtilities.isLeftMouseButton(evt))
+    if (!evt.isPopupTrigger() && SwingUtilities.isLeftMouseButton(evt))
     {
       if (selectedRow > -1 && selectedRow < aa.length)
       {
@@ -551,8 +803,45 @@ public class AnnotationLabels extends JPanel implements MouseListener,
             // todo: make the ap scroll to the selection - not necessary, first
             // click highlights/scrolls, second selects
             ap.getSeqPanel().ap.getIdPanel().highlightSearchResults(null);
-            ap.av.setSelectionGroup(// new SequenceGroup(
-            aa[selectedRow].groupRef); // );
+            // process modifiers
+            SequenceGroup sg = ap.av.getSelectionGroup();
+            if (sg == null
+                    || sg == aa[selectedRow].groupRef
+                    || !(jalview.util.Platform.isControlDown(evt) || evt
+                            .isShiftDown()))
+            {
+              if (jalview.util.Platform.isControlDown(evt)
+                      || evt.isShiftDown())
+              {
+                // clone a new selection group from the associated group
+                ap.av.setSelectionGroup(new SequenceGroup(
+                        aa[selectedRow].groupRef));
+              }
+              else
+              {
+                // set selection to the associated group so it can be edited
+                ap.av.setSelectionGroup(aa[selectedRow].groupRef);
+              }
+            }
+            else
+            {
+              // modify current selection with associated group
+              int remainToAdd = aa[selectedRow].groupRef.getSize();
+              for (SequenceI sgs : aa[selectedRow].groupRef.getSequences())
+              {
+                if (jalview.util.Platform.isControlDown(evt))
+                {
+                  sg.addOrRemove(sgs, --remainToAdd == 0);
+                }
+                else
+                {
+                  // notionally, we should also add intermediate sequences from
+                  // last added sequence ?
+                  sg.addSequence(sgs, --remainToAdd == 0);
+                }
+              }
+            }
+
             ap.paintAlignment(false);
             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
             ap.av.sendSelection();
@@ -582,7 +871,8 @@ public class AnnotationLabels extends JPanel implements MouseListener,
               // we make a copy rather than edit the current selection if no
               // modifiers pressed
               // see Enhancement JAL-1557
-              if (!(evt.isControlDown() || evt.isShiftDown()))
+              if (!(jalview.util.Platform.isControlDown(evt) || evt
+                      .isShiftDown()))
               {
                 sg = new SequenceGroup(sg);
                 sg.clear();
@@ -590,7 +880,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
               }
               else
               {
-                if (evt.isControlDown())
+                if (jalview.util.Platform.isControlDown(evt))
                 {
                   sg.addOrRemove(aa[selectedRow].sequenceRef, true);
                 }
@@ -610,273 +900,15 @@ public class AnnotationLabels extends JPanel implements MouseListener,
               sg.addSequence(aa[selectedRow].sequenceRef, false);
             }
             ap.av.setSelectionGroup(sg);
-            ap.av.sendSelection();
             ap.paintAlignment(false);
             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
+            ap.av.sendSelection();
           }
 
         }
       }
-    }
-    // if (!evt.isPopupTrigger())
-    // {
-    // return;
-    // }
-
-    JPopupMenu pop = new JPopupMenu(
-            MessageManager.getString("label.annotations"));
-    JMenuItem item = new JMenuItem(ADDNEW);
-    item.addActionListener(this);
-    pop.add(item);
-    if (selectedRow < 0)
-    {
-      if (hasHiddenRows)
-      { // let the user make everything visible again
-        item = new JMenuItem(SHOWALL);
-        item.addActionListener(this);
-        pop.add(item);
-      }
-      pop.show(this, evt.getX(), evt.getY());
       return;
     }
-    item = new JMenuItem(EDITNAME);
-    item.addActionListener(this);
-    pop.add(item);
-    item = new JMenuItem(HIDE);
-    item.addActionListener(this);
-    pop.add(item);
-    // JAL-1264 hide all sequence-specific annotations of this type
-    if (selectedRow < aa.length)
-    {
-      if (aa[selectedRow].sequenceRef != null)
-      {
-        final String label = aa[selectedRow].label;
-        JMenuItem hideType = new JMenuItem();
-        String text = MessageManager.getString("label.hide_all") + " "
-                + label;
-        hideType.setText(text);
-        hideType.addActionListener(new ActionListener()
-        {
-          @Override
-          public void actionPerformed(ActionEvent e)
-          {
-            AlignmentUtils.showOrHideSequenceAnnotations(
-                    ap.av.getAlignment(), Collections.singleton(label),
-                    null, false, false);
-            // for (AlignmentAnnotation ann : ap.av.getAlignment()
-            // .getAlignmentAnnotation())
-            // {
-            // if (ann.sequenceRef != null && ann.label != null
-            // && ann.label.equals(label))
-            // {
-            // ann.visible = false;
-            // }
-            // }
-            refresh();
-          }
-        });
-        pop.add(hideType);
-      }
-    }
-    item = new JMenuItem(DELETE);
-    item.addActionListener(this);
-    pop.add(item);
-    if (hasHiddenRows)
-    {
-      item = new JMenuItem(SHOWALL);
-      item.addActionListener(this);
-      pop.add(item);
-    }
-    item = new JMenuItem(OUTPUT_TEXT);
-    item.addActionListener(this);
-    pop.add(item);
-    // TODO: annotation object should be typed for autocalculated/derived
-    // property methods
-    if (selectedRow < aa.length)
-    {
-      final String label = aa[selectedRow].label;
-      if (!aa[selectedRow].autoCalculated)
-      {
-        if (aa[selectedRow].graph == AlignmentAnnotation.NO_GRAPH)
-        {
-          // display formatting settings for this row.
-          pop.addSeparator();
-          // av and sequencegroup need to implement same interface for
-          item = new JCheckBoxMenuItem(TOGGLE_LABELSCALE,
-                  aa[selectedRow].scaleColLabel);
-          item.addActionListener(this);
-          pop.add(item);
-        }
-      }
-      else if (label.indexOf("Consensus") > -1)
-      {
-        pop.addSeparator();
-        // av and sequencegroup need to implement same interface for
-        final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem(
-                MessageManager.getString("label.ignore_gaps_consensus"),
-                (aa[selectedRow].groupRef != null) ? aa[selectedRow].groupRef
-                        .getIgnoreGapsConsensus() : ap.av
-                        .isIgnoreGapsConsensus());
-        final AlignmentAnnotation aaa = aa[selectedRow];
-        cbmi.addActionListener(new ActionListener()
-        {
-          @Override
-          public void actionPerformed(ActionEvent e)
-          {
-            if (aaa.groupRef != null)
-            {
-              // TODO: pass on reference to ap so the view can be updated.
-              aaa.groupRef.setIgnoreGapsConsensus(cbmi.getState());
-              ap.getAnnotationPanel().paint(
-                      ap.getAnnotationPanel().getGraphics());
-            }
-            else
-            {
-              ap.av.setIgnoreGapsConsensus(cbmi.getState(), ap);
-            }
-          }
-        });
-        pop.add(cbmi);
-        // av and sequencegroup need to implement same interface for
-        if (aaa.groupRef != null)
-        {
-          final JCheckBoxMenuItem chist = new JCheckBoxMenuItem(
-                  MessageManager.getString("label.show_group_histogram"),
-                  aa[selectedRow].groupRef.isShowConsensusHistogram());
-          chist.addActionListener(new ActionListener()
-          {
-            @Override
-            public void actionPerformed(ActionEvent e)
-            {
-              // TODO: pass on reference
-              // to ap
-              // so the
-              // view
-              // can be
-              // updated.
-              aaa.groupRef.setShowConsensusHistogram(chist.getState());
-              ap.repaint();
-              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
-            }
-          });
-          pop.add(chist);
-          final JCheckBoxMenuItem cprofl = new JCheckBoxMenuItem(
-                  MessageManager.getString("label.show_group_logo"),
-                  aa[selectedRow].groupRef.isShowSequenceLogo());
-          cprofl.addActionListener(new ActionListener()
-          {
-            @Override
-            public void actionPerformed(ActionEvent e)
-            {
-              // TODO: pass on reference
-              // to ap
-              // so the
-              // view
-              // can be
-              // updated.
-              aaa.groupRef.setshowSequenceLogo(cprofl.getState());
-              ap.repaint();
-              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
-            }
-          });
-          pop.add(cprofl);
-          final JCheckBoxMenuItem cproflnorm = new JCheckBoxMenuItem(
-                  MessageManager.getString("label.normalise_group_logo"),
-                  aa[selectedRow].groupRef.isNormaliseSequenceLogo());
-          cproflnorm.addActionListener(new ActionListener()
-          {
-            @Override
-            public void actionPerformed(ActionEvent e)
-            {
-
-              // TODO: pass on reference
-              // to ap
-              // so the
-              // view
-              // can be
-              // updated.
-              aaa.groupRef.setNormaliseSequenceLogo(cproflnorm.getState());
-              // automatically enable logo display if we're clicked
-              aaa.groupRef.setshowSequenceLogo(true);
-              ap.repaint();
-              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
-            }
-          });
-          pop.add(cproflnorm);
-        }
-        else
-        {
-          final JCheckBoxMenuItem chist = new JCheckBoxMenuItem(
-                  MessageManager.getString("label.show_histogram"),
-                  av.isShowConsensusHistogram());
-          chist.addActionListener(new ActionListener()
-          {
-            @Override
-            public void actionPerformed(ActionEvent e)
-            {
-              // TODO: pass on reference
-              // to ap
-              // so the
-              // view
-              // can be
-              // updated.
-              av.setShowConsensusHistogram(chist.getState());
-              ap.alignFrame.setMenusForViewport();
-              ap.repaint();
-              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
-            }
-          });
-          pop.add(chist);
-          final JCheckBoxMenuItem cprof = new JCheckBoxMenuItem(
-                  MessageManager.getString("label.show_logo"),
-                  av.isShowSequenceLogo());
-          cprof.addActionListener(new ActionListener()
-          {
-            @Override
-            public void actionPerformed(ActionEvent e)
-            {
-              // TODO: pass on reference
-              // to ap
-              // so the
-              // view
-              // can be
-              // updated.
-              av.setShowSequenceLogo(cprof.getState());
-              ap.alignFrame.setMenusForViewport();
-              ap.repaint();
-              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
-            }
-          });
-          pop.add(cprof);
-          final JCheckBoxMenuItem cprofnorm = new JCheckBoxMenuItem(
-                  MessageManager.getString("label.normalise_logo"),
-                  av.isNormaliseSequenceLogo());
-          cprofnorm.addActionListener(new ActionListener()
-          {
-            @Override
-            public void actionPerformed(ActionEvent e)
-            {
-              // TODO: pass on reference
-              // to ap
-              // so the
-              // view
-              // can be
-              // updated.
-              av.setShowSequenceLogo(true);
-              av.setNormaliseSequenceLogo(cprofnorm.getState());
-              ap.alignFrame.setMenusForViewport();
-              ap.repaint();
-              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
-            }
-          });
-          pop.add(cprofnorm);
-        }
-        final JMenuItem consclipbrd = new JMenuItem(COPYCONS_SEQ);
-        consclipbrd.addActionListener(this);
-        pop.add(consclipbrd);
-      }
-    }
-    pop.show(this, evt.getX(), evt.getY());
   }
 
   /**
index 392bf32..e56c42f 100644 (file)
@@ -72,9 +72,6 @@ import java.beans.PropertyVetoException;
 import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileOutputStream;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Hashtable;
@@ -172,8 +169,6 @@ public class Desktop extends jalview.jbgui.GDesktop implements
 
   static final int yOffset = 30;
 
-  private static AlignFrame currentAlignFrame;
-
   public static jalview.ws.jws1.Discoverer discoverer;
 
   public static Object[] jalviewClipboard;
@@ -315,7 +310,20 @@ public class Desktop extends jalview.jbgui.GDesktop implements
      */
     instance = this;
     doVamsasClientCheck();
-    doGroovyCheck();
+
+    groovyShell = new JMenuItem();
+    groovyShell.setText(MessageManager.getString("label.groovy_console"));
+    groovyShell.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        groovyShell_actionPerformed();
+      }
+    });
+    toolsMenu.add(groovyShell);
+    groovyShell.setVisible(true);
+
     doConfigureStructurePrefs();
     setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
@@ -942,53 +950,15 @@ public class Desktop extends jalview.jbgui.GDesktop implements
   {
     boolean success = true;
     Transferable t = evt.getTransferable();
-    java.util.List files = null;
-    java.util.List protocols = null;
+    java.util.List<String> files = new ArrayList<String>();
+    java.util.List<String> protocols = new ArrayList<String>();
 
     try
     {
-      DataFlavor uriListFlavor = new DataFlavor(
-              "text/uri-list;class=java.lang.String");
-      if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
-      {
-        // Works on Windows and MacOSX
-        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
-        files = (java.util.List) t
-                .getTransferData(DataFlavor.javaFileListFlavor);
-      }
-      else if (t.isDataFlavorSupported(uriListFlavor))
-      {
-        // This is used by Unix drag system
-        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
-        String data = (String) t.getTransferData(uriListFlavor);
-        files = new java.util.ArrayList(1);
-        protocols = new java.util.ArrayList(1);
-        for (java.util.StringTokenizer st = new java.util.StringTokenizer(
-                data, "\r\n"); st.hasMoreTokens();)
-        {
-          String s = st.nextToken();
-          if (s.startsWith("#"))
-          {
-            // the line is a comment (as per the RFC 2483)
-            continue;
-          }
-          java.net.URI uri = new java.net.URI(s);
-          if (uri.getScheme().toLowerCase().startsWith("http"))
-          {
-            protocols.add(FormatAdapter.URL);
-            files.add(uri.toString());
-          }
-          else
-          {
-            // otherwise preserve old behaviour: catch all for file objects
-            java.io.File file = new java.io.File(uri);
-            protocols.add(FormatAdapter.FILE);
-            files.add(file.toString());
-          }
-        }
-      }
+      Desktop.transferFromDropTarget(files, protocols, evt, t);
     } catch (Exception e)
     {
+      e.printStackTrace();
       success = false;
     }
 
@@ -2389,25 +2359,6 @@ public class Desktop extends jalview.jbgui.GDesktop implements
 
   protected JMenuItem groovyShell;
 
-  public void doGroovyCheck()
-  {
-    if (jalview.bin.Cache.groovyJarsPresent())
-    {
-      groovyShell = new JMenuItem();
-      groovyShell.setText(MessageManager.getString("label.groovy_console"));
-      groovyShell.addActionListener(new ActionListener()
-      {
-        @Override
-        public void actionPerformed(ActionEvent e)
-        {
-          groovyShell_actionPerformed();
-        }
-      });
-      toolsMenu.add(groovyShell);
-      groovyShell.setVisible(true);
-    }
-  }
-
   /**
    * Accessor method to quickly get all the AlignmentFrames loaded.
    * 
@@ -2418,7 +2369,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
     if (Jalview.isHeadlessMode())
     {
       // Desktop.desktop is null in headless mode
-      return new AlignFrame[] { currentAlignFrame };
+      return new AlignFrame[] { Jalview.currentAlignFrame };
     }
 
     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
@@ -2495,12 +2446,6 @@ public class Desktop extends jalview.jbgui.GDesktop implements
    */
   public void groovyShell_actionPerformed()
   {
-    if (!jalview.bin.Cache.groovyJarsPresent())
-    {
-      throw new Error(
-              MessageManager
-                      .getString("error.implementation_error_cannot_create_groovyshell"));
-    }
     try
     {
       openGroovyConsole();
@@ -2516,36 +2461,21 @@ public class Desktop extends jalview.jbgui.GDesktop implements
   }
 
   /**
-   * Open the Groovy console, using reflection to avoid creating compile-time
-   * dependency on Groovy libraries
-   * 
-   * @throws ClassNotFoundException
-   * @throws NoSuchMethodException
-   * @throws InstantiationException
-   * @throws IllegalAccessException
-   * @throws InvocationTargetException
+   * Open the Groovy console
    */
-  void openGroovyConsole() throws ClassNotFoundException,
-          NoSuchMethodException, InstantiationException,
-          IllegalAccessException, InvocationTargetException
+  void openGroovyConsole()
   {
-    Class<?> gcClass = Desktop.class.getClassLoader().loadClass(
-            "groovy.ui.Console");
-    Constructor<?> gccons = gcClass.getConstructor();
-    groovyConsole = gccons.newInstance();
+    groovyConsole = new groovy.ui.Console();
 
     /*
      * bind groovy variable 'Jalview' to the Desktop object
      */
-    Method setvar = gcClass.getMethod("setVariable", new Class[] {
-        String.class, Object.class });
-    setvar.invoke(groovyConsole, new Object[] { "Jalview", this });
+    groovyConsole.setVariable("Jalview", this);
 
     /*
      * start the console
      */
-    Method run = gcClass.getMethod("run");
-    run.invoke(groovyConsole);
+    groovyConsole.run();
 
     /*
      * Allow only one console at a time, so that the AlignFrame menu option
@@ -2553,14 +2483,12 @@ public class Desktop extends jalview.jbgui.GDesktop implements
      * Disable 'new console', and enable 'Run script', when the console is 
      * opened, and the reverse when it is closed
      */
-    Method getFrame = gcClass.getMethod("getFrame");
-    Window window = (Window) getFrame.invoke(groovyConsole);
+    Window window = (Window) groovyConsole.getFrame();
     window.addWindowListener(new WindowAdapter()
     {
       @Override
       public void windowClosed(WindowEvent e)
       {
-        groovyShell.setEnabled(true);
         enableExecuteGroovy(false);
       }
     });
@@ -2569,7 +2497,6 @@ public class Desktop extends jalview.jbgui.GDesktop implements
      * if we got this far, enable 'Run Groovy' in AlignFrame menus
      * and disable opening a second console
      */
-    groovyShell.setEnabled(false);
     enableExecuteGroovy(true);
   }
 
@@ -2577,9 +2504,16 @@ public class Desktop extends jalview.jbgui.GDesktop implements
    * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
    * 
    * @param enabled
+   *          true if Groovy console is open
    */
   public void enableExecuteGroovy(boolean enabled)
   {
+    /*
+     * disable opening a second Groovy console
+     * (or re-enable when the console is closed)
+     */
+    groovyShell.setEnabled(!enabled);
+
     AlignFrame[] alignFrames = getAlignFrames();
     if (alignFrames != null)
     {
@@ -2986,12 +2920,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
    */
   private java.util.concurrent.Semaphore block = new Semaphore(0);
 
-  /*
-   * groovy.ui.Console object - if Groovy jars are present and the 
-   * user has activated the Groovy console. Use via reflection to
-   * avoid compile-time dependency on Groovy libraries.
-   */
-  private static Object groovyConsole;
+  private static groovy.ui.Console groovyConsole;
 
   /**
    * add another dialog thread to the queue
@@ -3208,22 +3137,109 @@ public class Desktop extends jalview.jbgui.GDesktop implements
      * The dust settles...give focus to the tab we did this from.
      */
     myTopFrame.setDisplayedView(myTopFrame.alignPanel);
-
   }
 
-  public static AlignFrame getCurrentAlignFrame()
+  public static groovy.ui.Console getGroovyConsole()
   {
-    return currentAlignFrame;
+    return groovyConsole;
   }
 
-  public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
+  public static void transferFromDropTarget(List<String> files,
+          List<String> protocols, DropTargetDropEvent evt, Transferable t)
+          throws Exception
   {
-    Desktop.currentAlignFrame = currentAlignFrame;
-  }
 
-  public static Object getGroovyConsole()
-  {
-    return groovyConsole;
+    DataFlavor uriListFlavor = new DataFlavor(
+            "text/uri-list;class=java.lang.String");
+    if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
+    {
+      // Works on Windows and MacOSX
+      Cache.log.debug("Drop handled as javaFileListFlavor");
+      evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
+      for (Object file : (List) t
+              .getTransferData(DataFlavor.javaFileListFlavor))
+      {
+        files.add(((File)file).toString());
+        protocols.add(FormatAdapter.FILE);
+      }
+    }
+    else
+    {
+      // Unix like behaviour
+      boolean added = false;
+      String data = null;
+      if (t.isDataFlavorSupported(uriListFlavor))
+      {
+        Cache.log.debug("Drop handled as uriListFlavor");
+        // This is used by Unix drag system
+        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
+        data = (String) t.getTransferData(uriListFlavor);
+      }
+      if (data == null)
+      {
+        // fallback to text: workaround - on OSX where there's a JVM bug
+        Cache.log.debug("standard URIListFlavor failed. Trying text");
+        // try text fallback
+        data = (String) t.getTransferData(new DataFlavor(
+                "text/plain;class=java.lang.String"));
+        if (Cache.log.isDebugEnabled())
+        {
+          Cache.log.debug("fallback returned " + data);
+        }
+      }
+      while (protocols.size() < files.size())
+      {
+        Cache.log.debug("Adding missing FILE protocol for "
+                + files.get(protocols.size()));
+        protocols.add(FormatAdapter.FILE);
+      }
+      for (java.util.StringTokenizer st = new java.util.StringTokenizer(
+              data, "\r\n"); st.hasMoreTokens();)
+      {
+        added = true;
+        String s = st.nextToken();
+        if (s.startsWith("#"))
+        {
+          // the line is a comment (as per the RFC 2483)
+          continue;
+        }
+        java.net.URI uri = new java.net.URI(s);
+        if (uri.getScheme().toLowerCase().startsWith("http"))
+        {
+          protocols.add(FormatAdapter.URL);
+          files.add(uri.toString());
+        }
+        else
+        {
+          // otherwise preserve old behaviour: catch all for file objects
+          java.io.File file = new java.io.File(uri);
+          protocols.add(FormatAdapter.FILE);
+          files.add(file.toString());
+        }
+      }
+      if (Cache.log.isDebugEnabled())
+      {
+        if (data == null || !added)
+        {
+          Cache.log
+                  .debug("Couldn't resolve drop data. Here are the supported flavors:");
+          for (DataFlavor fl : t.getTransferDataFlavors())
+          {
+            Cache.log.debug("Supported transfer dataflavor: "
+                    + fl.toString());
+            evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
+            Object df = t.getTransferData(fl);
+            if (df != null)
+            {
+              Cache.log.debug("Retrieves: " + df);
+            }
+            else
+            {
+              Cache.log.debug("Retrieved nothing");
+            }
+          }
+        }
+      }
+    }
   }
-
 }
index 6633156..09204d1 100644 (file)
@@ -28,7 +28,9 @@ import jalview.gui.Help.HelpId;
 import jalview.io.JalviewFileChooser;
 import jalview.schemes.AnnotationColourGradient;
 import jalview.schemes.GraduatedColor;
+import jalview.util.Format;
 import jalview.util.MessageManager;
+import jalview.util.QuickSort;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.ws.dbsources.das.api.jalviewSourceI;
 
@@ -394,7 +396,6 @@ public class FeatureSettings extends JPanel implements
             MessageManager.getString("label.select_columns_containing"));
     selCols.addActionListener(new ActionListener()
     {
-
       @Override
       public void actionPerformed(ActionEvent arg0)
       {
@@ -406,7 +407,6 @@ public class FeatureSettings extends JPanel implements
             MessageManager.getString("label.select_columns_not_containing"));
     clearCols.addActionListener(new ActionListener()
     {
-
       @Override
       public void actionPerformed(ActionEvent arg0)
       {
@@ -414,8 +414,30 @@ public class FeatureSettings extends JPanel implements
                 false, type);
       }
     });
+    JMenuItem hideCols = new JMenuItem(
+            MessageManager.getString("label.hide_columns_containing"));
+    hideCols.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent arg0)
+      {
+        fr.ap.alignFrame.hideFeatureColumns(type, true);
+      }
+    });
+    JMenuItem hideOtherCols = new JMenuItem(
+            MessageManager.getString("label.hide_columns_not_containing"));
+    hideOtherCols.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent arg0)
+      {
+        fr.ap.alignFrame.hideFeatureColumns(type, false);
+      }
+    });
     men.add(selCols);
     men.add(clearCols);
+    men.add(hideCols);
+    men.add(hideOtherCols);
     men.show(table, x, y);
   }
 
@@ -810,7 +832,7 @@ public class FeatureSettings extends JPanel implements
   void save()
   {
     JalviewFileChooser chooser = new JalviewFileChooser(
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
+            Cache.getProperty("LAST_DIRECTORY"),
             new String[] { "fc" },
             new String[] { "Sequence Feature Colours" },
             "Sequence Feature Colours");
@@ -831,34 +853,35 @@ public class FeatureSettings extends JPanel implements
         PrintWriter out = new PrintWriter(new OutputStreamWriter(
                 new FileOutputStream(choice), "UTF-8"));
 
-        Set fr_colours = fr.getAllFeatureColours();
-        Iterator e = fr_colours.iterator();
+        Set<String> fr_colours = fr.getAllFeatureColours();
+        Iterator<String> e = fr_colours.iterator();
         float[] sortOrder = new float[fr_colours.size()];
         String[] sortTypes = new String[fr_colours.size()];
         int i = 0;
         while (e.hasNext())
         {
-          sortTypes[i] = e.next().toString();
+          sortTypes[i] = e.next();
           sortOrder[i] = fr.getOrder(sortTypes[i]);
           i++;
         }
-        jalview.util.QuickSort.sort(sortOrder, sortTypes);
+        QuickSort.sort(sortOrder, sortTypes);
         sortOrder = null;
         Object fcol;
         GraduatedColor gcol;
-        for (i = 0; i < sortTypes.length; i++)
+        for (String featureType : sortTypes)
         {
           jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
-          col.setName(sortTypes[i]);
-          col.setRGB(jalview.util.Format.getHexString(fr.getColour(col
-                  .getName())));
-          fcol = fr.getFeatureStyle(sortTypes[i]);
+          col.setName(featureType);
+          fcol = fr.getFeatureStyle(featureType);
+          Color colour = fcol instanceof Color ? (Color) fcol
+                  : ((GraduatedColor) fcol).getMaxColor();
+          col.setRGB(Format.getHexString(colour));
           if (fcol instanceof GraduatedColor)
           {
             gcol = (GraduatedColor) fcol;
             col.setMin(gcol.getMin());
             col.setMax(gcol.getMax());
-            col.setMinRGB(jalview.util.Format.getHexString(gcol
+            col.setMinRGB(Format.getHexString(gcol
                     .getMinColor()));
             col.setAutoScale(gcol.isAutoScale());
             col.setThreshold(gcol.getThresh());
@@ -1303,7 +1326,7 @@ public class FeatureSettings extends JPanel implements
    * 
    * @return vector of selected das source nicknames
    */
-  public Vector getSelectedSources()
+  public Vector<jalviewSourceI> getSelectedSources()
   {
     return dassourceBrowser.getSelectedSources();
   }
index c89a9d5..37be8bc 100755 (executable)
@@ -204,6 +204,7 @@ public class IdCanvas extends JPanel
    * @param g
    *          DOCUMENT ME!
    */
+  @Override
   public void paintComponent(Graphics g)
   {
     g.setColor(Color.white);
@@ -479,7 +480,7 @@ public class IdCanvas extends JPanel
     Font bold = new Font(av.getFont().getName(), Font.BOLD, av.getFont()
             .getSize());
 
-    if (av.isHiddenRepSequence(seq))
+    if (av.isReferenceSeq(seq) || av.isHiddenRepSequence(seq))
     {
       gg.setFont(bold);
     }
index e247793..61ddafb 100755 (executable)
@@ -191,8 +191,10 @@ public class IdPanel extends JPanel implements MouseListener,
      * Ignore single click. Ignore 'left' click followed by 'right' click (user
      * selects a row then its pop-up menu).
      */
-    if (e.getClickCount() < 2 || e.isPopupTrigger())
+    if (e.getClickCount() < 2 || SwingUtilities.isRightMouseButton(e))
     {
+      // reinstate isRightMouseButton check to ignore mouse-related popup events
+      // note - this does nothing on default MacBookPro force-trackpad config!
       return;
     }
 
@@ -347,10 +349,9 @@ public class IdPanel extends JPanel implements MouseListener,
 
       return;
     }
-
     if ((av.getSelectionGroup() == null)
-            || ((!e.isControlDown() && !e.isShiftDown()) && av
-                    .getSelectionGroup() != null))
+            || (!jalview.util.Platform.isControlDown(e)
+                    && !e.isShiftDown() && av.getSelectionGroup() != null))
     {
       av.setSelectionGroup(new SequenceGroup());
       av.getSelectionGroup().setStartRes(0);
index 6f602ad..8294d2b 100644 (file)
@@ -26,7 +26,6 @@ import jalview.ws.seqfetcher.DbSourceProxy;
 
 import java.awt.BorderLayout;
 import java.awt.Component;
-import java.awt.Container;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.GridLayout;
@@ -73,7 +72,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
       @Override
       public void actionPerformed(ActionEvent arg0)
       {
-        showDialog(null);
+        showDialog();
       }
     });
     return viewdbs;
@@ -188,6 +187,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
     jc.validate();
     // j.setPreferredSize(new Dimension(300,50));
     add(jc, BorderLayout.CENTER);
+    ok.setEnabled(false);
     j.add(ok);
     j.add(cancel);
     add(j, BorderLayout.SOUTH);
@@ -320,7 +320,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
     closeDialog();
   }
 
-  private void showDialog(Container parent)
+  void showDialog()
   {
     oldselection = selection;
     oldtsel = tsel;
@@ -349,10 +349,12 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
     {
       return;
     }
+    ok.setEnabled(false);
     if (dbviews.getSelectionCount() == 0)
     {
       selection = null;
     }
+
     tsel = dbviews.getSelectionPaths();
     boolean forcedFirstChild = false;
     List<DbSourceProxy> srcs = new ArrayList<DbSourceProxy>();
@@ -364,6 +366,10 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
                 .getLastPathComponent();
         if (dmt.getUserObject() != null)
         {
+          /*
+           * enable OK button once a selection has been made
+           */
+          ok.setEnabled(true);
           if (dmt.getUserObject() instanceof DbSourceProxy)
           {
             srcs.add((DbSourceProxy) dmt.getUserObject());
@@ -419,6 +425,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
       }
     }
 
+    dbstatex.setText(" ");
     if (allowMultiSelections)
     {
       dbstatus.setText(MessageManager.formatMessage(
@@ -427,7 +434,6 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
                   (srcs.size() == 1 ? "" : "s"),
                   (srcs.size() > 0 ? " with " + x + " test quer"
                           + (x == 1 ? "y" : "ies") : ".") }));
-      dbstatex.setText(" ");
     }
     else
     {
@@ -440,10 +446,6 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
           dbstatex.setText(MessageManager.formatMessage(
                   "label.example_param", new String[] { qr }));
         }
-        else
-        {
-          dbstatex.setText(" ");
-        }
       }
       else
       {
index 2799a7e..a3604d6 100644 (file)
@@ -79,6 +79,7 @@ import jalview.structure.StructureSelectionManager;
 import jalview.structures.models.AAStructureBindingModel;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.util.StringUtils;
 import jalview.util.jarInputStreamProvider;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
@@ -90,6 +91,7 @@ import jalview.ws.params.ArgumentI;
 import jalview.ws.params.AutoCalcSetting;
 import jalview.ws.params.WsParamSetI;
 
+import java.awt.Color;
 import java.awt.Rectangle;
 import java.io.BufferedReader;
 import java.io.DataInputStream;
@@ -116,7 +118,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-import java.util.StringTokenizer;
 import java.util.Vector;
 import java.util.jar.JarEntry;
 import java.util.jar.JarInputStream;
@@ -1194,17 +1195,17 @@ public class Jalview2XML
                 .getFeatureRenderer().getRenderOrder()
                 .toArray(new String[0]);
 
-        Vector settingsAdded = new Vector();
+        Vector<String> settingsAdded = new Vector<String>();
         Object gstyle = null;
         GraduatedColor gcol = null;
         if (renderOrder != null)
         {
-          for (int ro = 0; ro < renderOrder.length; ro++)
+          for (String featureType : renderOrder)
           {
             gstyle = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
-                    .getFeatureStyle(renderOrder[ro]);
+                    .getFeatureStyle(featureType);
             Setting setting = new Setting();
-            setting.setType(renderOrder[ro]);
+            setting.setType(featureType);
             if (gstyle instanceof GraduatedColor)
             {
               gcol = (GraduatedColor) gstyle;
@@ -1219,57 +1220,30 @@ public class Jalview2XML
             }
             else
             {
-              setting.setColour(ap.getSeqPanel().seqCanvas
-                      .getFeatureRenderer().getColour(renderOrder[ro])
-                      .getRGB());
+              setting.setColour(((Color) gstyle).getRGB());
             }
 
             setting.setDisplay(av.getFeaturesDisplayed().isVisible(
-                    renderOrder[ro]));
+                    featureType));
             float rorder = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
-                    .getOrder(renderOrder[ro]);
+                    .getOrder(featureType);
             if (rorder > -1)
             {
               setting.setOrder(rorder);
             }
             fs.addSetting(setting);
-            settingsAdded.addElement(renderOrder[ro]);
+            settingsAdded.addElement(featureType);
           }
         }
 
-        // Make sure we save none displayed feature settings
-        Iterator en = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
-                .getFeatureColours().keySet().iterator();
-        while (en.hasNext())
-        {
-          String key = en.next().toString();
-          if (settingsAdded.contains(key))
-          {
-            continue;
-          }
-
-          Setting setting = new Setting();
-          setting.setType(key);
-          setting.setColour(ap.getSeqPanel().seqCanvas.getFeatureRenderer()
-                  .getColour(key).getRGB());
-
-          setting.setDisplay(false);
-          float rorder = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
-                  .getOrder(key);
-          if (rorder > -1)
-          {
-            setting.setOrder(rorder);
-          }
-          fs.addSetting(setting);
-          settingsAdded.addElement(key);
-        }
         // is groups actually supposed to be a map here ?
-        en = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
+        Iterator<String> en = ap.getSeqPanel().seqCanvas
+                .getFeatureRenderer()
                 .getFeatureGroups().iterator();
-        Vector groupsAdded = new Vector();
+        Vector<String> groupsAdded = new Vector<String>();
         while (en.hasNext())
         {
-          String grp = en.next().toString();
+          String grp = en.next();
           if (groupsAdded.contains(grp))
           {
             continue;
@@ -4047,18 +4021,22 @@ public class Jalview2XML
   }
 
   /**
+   * Answers true if 'version' is equal to or later than 'supported', where each
+   * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
+   * changes. Development and test values for 'version' are leniently treated
+   * i.e. answer true.
    * 
    * @param supported
    *          - minimum version we are comparing against
    * @param version
-   *          - version of data being processsed.
-   * @return true if version is development/null or evaluates to the same or
-   *         later X.Y.Z (where X,Y,Z are like [0-9]+b?[0-9]*)
+   *          - version of data being processsed
+   * @return
    */
   public static boolean isVersionStringLaterThan(String supported,
           String version)
   {
-    if (version == null || version.equalsIgnoreCase("DEVELOPMENT BUILD")
+    if (supported == null || version == null
+            || version.equalsIgnoreCase("DEVELOPMENT BUILD")
             || version.equalsIgnoreCase("Test")
             || version.equalsIgnoreCase("AUTOMATED BUILD"))
     {
@@ -4069,45 +4047,8 @@ public class Jalview2XML
     }
     else
     {
-      StringTokenizer currentV = new StringTokenizer(supported, "."), fileV = new StringTokenizer(
-              version, ".");
-      while (currentV.hasMoreTokens() && fileV.hasMoreTokens())
-      {
-        // convert b to decimal to catch bugfix releases within a series
-        String curT = currentV.nextToken().toLowerCase().replace('b', '.');
-        String fileT = fileV.nextToken().toLowerCase().replace('b', '.');
-        try
-        {
-          float supportedVersionToken = Float.parseFloat(curT);
-          float myVersiontoken = Float.parseFloat(fileT);
-          if (supportedVersionToken > myVersiontoken)
-          {
-            // current version is newer than the version that wrote the file
-            return false;
-          }
-          if (supportedVersionToken < myVersiontoken)
-          {
-            // current version is older than the version that wrote the file
-            return true;
-          }
-        } catch (NumberFormatException nfe)
-        {
-          System.err
-                  .println("** WARNING: Version comparison failed for tokens ("
-                          + curT
-                          + ") and ("
-                          + fileT
-                          + ")\n** Current: '"
-                          + supported + "' and Version: '" + version + "'");
-        }
-      }
-      if (currentV.hasMoreElements())
-      {
-        // fileV has no minor version but identical series to current
-        return false;
-      }
+      return StringUtils.compareVersions(version, supported, "b") >= 0;
     }
-    return true;
   }
 
   Vector<JalviewStructureDisplayI> newStructureViewers = null;
index 801cb1f..7f1b305 100644 (file)
@@ -114,7 +114,7 @@ public class OptsAndParamsPage
                 .wrapTooltip(
                         true,
                         ((desc == null || desc.trim().length() == 0) ? MessageManager
-                                .getString("label.opt_and_params_further_details ")
+                                .getString("label.opt_and_params_further_details")
                                 : desc)
                                 + "<br><img src=\"" + linkImageURL + "\"/>"));
         enabled.addMouseListener(this);
@@ -357,7 +357,7 @@ public class OptsAndParamsPage
                                         + linkImageURL
                                         + "\"/>"
                                         + MessageManager
-                                                .getString("label.opt_and_params_further_detail")
+                                                .getString("label.opt_and_params_further_details")
                                         : "")));
       }
 
index 1e0772a..4b0ffad 100644 (file)
@@ -60,6 +60,7 @@ import jalview.util.GroupUrlLink;
 import jalview.util.GroupUrlLink.UrlStringTooLongException;
 import jalview.util.MessageManager;
 import jalview.util.UrlLink;
+import jalview.ws.DBRefFetcher;
 
 import java.awt.Color;
 import java.awt.event.ActionEvent;
@@ -2389,11 +2390,11 @@ public class PopupMenu extends JPopupMenu
       @Override
       public void run()
       {
-        boolean isNuclueotide = ap.alignFrame.getViewport().getAlignment()
+        boolean isNucleotide = ap.alignFrame.getViewport().getAlignment()
                 .isNucleotide();
 
-        new jalview.ws.DBRefFetcher(sequences, ap.alignFrame, null,
-                ap.alignFrame.featureSettings, isNuclueotide)
+        new DBRefFetcher(sequences, ap.alignFrame, null,
+                ap.alignFrame.featureSettings, isNucleotide)
                 .fetchDBRefs(false);
 
       }
index 6b2d3c4..afc93e0 100755 (executable)
@@ -164,6 +164,16 @@ public class Preferences extends GPreferences
 
   private WsPreferences wsPrefs;
 
+  private OptionsParam promptEachTimeOpt = new OptionsParam(
+          MessageManager.getString("label.prompt_each_time"),
+          "Prompt each time");
+
+  private OptionsParam lineArtOpt = new OptionsParam(
+          MessageManager.getString("label.lineart"), "Lineart");
+
+  private OptionsParam textOpt = new OptionsParam(
+          MessageManager.getString("action.text"), "Text");
+
   /**
    * Creates a new Preferences object.
    */
@@ -359,12 +369,23 @@ public class Preferences extends GPreferences
     /*
      * Set Output tab defaults
      */
-    epsRendering
-            .addItem(MessageManager.getString("label.prompt_each_time"));
-    epsRendering.addItem(MessageManager.getString("label.lineart"));
-    epsRendering.addItem(MessageManager.getString("action.text"));
-    epsRendering.setSelectedItem(Cache.getDefault("EPS_RENDERING",
-            "Prompt each time"));
+    epsRendering.addItem(promptEachTimeOpt);
+    epsRendering.addItem(lineArtOpt);
+    epsRendering.addItem(textOpt);
+    String defaultEPS = Cache.getDefault("EPS_RENDERING",
+            "Prompt each time");
+    if (defaultEPS.equalsIgnoreCase("Text"))
+    {
+      epsRendering.setSelectedItem(textOpt);
+    }
+    else if (defaultEPS.equalsIgnoreCase("Lineart"))
+    {
+      epsRendering.setSelectedItem(lineArtOpt);
+    }
+    else
+    {
+      epsRendering.setSelectedItem(promptEachTimeOpt);
+    }
     autoIdWidth.setSelected(Cache.getDefault("FIGURE_AUTOIDWIDTH", false));
     userIdWidth.setEnabled(!autoIdWidth.isSelected());
     userIdWidthlabel.setEnabled(!autoIdWidth.isSelected());
@@ -515,15 +536,8 @@ public class Preferences extends GPreferences
     /*
      * Save Output settings
      */
-    if (epsRendering.getSelectedItem().equals("Prompt each time"))
-    {
-      Cache.applicationProperties.remove("EPS_RENDERING");
-    }
-    else
-    {
-      Cache.applicationProperties.setProperty("EPS_RENDERING", epsRendering
-              .getSelectedItem().toString());
-    }
+      Cache.applicationProperties.setProperty("EPS_RENDERING",
+              ((OptionsParam) epsRendering.getSelectedItem()).getCode());
 
     /*
      * Save Connections settings
@@ -983,4 +997,57 @@ public class Preferences extends GPreferences
     }
   }
 
+  public class OptionsParam
+  {
+    private String name;
+
+    private String code;
+
+    public OptionsParam(String name, String code)
+    {
+      this.name = name;
+      this.code = code;
+    }
+
+    public String getName()
+    {
+      return name;
+    }
+
+    public void setName(String name)
+    {
+      this.name = name;
+    }
+
+    public String getCode()
+    {
+      return code;
+    }
+
+    public void setCode(String code)
+    {
+      this.code = code;
+    }
+
+    @Override
+    public String toString()
+    {
+      return name;
+    }
+
+    @Override
+    public boolean equals(Object that)
+    {
+      if (!(that instanceof OptionsParam))
+      {
+        return false;
+      }
+      return this.code.equalsIgnoreCase(((OptionsParam) that).code);
+    }
+
+    @Override
+    public int hashCode(){
+      return name.hashCode() + code.hashCode();
+    }
+  }
 }
index 3ab681c..2165b2c 100755 (executable)
@@ -35,6 +35,7 @@ import java.awt.event.ActionListener;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.util.List;
 
 import javax.swing.JMenuItem;
 import javax.swing.JPanel;
@@ -42,17 +43,14 @@ import javax.swing.JPopupMenu;
 import javax.swing.ToolTipManager;
 
 /**
- * DOCUMENT ME!
- * 
- * @author $author$
- * @version $Revision$
+ * The panel containing the sequence ruler (when not in wrapped mode), and
+ * supports a range of mouse operations to select, hide or reveal columns.
  */
 public class ScalePanel extends JPanel implements MouseMotionListener,
         MouseListener
 {
   protected int offy = 4;
 
-  /** DOCUMENT ME!! */
   public int width;
 
   protected AlignViewport av;
@@ -61,13 +59,26 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
 
   boolean stretchingGroup = false;
 
-  int min; // used by mouseDragged to see if user
+  /*
+   * min, max hold the extent of a mouse drag action
+   */
+  int min;
 
-  int max; // used by mouseDragged to see if user
+  int max;
 
   boolean mouseDragging = false;
 
-  // wants to delete columns
+  /*
+   * holds a hidden column range when the mouse is over an adjacent column
+   */
+  int[] reveal;
+
+  /**
+   * Constructor
+   * 
+   * @param av
+   * @param ap
+   */
   public ScalePanel(AlignViewport av, AlignmentPanel ap)
   {
     this.av = av;
@@ -392,6 +403,8 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
   @Override
   public void mouseMoved(MouseEvent evt)
   {
+    this.setToolTipText(null);
+    reveal = null;
     if (!av.hasHiddenColumns())
     {
       return;
@@ -401,7 +414,6 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
 
     res = av.getColumnSelection().adjustForHiddenColumns(res);
 
-    reveal = null;
     if (av.getColumnSelection().getHiddenColumns() != null)
     {
       for (int[] region : av.getColumnSelection().getHiddenColumns())
@@ -414,17 +426,11 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
                   .getString("label.reveal_hidden_columns"));
           break;
         }
-        else
-        {
-          this.setToolTipText(null);
-        }
       }
     }
     repaint();
   }
 
-  int[] reveal;
-
   /**
    * DOCUMENT ME!
    * 
@@ -459,7 +465,6 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
     ColumnSelection cs = av.getColumnSelection();
     int avCharWidth = av.getCharWidth(), avCharHeight = av.getCharHeight();
 
-    int s;
     if (cs != null)
     {
       gg.setColor(new Color(220, 0, 0));
@@ -488,50 +493,15 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
         }
       }
     }
-    // Draw the scale numbers
-    gg.setColor(Color.black);
 
-    int scalestartx = (startx / 10) * 10;
     int widthx = 1 + endx - startx;
 
     FontMetrics fm = gg.getFontMetrics(av.getFont());
-    int y = avCharHeight - fm.getDescent();
-
-    if ((scalestartx % 10) == 0)
-    {
-      scalestartx += 5;
-    }
-
-    String string;
-    int maxX = 0;
-
-    for (int i = scalestartx; i < endx; i += 5)
-    {
-      if ((i % 10) == 0)
-      {
-        string = String.valueOf(av.getColumnSelection()
-                .adjustForHiddenColumns(i));
-        if ((i - startx - 1) * avCharWidth > maxX)
-        {
-          gg.drawString(string, (i - startx - 1) * avCharWidth, y);
-          maxX = (i - startx + 1) * avCharWidth + fm.stringWidth(string);
-        }
-
-        gg.drawLine(((i - startx - 1) * avCharWidth) + (avCharWidth / 2),
-                y + 2,
-                ((i - startx - 1) * avCharWidth) + (avCharWidth / 2), y
-                        + (fm.getDescent() * 2));
-      }
-      else
-      {
-        gg.drawLine(((i - startx - 1) * avCharWidth) + (avCharWidth / 2), y
-                + fm.getDescent(), ((i - startx - 1) * avCharWidth)
-                + (avCharWidth / 2), y + (fm.getDescent() * 2));
-      }
-    }
-
+    int y = avCharHeight, yOf = fm.getDescent();
+    y -= yOf;
     if (av.hasHiddenColumns())
     {
+      // draw any hidden column markers
       gg.setColor(Color.blue);
       int res;
       if (av.getShowHiddenMarkers()
@@ -548,14 +518,47 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
             continue;
           }
 
-          gg.fillPolygon(new int[] { res * avCharWidth - avCharHeight / 4,
-              res * avCharWidth + avCharHeight / 4, res * avCharWidth },
-                  new int[] { y - avCharHeight / 2, y - avCharHeight / 2,
-                      y + 8 }, 3);
+          gg.fillPolygon(new int[] {
+              -1 + res * avCharWidth - avCharHeight / 4,
+              -1 + res * avCharWidth + avCharHeight / 4,
+              -1 + res * avCharWidth }, new int[] { y, y, y + 2 * yOf }, 3);
 
         }
       }
+    }
+    // Draw the scale numbers
+    gg.setColor(Color.black);
 
+    int maxX = 0;
+    List<Object[]> marks = jalview.renderer.ScaleRenderer.calculateMarks(
+            av, startx, endx);
+
+    for (Object[] mark : marks)
+    {
+      boolean major = Boolean.valueOf((Boolean) mark[0]);
+      int mpos = ((Integer) mark[1]).intValue(); // (i - startx - 1)
+      String mstring = (String) mark[2];
+      if (mstring != null)
+      {
+        if (mpos * avCharWidth > maxX)
+        {
+          gg.drawString(mstring, mpos * avCharWidth, y);
+          maxX = (mpos + 2) * avCharWidth + fm.stringWidth(mstring);
+        }
+      }
+      if (major)
+      {
+        gg.drawLine((mpos * avCharWidth) + (avCharWidth / 2), y + 2,
+                (mpos * avCharWidth) + (avCharWidth / 2), y + (yOf * 2));
+      }
+      else
+      {
+        gg.drawLine((mpos * avCharWidth) + (avCharWidth / 2), y + yOf,
+                (mpos * avCharWidth) + (avCharWidth / 2), y + (yOf * 2));
+      }
+    }
+    if (av.hasHiddenColumns())
+    {
       if (reveal != null && reveal[0] > startx && reveal[0] < endx)
       {
         gg.drawString(MessageManager.getString("label.reveal_columns"),
@@ -564,4 +567,5 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
     }
 
   }
+
 }
index 0f24b4b..2f7cd76 100755 (executable)
@@ -122,24 +122,26 @@ public class SeqCanvas extends JComponent
   private void drawNorthScale(Graphics g, int startx, int endx, int ypos)
   {
     updateViewport();
-    int scalestartx = startx - (startx % 10) + 10;
-
-    g.setColor(Color.black);
-    // NORTH SCALE
-    for (int i = scalestartx; i < endx; i += 10)
+    for (Object[] mark : jalview.renderer.ScaleRenderer.calculateMarks(av,
+            startx, endx))
     {
-      int value = i;
-      if (av.hasHiddenColumns())
+      int mpos = ((Integer) mark[1]).intValue(); // (i - startx - 1)
+      if (mpos < 0)
       {
-        value = av.getColumnSelection().adjustForHiddenColumns(value);
+        continue;
       }
+      String mstring = (String) mark[2];
 
-      g.drawString(String.valueOf(value), (i - startx - 1) * charWidth,
-              ypos - (charHeight / 2));
-
-      g.drawLine(((i - startx - 1) * charWidth) + (charWidth / 2),
-              (ypos + 2) - (charHeight / 2), ((i - startx - 1) * charWidth)
-                      + (charWidth / 2), ypos - 2);
+      if (Boolean.valueOf((Boolean) mark[0]))
+      {
+        if (mstring != null)
+        {
+          g.drawString(mstring, mpos * charWidth, ypos - (charHeight / 2));
+        }
+        g.drawLine((mpos * charWidth) + (charWidth / 2), (ypos + 2)
+                - (charHeight / 2), (mpos * charWidth) + (charWidth / 2),
+                ypos - 2);
+      }
     }
   }
 
index 3fbb809..2d44a0f 100644 (file)
@@ -1947,10 +1947,12 @@ public class SeqPanel extends JPanel implements MouseListener,
 
     // do we want to thread this ? (contention with seqsel and colsel locks, I
     // suspect)
-    // rules are: colsel is copied if there is a real intersection between
-    // sequence selection
+    /*
+     * only copy colsel if there is a real intersection between
+     * sequence selection and this panel's alignment
+     */
     boolean repaint = false;
-    boolean copycolsel = true;
+    boolean copycolsel = false;
 
     SequenceGroup sgroup = null;
     if (seqsel != null && seqsel.getSize() > 0)
@@ -1964,11 +1966,9 @@ public class SeqPanel extends JPanel implements MouseListener,
       }
       sgroup = seqsel.intersect(av.getAlignment(),
               (av.hasHiddenRows()) ? av.getHiddenRepSequences() : null);
-      if ((sgroup == null || sgroup.getSize() == 0)
-              || (colsel == null || colsel.isEmpty()))
+      if ((sgroup != null && sgroup.getSize() > 0))
       {
-        // don't copy columns if the region didn't intersect.
-        copycolsel = false;
+        copycolsel = true;
       }
     }
     if (sgroup != null && sgroup.getSize() > 0)
@@ -2061,7 +2061,6 @@ public class SeqPanel extends JPanel implements MouseListener,
     ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
             av);
     av.setColumnSelection(cs);
-    av.isColSelChanged(true);
 
     PaintRefresher.Refresh(this, av.getSequenceSetId());
 
index ab78ad3..03bb375 100755 (executable)
@@ -31,6 +31,7 @@ import jalview.fts.service.uniprot.UniprotFTSPanel;
 import jalview.io.gff.SequenceOntologyI;
 import jalview.util.DBRefUtils;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
 import jalview.ws.dbsources.das.api.DasSourceRegistryI;
 import jalview.ws.seqfetcher.DbSourceProxy;
 
@@ -274,13 +275,13 @@ public class SequenceFetcher extends JPanel implements Runnable
 
     frame = new JInternalFrame();
     frame.setContentPane(this);
-    if (new jalview.util.Platform().isAMac())
+    if (Platform.isAMac())
     {
-      Desktop.addInternalFrame(frame, getFrameTitle(), 400, 240);
+      Desktop.addInternalFrame(frame, getFrameTitle(), false, 400, 240);
     }
     else
     {
-      Desktop.addInternalFrame(frame, getFrameTitle(), 400, 180);
+      Desktop.addInternalFrame(frame, getFrameTitle(), false, 400, 180);
     }
   }
 
@@ -365,7 +366,19 @@ public class SequenceFetcher extends JPanel implements Runnable
     jPanel1.add(close);
     jPanel3.add(jPanel2, java.awt.BorderLayout.CENTER);
     jPanel2.setLayout(borderLayout3);
-    databaseButt = database.getDatabaseSelectorButton();
+    databaseButt = /*database.getDatabaseSelectorButton();
+                   final JButton viewdbs =*/new JButton(
+            MessageManager.getString("action.select_ddbb"));
+    databaseButt.addActionListener(new ActionListener()
+    {
+
+      @Override
+      public void actionPerformed(ActionEvent arg0)
+      {
+        hidePanel();
+        database.showDialog();
+      }
+    });
     databaseButt.setFont(JvSwingUtils.getLabelFont());
     database.addActionListener(new ActionListener()
     {
@@ -374,6 +387,12 @@ public class SequenceFetcher extends JPanel implements Runnable
       {
         debounceTrap++;
         String currentSelection = database.getSelectedItem();
+        if (currentSelection == null)
+        {
+          close_actionPerformed(null);
+        }
+
+        showPanel();
 
         if (currentSelection.equalsIgnoreCase("pdb")
                 && (database.action == KeyEvent.VK_ENTER || ((debounceTrap % 2) == 0)))
@@ -407,6 +426,10 @@ public class SequenceFetcher extends JPanel implements Runnable
     this.add(jPanel2, java.awt.BorderLayout.NORTH);
     jScrollPane1.getViewport().add(textArea);
 
+    /*
+     * open the database tree
+     */
+    database.waitForInput();
   }
 
   private void pdbSourceAction()
@@ -538,30 +561,31 @@ 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;
-    ArrayList<String> aresultq = new ArrayList<String>(), presultTitle = new ArrayList<String>();
-    ArrayList<AlignmentI> presult = new ArrayList<AlignmentI>(), aresult = new ArrayList<AlignmentI>();
+    List<String> aresultq = new ArrayList<String>();
+    List<String> presultTitle = new ArrayList<String>();
+    List<AlignmentI> presult = new ArrayList<AlignmentI>();
+    List<AlignmentI> aresult = new ArrayList<AlignmentI>();
     Iterator<DbSourceProxy> proxies = database.getSelectedSources()
             .iterator();
     String[] qries;
-    List<String> nextfetch = Arrays.asList(qries = textArea.getText()
+    List<String> nextFetch = Arrays.asList(qries = textArea.getText()
             .split(";"));
     Iterator<String> en = Arrays.asList(new String[0]).iterator();
     int nqueries = qries.length;
 
     FeatureSettingsModelI preferredFeatureColours = null;
-    while (proxies.hasNext() && (en.hasNext() || nextfetch.size() > 0))
+    while (proxies.hasNext() && (en.hasNext() || nextFetch.size() > 0))
     {
-      if (!en.hasNext() && nextfetch.size() > 0)
+      if (!en.hasNext() && nextFetch.size() > 0)
       {
-        en = nextfetch.iterator();
-        nqueries = nextfetch.size();
+        en = nextFetch.iterator();
+        nqueries = nextFetch.size();
         // save the remaining queries in the original array
-        qries = nextfetch.toArray(new String[nqueries]);
-        nextfetch = new ArrayList<String>();
+        qries = nextFetch.toArray(new String[nqueries]);
+        nextFetch = new ArrayList<String>();
       }
 
       DbSourceProxy proxy = proxies.next();
-      boolean isAliSource = false;
       try
       {
         // update status
@@ -572,122 +596,27 @@ public class SequenceFetcher extends JPanel implements Runnable
                             Integer.valueOf(nqueries).toString(),
                             proxy.getDbName() }), Thread.currentThread()
                         .hashCode());
-        isAliSource = proxy.isAlignmentSource();
         if (proxy.getMaximumQueryCount() == 1)
         {
+          /*
+           * proxy only handles one accession id at a time
+           */
           while (en.hasNext())
           {
-            String item = en.next();
-            try
-            {
-              if (aresult != null)
-              {
-                try
-                {
-                  // give the server a chance to breathe
-                  Thread.sleep(5);
-                } catch (Exception e)
-                {
-                  //
-                }
-
-              }
-
-              AlignmentI indres = null;
-              try
-              {
-                indres = proxy.getSequenceRecords(item);
-              } catch (OutOfMemoryError oome)
-              {
-                new OOMWarning("fetching " + item + " from "
-                        + proxy.getDbName(), oome, this);
-              }
-              if (indres != null)
-              {
-                aresultq.add(item);
-                aresult.add(indres);
-              }
-              else
-              {
-                nextfetch.add(item);
-              }
-            } catch (Exception e)
+            String acc = en.next();
+            if (!fetchSingleAccession(proxy, acc, aresultq, aresult))
             {
-              Cache.log.info(
-                      "Error retrieving " + item
-                      + " from " + proxy.getDbName(), e);
-              nextfetch.add(item);
+              nextFetch.add(acc);
             }
           }
         }
         else
         {
-          StringBuffer multiacc = new StringBuffer();
-          ArrayList<String> tosend = new ArrayList<String>();
-          while (en.hasNext())
-          {
-            String nel = en.next();
-            tosend.add(nel);
-            multiacc.append(nel);
-            if (en.hasNext())
-            {
-              multiacc.append(proxy.getAccessionSeparator());
-            }
-          }
-          try
-          {
-            AlignmentI rslt;
-            SequenceI[] rs;
-            List<String> nores = new ArrayList<String>();
-            rslt = proxy.getSequenceRecords(multiacc.toString());
-            if (rslt == null || rslt.getHeight() == 0)
-            {
-              // no results - pass on all queries to next source
-              nextfetch.addAll(tosend);
-            }
-            else
-            {
-              aresultq.add(multiacc.toString());
-              aresult.add(rslt);
-
-              rs = rslt.getSequencesArray();
-              // search for each query in the dbrefs associated with each
-              // sequence
-              // returned.
-              // ones we do not find will be used to query next source (if any)
-              for (String q : tosend)
-              {
-                DBRefEntry dbr = new DBRefEntry(), found[] = null;
-                dbr.setSource(proxy.getDbSource());
-                dbr.setVersion(null);
-                String accId = proxy.getAccessionIdFromQuery(q);
-                dbr.setAccessionId(accId);
-                boolean rfound = false;
-                for (int r = 0; r < rs.length; r++)
-                {
-                  if (rs[r] != null)
-                  {
-                    found = DBRefUtils.searchRefs(rs[r].getDBRefs(), accId);
-                    if (found != null && found.length > 0)
-                    {
-                      rfound = true;
-                      rs[r] = null;
-                    }
-                  }
-                }
-                if (!rfound)
-                {
-                  nextfetch.add(q);
-                }
-              }
-            }
-          } catch (OutOfMemoryError oome)
-          {
-            new OOMWarning("fetching " + multiacc + " from "
-                    + database.getSelectedItem(), oome, this);
-          }
+          /*
+           * proxy can fetch multiple accessions at one time
+           */
+          fetchMultipleAccessions(proxy, en, aresultq, aresult, nextFetch);
         }
-
       } catch (Exception e)
       {
         showErrorMessage("Error retrieving " + textArea.getText()
@@ -700,7 +629,6 @@ public class SequenceFetcher extends JPanel implements Runnable
         e.printStackTrace();
       } catch (OutOfMemoryError e)
       {
-        // resets dialog box - so we don't use OOMwarning here.
         showErrorMessage("Out of Memory when retrieving "
                 + textArea.getText()
                 + " from "
@@ -713,6 +641,7 @@ public class SequenceFetcher extends JPanel implements Runnable
                 + " from " + database.getSelectedItem());
         e.printStackTrace();
       }
+
       // Stack results ready for opening in alignment windows
       if (aresult != null && aresult.size() > 0)
       {
@@ -724,7 +653,7 @@ public class SequenceFetcher extends JPanel implements Runnable
         }
 
         AlignmentI ar = null;
-        if (isAliSource)
+        if (proxy.isAlignmentSource())
         {
           addToLast = false;
           // new window for each result
@@ -754,7 +683,6 @@ public class SequenceFetcher extends JPanel implements Runnable
             {
               ar.append(aresult.remove(0));
             }
-            ;
           }
           addToLast = true;
           presult.add(ar);
@@ -778,14 +706,14 @@ public class SequenceFetcher extends JPanel implements Runnable
     }
     // only remove visual delay after we finished parsing.
     guiWindow.setProgressBar(null, Thread.currentThread().hashCode());
-    if (nextfetch.size() > 0)
+    if (nextFetch.size() > 0)
     {
       StringBuffer sb = new StringBuffer();
       sb.append("Didn't retrieve the following "
-              + (nextfetch.size() == 1 ? "query" : nextfetch.size()
+              + (nextFetch.size() == 1 ? "query" : nextFetch.size()
                       + " queries") + ": \n");
       int l = sb.length(), lr = 0;
-      for (String s : nextfetch)
+      for (String s : nextFetch)
       {
         if (l != sb.length())
         {
@@ -803,6 +731,161 @@ public class SequenceFetcher extends JPanel implements Runnable
   }
 
   /**
+   * Tries to fetch one or more accession ids from the database proxy
+   * 
+   * @param proxy
+   * @param accessions
+   *          the queries to fetch
+   * @param aresultq
+   *          a successful queries list to add to
+   * @param aresult
+   *          a list of retrieved alignments to add to
+   * @param nextFetch
+   *          failed queries are added to this list
+   * @throws Exception
+   */
+  void fetchMultipleAccessions(DbSourceProxy proxy,
+          Iterator<String> accessions, List<String> aresultq,
+          List<AlignmentI> aresult, List<String> nextFetch)
+          throws Exception
+  {
+    StringBuilder multiacc = new StringBuilder();
+    List<String> tosend = new ArrayList<String>();
+    while (accessions.hasNext())
+    {
+      String nel = accessions.next();
+      tosend.add(nel);
+      multiacc.append(nel);
+      if (accessions.hasNext())
+      {
+        multiacc.append(proxy.getAccessionSeparator());
+      }
+    }
+
+    try
+    {
+      String query = multiacc.toString();
+      AlignmentI rslt = proxy.getSequenceRecords(query);
+      if (rslt == null || rslt.getHeight() == 0)
+      {
+        // no results - pass on all queries to next source
+        nextFetch.addAll(tosend);
+      }
+      else
+      {
+        aresultq.add(query);
+        aresult.add(rslt);
+        if (tosend.size() > 1)
+        {
+          checkResultForQueries(rslt, tosend, nextFetch, proxy);
+        }
+      }
+    } catch (OutOfMemoryError oome)
+    {
+      new OOMWarning("fetching " + multiacc + " from "
+              + database.getSelectedItem(), oome, this);
+    }
+  }
+
+  /**
+   * Query for a single accession id via the database proxy
+   * 
+   * @param proxy
+   * @param accession
+   * @param aresultq
+   *          a list of successful queries to add to
+   * @param aresult
+   *          a list of retrieved alignments to add to
+   * @return true if the fetch was successful, else false
+   */
+  boolean fetchSingleAccession(DbSourceProxy proxy, String accession,
+          List<String> aresultq, List<AlignmentI> aresult)
+  {
+    boolean success = false;
+    try
+    {
+      if (aresult != null)
+      {
+        try
+        {
+          // give the server a chance to breathe
+          Thread.sleep(5);
+        } catch (Exception e)
+        {
+          //
+        }
+      }
+
+      AlignmentI indres = null;
+      try
+      {
+        indres = proxy.getSequenceRecords(accession);
+      } catch (OutOfMemoryError oome)
+      {
+        new OOMWarning("fetching " + accession + " from "
+                + proxy.getDbName(), oome, this);
+      }
+      if (indres != null)
+      {
+        aresultq.add(accession);
+        aresult.add(indres);
+        success = true;
+      }
+    } catch (Exception e)
+    {
+      Cache.log.info(
+              "Error retrieving " + accession
+              + " from " + proxy.getDbName(), e);
+    } finally
+    {
+      return success;
+    }
+  }
+
+  /**
+   * Checks which of the queries were successfully retrieved by searching the
+   * DBRefs of the retrieved sequences for a match. Any not found are added to
+   * the 'nextFetch' list.
+   * 
+   * @param rslt
+   * @param queries
+   * @param nextFetch
+   * @param proxy
+   */
+  void checkResultForQueries(AlignmentI rslt, List<String> queries,
+          List<String> nextFetch, DbSourceProxy proxy)
+  {
+    SequenceI[] rs = rslt.getSequencesArray();
+
+    for (String q : queries)
+    {
+      DBRefEntry[] found = null;
+      DBRefEntry dbr = new DBRefEntry();
+      dbr.setSource(proxy.getDbSource());
+      dbr.setVersion(null);
+      String accId = proxy.getAccessionIdFromQuery(q);
+      dbr.setAccessionId(accId);
+      boolean rfound = false;
+      for (int r = 0; r < rs.length; r++)
+      {
+        if (rs[r] != null)
+        {
+          found = DBRefUtils.searchRefs(rs[r].getDBRefs(), accId);
+          if (found != null && found.length > 0)
+          {
+            rfound = true;
+            break;
+          }
+        }
+      }
+      if (!rfound)
+      {
+        nextFetch.add(q);
+      }
+    }
+  }
+
+  /**
    * 
    * @return a standard title for any results retrieved using the currently
    *         selected source and settings
@@ -859,7 +942,7 @@ public class SequenceFetcher extends JPanel implements Runnable
         }
         if (Cache.getDefault("HIDE_INTRONS", true))
         {
-          hideIntronsIfPresent(af);
+          af.hideFeatureColumns(SequenceOntologyI.EXON, false);
         }
 
         Desktop.addInternalFrame(af, title, AlignFrame.DEFAULT_WIDTH,
@@ -884,25 +967,6 @@ public class SequenceFetcher extends JPanel implements Runnable
     return al;
   }
 
-  /**
-   * Hide columns not containing 'exon' features, provided there are exon
-   * features on the alignment
-   * 
-   * @param af
-   */
-  public void hideIntronsIfPresent(AlignFrame af)
-  {
-    boolean hasExons = af.avc.markColumnsContainingFeatures(false, false,
-            false,
-            SequenceOntologyI.EXON);
-    if (hasExons)
-    {
-      af.avc.markColumnsContainingFeatures(true, false, true,
-              SequenceOntologyI.EXON);
-      af.getViewport().hideSelectedColumns();
-    }
-  }
-
   void showErrorMessage(final String error)
   {
     resetDialog();
@@ -927,4 +991,22 @@ public class SequenceFetcher extends JPanel implements Runnable
   {
     this.progressIndicator = progressIndicator;
   }
+
+  /**
+   * Make this panel visible (after a selection has been made in the database
+   * chooser)
+   */
+  void showPanel()
+  {
+    frame.setVisible(true);
+  }
+
+  /**
+   * Hide this panel (on clicking the database button to open the database
+   * chooser)
+   */
+  void hidePanel()
+  {
+    frame.setVisible(false);
+  }
 }
index d924e73..fd2de8e 100644 (file)
@@ -35,6 +35,7 @@ import jalview.fts.service.pdb.PDBFTSRestClient;
 import jalview.jbgui.GStructureChooser;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
+import jalview.ws.DBRefFetcher;
 import jalview.ws.sifts.SiftsSettings;
 
 import java.awt.event.ItemEvent;
@@ -147,8 +148,8 @@ public class StructureChooser extends GStructureChooser implements
   {
     long startTime = System.currentTimeMillis();
     pdbRestCleint = PDBFTSRestClient.getInstance();
-    Collection<FTSDataColumnI> wantedFields = pdbRestCleint
-            .getAllDefaulDisplayedDataColumns();
+    Collection<FTSDataColumnI> wantedFields = pdbDocFieldPrefs
+            .getStructureSummaryFields();
 
     discoveredStructuresSet = new LinkedHashSet<FTSData>();
     HashSet<String> errors = new HashSet<String>();
@@ -185,7 +186,8 @@ public class StructureChooser extends GStructureChooser implements
     if (discoveredStructuresSet != null
             && !discoveredStructuresSet.isEmpty())
     {
-      tbl_summary.setModel(FTSRestResponse.getTableModel(lastPdbRequest,
+      getResultTable().setModel(
+              FTSRestResponse.getTableModel(lastPdbRequest,
               discoveredStructuresSet));
       structuresDiscovered = true;
       noOfStructuresFound = discoveredStructuresSet.size();
@@ -330,17 +332,17 @@ public class StructureChooser extends GStructureChooser implements
   }
 
   /**
-   * Remove the following special characters from input string +, -, &, |, !, (,
-   * ), {, }, [, ], ^, ", ~, *, ?, :, \
+   * Remove the following special characters from input string +, -, &, !, (, ),
+   * {, }, [, ], ^, ", ~, *, ?, :, \
    * 
    * @param seqName
    * @return
    */
-  private static String sanitizeSeqName(String seqName)
+  static String sanitizeSeqName(String seqName)
   {
     Objects.requireNonNull(seqName);
     return seqName.replaceAll("\\[\\d*\\]", "")
-            .replaceAll("[^\\dA-Za-z|]", "").replaceAll("\\s+", "+");
+            .replaceAll("[^\\dA-Za-z|_]", "").replaceAll("\\s+", "+");
   }
 
 
@@ -396,8 +398,8 @@ public class StructureChooser extends GStructureChooser implements
         long startTime = System.currentTimeMillis();
         pdbRestCleint = PDBFTSRestClient.getInstance();
         lbl_loading.setVisible(true);
-        Collection<FTSDataColumnI> wantedFields = pdbRestCleint
-                .getAllDefaulDisplayedDataColumns();
+        Collection<FTSDataColumnI> wantedFields = pdbDocFieldPrefs
+                .getStructureSummaryFields();
         Collection<FTSData> filteredResponse = new HashSet<FTSData>();
         HashSet<String> errors = new HashSet<String>();
 
@@ -406,7 +408,6 @@ public class StructureChooser extends GStructureChooser implements
           FTSRestRequest pdbRequest = new FTSRestRequest();
           if (fieldToFilterBy.equalsIgnoreCase("uniprot_coverage"))
           {
-            System.out.println(">>>>>> Filtering with uniprot coverate");
             pdbRequest.setAllowEmptySeq(false);
             pdbRequest.setResponseSize(1);
             pdbRequest.setFieldToSearchBy("(");
@@ -454,15 +455,18 @@ public class StructureChooser extends GStructureChooser implements
           Collection<FTSData> reorderedStructuresSet = new LinkedHashSet<FTSData>();
           reorderedStructuresSet.addAll(filteredResponse);
           reorderedStructuresSet.addAll(discoveredStructuresSet);
-          tbl_summary.setModel(FTSRestResponse.getTableModel(
+          getResultTable().setModel(
+                  FTSRestResponse.getTableModel(
                   lastPdbRequest, reorderedStructuresSet));
 
-          FTSRestResponse.configureTableColumn(tbl_summary, wantedFields);
-          tbl_summary.getColumn("Ref Sequence").setPreferredWidth(120);
-          tbl_summary.getColumn("Ref Sequence").setMinWidth(100);
-          tbl_summary.getColumn("Ref Sequence").setMaxWidth(200);
+          FTSRestResponse.configureTableColumn(getResultTable(),
+                  wantedFields);
+          getResultTable().getColumn("Ref Sequence").setPreferredWidth(120);
+          getResultTable().getColumn("Ref Sequence").setMinWidth(100);
+          getResultTable().getColumn("Ref Sequence").setMaxWidth(200);
           // Update table selection model here
-          tbl_summary.addRowSelectionInterval(0, filterResponseCount - 1);
+          getResultTable().addRowSelectionInterval(0,
+                  filterResponseCount - 1);
           mainFrame.setTitle(MessageManager.formatMessage(
                   "label.structure_chooser_filter_time", totalTime));
         }
@@ -529,8 +533,6 @@ public class StructureChooser extends GStructureChooser implements
     {
       cmb_filterOption.addItem(new FilterOption("Best Quality",
               "overall_quality", VIEWS_FILTER));
-      cmb_filterOption.addItem(new FilterOption("Most UniProt Coverage",
-              "uniprot_coverage", VIEWS_FILTER));
       cmb_filterOption.addItem(new FilterOption("Best Resolution",
               "resolution", VIEWS_FILTER));
       cmb_filterOption.addItem(new FilterOption("Most Protein Chain",
@@ -591,7 +593,7 @@ public class StructureChooser extends GStructureChooser implements
     String currentView = selectedFilterOpt.getView();
     if (currentView == VIEWS_FILTER)
     {
-      if (tbl_summary.getSelectedRows().length > 0)
+      if (getResultTable().getSelectedRows().length > 0)
       {
         btn_view.setEnabled(true);
       }
@@ -729,19 +731,21 @@ public class StructureChooser extends GStructureChooser implements
     String currentView = selectedFilterOpt.getView();
     if (currentView == VIEWS_FILTER)
     {
-          int pdbIdColIndex = tbl_summary.getColumn("PDB Id")
+          int pdbIdColIndex = getResultTable().getColumn("PDB Id")
                   .getModelIndex();
-      int refSeqColIndex = tbl_summary.getColumn("Ref Sequence")
+          int refSeqColIndex = getResultTable().getColumn("Ref Sequence")
               .getModelIndex();
-      int[] selectedRows = tbl_summary.getSelectedRows();
+          int[] selectedRows = getResultTable().getSelectedRows();
       PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
       int count = 0;
       ArrayList<SequenceI> selectedSeqsToView = new ArrayList<SequenceI>();
       for (int row : selectedRows)
       {
-        String pdbIdStr = tbl_summary.getValueAt(row, pdbIdColIndex)
+            String pdbIdStr = getResultTable().getValueAt(row,
+                    pdbIdColIndex)
                 .toString();
-        SequenceI selectedSeq = (SequenceI) tbl_summary.getValueAt(row,
+            SequenceI selectedSeq = (SequenceI) getResultTable()
+                    .getValueAt(row,
                 refSeqColIndex);
         selectedSeqsToView.add(selectedSeq);
             PDBEntry pdbEntry = selectedSeq.getPDBEntry(pdbIdStr);
@@ -800,6 +804,10 @@ public class StructureChooser extends GStructureChooser implements
       if (pdbEntry == null)
       {
         pdbEntry = new PDBEntry();
+            if (pdbIdStr.split(":").length > 1)
+            {
+              pdbEntry.setChainCode(pdbIdStr.split(":")[1]);
+            }
         pdbEntry.setId(pdbIdStr);
         pdbEntry.setType(PDBEntry.Type.PDB);
         selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
@@ -849,42 +857,58 @@ public class StructureChooser extends GStructureChooser implements
           final PDBEntry[] pdbEntriesToView,
           final AlignmentPanel alignPanel, SequenceI[] sequences)
   {
-    ssm.setProgressBar("Launching PDB structure viewer..");
+    ssm.setProgressBar(MessageManager
+            .getString("status.launching_3d_structure_viewer"));
     final StructureViewer sViewer = new StructureViewer(ssm);
 
     if (SiftsSettings.isMapWithSifts())
     {
+      ArrayList<SequenceI> seqsWithoutSourceDBRef = new ArrayList<SequenceI>();
       for (SequenceI seq : sequences)
       {
-        if (seq.getSourceDBRef() == null)
+        if (seq.getSourceDBRef() == null && seq.getDBRefs() == null)
         {
-          ssm.setProgressBar(null);
-          ssm.setProgressBar("Fetching Database refs..");
-          new jalview.ws.DBRefFetcher(sequences, null, null, null, false)
-                  .fetchDBRefs(true);
-          break;
+            seqsWithoutSourceDBRef.add(seq);
+            continue;
+          }
+      }
+      if (!seqsWithoutSourceDBRef.isEmpty())
+      {
+        int y = seqsWithoutSourceDBRef.size();
+        ssm.setProgressBar(null);
+        ssm.setProgressBar(MessageManager.formatMessage(
+                "status.fetching_dbrefs_for_sequences_without_valid_refs",
+                y));
+        SequenceI[] seqWithoutSrcDBRef = new SequenceI[y];
+        int x = 0;
+        for (SequenceI fSeq : seqsWithoutSourceDBRef)
+        {
+          seqWithoutSrcDBRef[x++] = fSeq;
         }
+        new DBRefFetcher(seqWithoutSrcDBRef).fetchDBRefs(true);
       }
     }
-        if (pdbEntriesToView.length > 1)
-        {
-          ArrayList<SequenceI[]> seqsMap = new ArrayList<SequenceI[]>();
-          for (SequenceI seq : sequences)
-          {
-            seqsMap.add(new SequenceI[] { seq });
-          }
-          SequenceI[][] collatedSeqs = seqsMap.toArray(new SequenceI[0][0]);
+    if (pdbEntriesToView.length > 1)
+    {
+      ArrayList<SequenceI[]> seqsMap = new ArrayList<SequenceI[]>();
+      for (SequenceI seq : sequences)
+      {
+        seqsMap.add(new SequenceI[] { seq });
+      }
+      SequenceI[][] collatedSeqs = seqsMap.toArray(new SequenceI[0][0]);
       ssm.setProgressBar(null);
-      ssm.setProgressBar("Fetching PDB Structures for selected entries..");
-          sViewer.viewStructures(pdbEntriesToView, collatedSeqs, alignPanel);
-        }
-        else
-        {
+      ssm.setProgressBar(MessageManager
+              .getString("status.fetching_3d_structures_for_selected_entries"));
+      sViewer.viewStructures(pdbEntriesToView, collatedSeqs, alignPanel);
+    }
+    else
+    {
       ssm.setProgressBar(null);
-      ssm.setProgressBar("Fetching PDB Structure for "
-              + pdbEntriesToView[0].getId());
-          sViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
-        }
+      ssm.setProgressBar(MessageManager.formatMessage(
+              "status.fetching_3d_structures_for",
+              pdbEntriesToView[0].getId()));
+      sViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
+    }
   }
 
   /**
@@ -943,6 +967,9 @@ public class StructureChooser extends GStructureChooser implements
         isValidPBDEntry = false;
         if (txt_search.getText().length() > 0)
         {
+          String searchTerm = txt_search.getText().toLowerCase();
+          searchTerm = searchTerm.split(":")[0];
+          // System.out.println(">>>>> search term : " + searchTerm);
           List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
           FTSRestRequest pdbRequest = new FTSRestRequest();
           pdbRequest.setAllowEmptySeq(false);
@@ -950,7 +977,7 @@ public class StructureChooser extends GStructureChooser implements
           pdbRequest.setFieldToSearchBy("(pdb_id:");
           pdbRequest.setWantedFields(wantedFields);
           pdbRequest
-                  .setSearchTerm(txt_search.getText().toLowerCase() + ")");
+.setSearchTerm(searchTerm + ")");
           pdbRequest.setAssociatedSequence(selectedSequence);
           pdbRestCleint = PDBFTSRestClient.getInstance();
           wantedFields.add(pdbRestCleint.getPrimaryKeyColumn());
index 6bac6df..f1c6768 100644 (file)
@@ -72,7 +72,7 @@ public class TextColourChooser
     final JPanel col2 = new JPanel();
     col2.setPreferredSize(new Dimension(40, 20));
     col2.setBorder(BorderFactory.createEtchedBorder());
-    col2.setToolTipText(MessageManager.getString("label.ligth_colour"));
+    col2.setToolTipText(MessageManager.getString("label.light_colour"));
     col2.setBackground(new Color(original2));
     final JPanel bigpanel = new JPanel(new BorderLayout());
     JPanel panel = new JPanel();
@@ -89,6 +89,7 @@ public class TextColourChooser
 
     col1.addMouseListener(new MouseAdapter()
     {
+      @Override
       public void mousePressed(MouseEvent e)
       {
         Color col = JColorChooser.showDialog(bigpanel,
@@ -104,6 +105,7 @@ public class TextColourChooser
 
     col2.addMouseListener(new MouseAdapter()
     {
+      @Override
       public void mousePressed(MouseEvent e)
       {
         Color col = JColorChooser.showDialog(bigpanel,
@@ -119,6 +121,7 @@ public class TextColourChooser
 
     slider.addChangeListener(new ChangeListener()
     {
+      @Override
       public void stateChanged(ChangeEvent evt)
       {
         thresholdChanged(slider.getValue());
index 9522144..d78350d 100755 (executable)
@@ -161,6 +161,7 @@ public class TreePanel extends GTreePanel
 
     av.addPropertyChangeListener(new java.beans.PropertyChangeListener()
     {
+      @Override
       public void propertyChange(PropertyChangeEvent evt)
       {
         if (evt.getPropertyName().equals("alignment"))
@@ -196,6 +197,7 @@ public class TreePanel extends GTreePanel
 
   }
 
+  @Override
   public void viewMenu_menuSelected()
   {
     buildAssociatedViewMenu();
@@ -231,6 +233,7 @@ public class TreePanel extends GTreePanel
       buttonGroup.add(item);
       item.addActionListener(new ActionListener()
       {
+        @Override
         public void actionPerformed(ActionEvent evt)
         {
           treeCanvas.applyToAllViews = false;
@@ -249,6 +252,7 @@ public class TreePanel extends GTreePanel
     itemf.setSelected(treeCanvas.applyToAllViews);
     itemf.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent evt)
       {
         treeCanvas.applyToAllViews = itemf.isSelected();
@@ -276,6 +280,7 @@ public class TreePanel extends GTreePanel
       }
     }
 
+    @Override
     public void run()
     {
 
@@ -389,6 +394,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void textbox_actionPerformed(ActionEvent e)
   {
     CutAndPasteTransfer cap = new CutAndPasteTransfer();
@@ -434,6 +440,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void saveAsNewick_actionPerformed(ActionEvent e)
   {
     JalviewFileChooser chooser = new JalviewFileChooser(
@@ -474,12 +481,14 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void printMenu_actionPerformed(ActionEvent e)
   {
     // Putting in a thread avoids Swing painting problems
     treeCanvas.startPrinting();
   }
 
+  @Override
   public void originalSeqData_actionPerformed(ActionEvent e)
   {
     if (!tree.hasOriginalSequenceData())
@@ -547,6 +556,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void fitToWindow_actionPerformed(ActionEvent e)
   {
     treeCanvas.fitToWindow = fitToWindow.isSelected();
@@ -637,6 +647,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void font_actionPerformed(ActionEvent e)
   {
     if (treeCanvas == null)
@@ -666,6 +677,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void distanceMenu_actionPerformed(ActionEvent e)
   {
     treeCanvas.setShowDistances(distanceMenu.isSelected());
@@ -677,6 +689,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void bootstrapMenu_actionPerformed(ActionEvent e)
   {
     treeCanvas.setShowBootstrap(bootstrapMenu.isSelected());
@@ -688,6 +701,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void placeholdersMenu_actionPerformed(ActionEvent e)
   {
     treeCanvas.setMarkPlaceholders(placeholdersMenu.isSelected());
@@ -699,6 +713,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void epsTree_actionPerformed(ActionEvent e)
   {
     boolean accurateText = true;
@@ -772,6 +787,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void pngTree_actionPerformed(ActionEvent e)
   {
     int width = treeCanvas.getWidth();
@@ -828,6 +844,7 @@ public class TreePanel extends GTreePanel
     tree.applyToNodes(new NodeTransformI()
     {
 
+      @Override
       public void transform(BinaryNode node)
       {
         if (node instanceof SequenceNode
index 2dd5f26..372d905 100755 (executable)
@@ -842,12 +842,12 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
         features = sequences[i].getSequenceFeatures();
         if (features != null)
         {
-          for (int j = 0; j < features.length; j++)
+          for (SequenceFeature sequenceFeature : features)
           {
-            isnonpos = features[j].begin == 0 && features[j].end == 0;
+            isnonpos = sequenceFeature.begin == 0 && sequenceFeature.end == 0;
             if ((!nonpos && isnonpos)
                     || (!isnonpos && visOnly && !visible
-                            .containsKey(features[j].type)))
+                            .containsKey(sequenceFeature.type)))
             {
               // skip if feature is nonpos and we ignore them or if we only
               // output visible and it isn't non-pos and it's not visible
@@ -855,47 +855,48 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
             }
 
             if (group != null
-                    && (features[j].featureGroup == null || !features[j].featureGroup
+                    && (sequenceFeature.featureGroup == null || !sequenceFeature.featureGroup
                             .equals(group)))
             {
               continue;
             }
 
-            if (group == null && features[j].featureGroup != null)
+            if (group == null && sequenceFeature.featureGroup != null)
             {
               continue;
             }
             // we have features to output
             featuresGen = true;
-            if (features[j].description == null
-                    || features[j].description.equals(""))
+            if (sequenceFeature.description == null
+                    || sequenceFeature.description.equals(""))
             {
-              out.append(features[j].type).append(TAB);
+              out.append(sequenceFeature.type).append(TAB);
             }
             else
             {
-              if (features[j].links != null
-                      && features[j].getDescription().indexOf("<html>") == -1)
+              if (sequenceFeature.links != null
+                      && sequenceFeature.getDescription().indexOf("<html>") == -1)
               {
                 out.append("<html>");
               }
 
-              out.append(features[j].description + " ");
-              if (features[j].links != null)
+              out.append(sequenceFeature.description);
+              if (sequenceFeature.links != null)
               {
-                for (int l = 0; l < features[j].links.size(); l++)
+                for (int l = 0; l < sequenceFeature.links.size(); l++)
                 {
-                  String label = features[j].links.elementAt(l).toString();
+                  String label = sequenceFeature.links.elementAt(l);
                   String href = label.substring(label.indexOf("|") + 1);
                   label = label.substring(0, label.indexOf("|"));
 
-                  if (features[j].description.indexOf(href) == -1)
+                  if (sequenceFeature.description.indexOf(href) == -1)
                   {
-                    out.append("<a href=\"" + href + "\">" + label + "</a>");
+                    out.append(" <a href=\"" + href + "\">" + label
+                            + "</a>");
                   }
                 }
 
-                if (features[j].getDescription().indexOf("</html>") == -1)
+                if (sequenceFeature.getDescription().indexOf("</html>") == -1)
                 {
                   out.append("</html>");
                 }
@@ -905,15 +906,15 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
             }
             out.append(sequences[i].getName());
             out.append("\t-1\t");
-            out.append(features[j].begin);
+            out.append(sequenceFeature.begin);
             out.append(TAB);
-            out.append(features[j].end);
+            out.append(sequenceFeature.end);
             out.append(TAB);
-            out.append(features[j].type);
-            if (!Float.isNaN(features[j].score))
+            out.append(sequenceFeature.type);
+            if (!Float.isNaN(sequenceFeature.score))
             {
               out.append(TAB);
-              out.append(features[j].score);
+              out.append(sequenceFeature.score);
             }
             out.append(newline);
           }
@@ -1024,7 +1025,8 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
           boolean includeNonPositionalFeatures)
   {
     StringBuilder out = new StringBuilder(256);
-    out.append(String.format("%s %d\n", GFF_VERSION, gffVersion));
+    int version = gffVersion == 0 ? 2 : gffVersion;
+    out.append(String.format("%s %d\n", GFF_VERSION, version));
     String source;
     boolean isnonpos;
     for (SequenceI seq : sequences)
index e554b8e..4e1b261 100644 (file)
@@ -51,6 +51,13 @@ public class HtmlSvgOutput
 
   AlignmentPanel ap;
 
+  private IProgressIndicator pIndicator;
+
+  private long pSessionId;
+
+  private boolean headless;
+
+
   public HtmlSvgOutput(File file, AlignmentPanel ap)
   {
     this.av = ap.av;
@@ -61,20 +68,16 @@ public class HtmlSvgOutput
 
   public void generateHtmlSvgOutput(File file)
   {
-    IProgressIndicator pIndicator = ap.alignFrame;
-    long pSessionId = System.currentTimeMillis();
+    pIndicator = ap.alignFrame;
+    pSessionId = System.currentTimeMillis();
     try
     {
-      boolean headless = (System.getProperty("java.awt.headless") != null && System
+      headless = (System.getProperty("java.awt.headless") != null && System
               .getProperty("java.awt.headless").equals("true"));
       if (file == null)
       {
-        if (pIndicator != null && !headless)
-        {
-          pIndicator.setProgressBar(MessageManager.formatMessage(
-                  "status.waiting_for_user_to_select_output_file", "HTML"),
-                  pSessionId);
-        }
+        setProgressMessage(MessageManager.formatMessage(
+                "status.waiting_for_user_to_select_output_file", "HTML"));
         JalviewFileChooser chooser = getHTMLChooser();
         chooser.setFileView(new jalview.io.JalviewFileView());
         chooser.setDialogTitle(ap.alignFrame.getTitle());
@@ -86,135 +89,164 @@ public class HtmlSvgOutput
           jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
                   .getSelectedFile().getParent());
           file = chooser.getSelectedFile();
+          ap.alignFrame.repaint();
         }
         else
         {
-
-          if (pIndicator != null && !headless)
-        {
-            pIndicator.setProgressBar(MessageManager.formatMessage(
-                    "status.cancelled_image_export_operation", "HTML"),
-                    pSessionId);
-          }
+          setProgressMessage(MessageManager.formatMessage(
+                  "status.cancelled_image_export_operation", "HTML"));
           return;
         }
       }
-
-      AlignmentDimension aDimension = ap.getAlignmentDimension();
-      SVGGraphics2D g1 = new SVGGraphics2D(aDimension.getWidth(),
-              aDimension.getHeight());
-      SVGGraphics2D g2 = new SVGGraphics2D(aDimension.getWidth(),
-              aDimension.getHeight());
-
-      String renderStyle = jalview.bin.Cache.getDefault("HTML_RENDERING",
-              "Prompt each time");
-
-      // If we need to prompt, and if the GUI is visible then
-      // Prompt for rendering style
-      if (renderStyle.equalsIgnoreCase("Prompt each time")
-              && !(System.getProperty("java.awt.headless") != null && System
-                      .getProperty("java.awt.headless").equals("true")))
-      {
-        HTMLOptions svgOption = new HTMLOptions();
-        renderStyle = svgOption.getValue();
-
-        if (renderStyle == null || svgOption.cancelled)
-        {
-          return;
-        }
-      }
-
-      if (renderStyle.equalsIgnoreCase("lineart"))
-      {
-        g1.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
-                SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
-        g2.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
-                SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
-      }
-      printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), 0, g1,
-              g2);
-
-      String titleSvgData = g1.getSVGDocument();
-      String alignSvgData = g2.getSVGDocument();
-      String jsonData = null;
-      boolean isEmbbedBioJSON = Boolean.valueOf(jalview.bin.Cache
-              .getDefault("EXPORT_EMBBED_BIOJSON", "true"));
-      if (isEmbbedBioJSON)
+    } catch (Exception e)
+    {
+      pIndicator.setProgressBar(MessageManager.formatMessage(
+              "info.error_creating_file", "HTML"), pSessionId);
+      e.printStackTrace();
+      return;
+    }
+    final File fileX = file;
+    new Thread()
+    {
+      @Override
+      public void run()
       {
-        AlignExportSettingI exportSettings = new AlignExportSettingI()
+        try
         {
-          @Override
-          public boolean isExportHiddenSequences()
+          setProgressMessage(null);
+          setProgressMessage(MessageManager
+.formatMessage(
+                  "status.exporting_alignment_as_x_file", "HTML"));
+          AlignmentDimension aDimension = ap.getAlignmentDimension();
+          SVGGraphics2D g1 = new SVGGraphics2D(aDimension.getWidth(),
+                  aDimension.getHeight());
+          SVGGraphics2D g2 = new SVGGraphics2D(aDimension.getWidth(),
+                  aDimension.getHeight());
+
+          String renderStyle = jalview.bin.Cache.getDefault(
+                  "HTML_RENDERING", "Prompt each time");
+
+          // If we need to prompt, and if the GUI is visible then
+          // Prompt for rendering style
+          if (renderStyle.equalsIgnoreCase("Prompt each time")
+                  && !(System.getProperty("java.awt.headless") != null && System
+                          .getProperty("java.awt.headless").equals("true")))
           {
-            return true;
+            HTMLOptions svgOption = new HTMLOptions();
+            renderStyle = svgOption.getValue();
+
+            if (renderStyle == null || svgOption.cancelled)
+            {
+              setProgressMessage(MessageManager.formatMessage(
+                      "status.cancelled_image_export_operation", "HTML"));
+              return;
+            }
           }
 
-          @Override
-          public boolean isExportHiddenColumns()
+          if (renderStyle.equalsIgnoreCase("Lineart"))
           {
-            return true;
+            g1.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
+                    SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
+            g2.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
+                    SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
           }
-
-          @Override
-          public boolean isExportAnnotations()
+          printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), 0,
+                  g1, g2);
+
+          String titleSvgData = g1.getSVGDocument();
+          String alignSvgData = g2.getSVGDocument();
+          String jsonData = null;
+          boolean isEmbbedBioJSON = Boolean.valueOf(jalview.bin.Cache
+                  .getDefault("EXPORT_EMBBED_BIOJSON", "true"));
+          if (isEmbbedBioJSON)
           {
-            return true;
+            AlignExportSettingI exportSettings = new AlignExportSettingI()
+            {
+              @Override
+              public boolean isExportHiddenSequences()
+              {
+                return true;
+              }
+
+              @Override
+              public boolean isExportHiddenColumns()
+              {
+                return true;
+              }
+
+              @Override
+              public boolean isExportAnnotations()
+              {
+                return true;
+              }
+
+              @Override
+              public boolean isExportFeatures()
+              {
+                return true;
+              }
+
+              @Override
+              public boolean isExportGroups()
+              {
+                return true;
+              }
+
+              @Override
+              public boolean isCancelled()
+              {
+                return false;
+              }
+
+            };
+            AlignmentExportData exportData = jalview.gui.AlignFrame
+                    .getAlignmentForExport(JSONFile.FILE_DESC, av,
+                            exportSettings);
+            jsonData = new FormatAdapter(ap, exportData.getSettings())
+                    .formatSequences(JSONFile.FILE_DESC,
+                            exportData.getAlignment(),
+                            exportData.getOmitHidden(),
+                            exportData.getStartEndPostions(),
+                            av.getColumnSelection());
           }
-
-          @Override
-          public boolean isExportFeatures()
-          {
-            return true;
-          }
-
-          @Override
-          public boolean isExportGroups()
+          String htmlData = getHtml(titleSvgData, alignSvgData, jsonData);
+          FileOutputStream out = new FileOutputStream(fileX);
+          out.write(htmlData.getBytes());
+          out.flush();
+          out.close();
+          if (!(System.getProperty("java.awt.headless") != null && System
+                  .getProperty("java.awt.headless").equals("true")))
           {
-            return true;
+            jalview.util.BrowserLauncher.openURL("file:///" + fileX);
           }
+        } catch (OutOfMemoryError err)
+        {
+          System.out.println("########################\n"
+                  + "OUT OF MEMORY " + fileX + "\n"
+                  + "########################");
+          new OOMWarning("Creating Image for " + fileX, err);
+        } catch (Exception e)
+        {
+          e.printStackTrace();
+          pIndicator.setProgressBar(MessageManager.formatMessage(
+                  "info.error_creating_file", "HTML"), pSessionId);
+        }
+        setProgressMessage(MessageManager.formatMessage(
+                "status.export_complete", "HTML"));
+      }
+    }.start();
 
-          @Override
-          public boolean isCancelled()
-          {
-            return false;
-          }
+  }
 
-        };
-        AlignmentExportData exportData = jalview.gui.AlignFrame
-                .getAlignmentForExport(JSONFile.FILE_DESC, av,
-                        exportSettings);
-        jsonData = new FormatAdapter(ap, exportData.getSettings())
-                .formatSequences(JSONFile.FILE_DESC,
-                        exportData.getAlignment(),
-                        exportData.getOmitHidden(),
-                        exportData.getStartEndPostions(),
-                        av.getColumnSelection());
-      }
-      String htmlData = getHtml(titleSvgData, alignSvgData, jsonData);
-      FileOutputStream out = new FileOutputStream(file);
-      out.write(htmlData.getBytes());
-      out.flush();
-      out.close();
-      if (!(System.getProperty("java.awt.headless") != null && System
-              .getProperty("java.awt.headless").equals("true")))
-      {
-        jalview.util.BrowserLauncher.openURL("file:///" + file);
-      }
-      if (pIndicator != null && !headless)
-      {
-        pIndicator.setProgressBar(MessageManager.formatMessage(
-                "status.export_complete", "HTML"), pSessionId);
-      }
-    } catch (OutOfMemoryError err)
+  private void setProgressMessage(String message)
+  {
+    if (pIndicator != null && !headless)
     {
-      System.out.println("########################\n" + "OUT OF MEMORY "
-              + file + "\n" + "########################");
-      new OOMWarning("Creating Image for " + file, err);
-    } catch (Exception e)
+      pIndicator.setProgressBar(message, pSessionId);
+    }
+    else
     {
-      e.printStackTrace();
-      pIndicator.setProgressBar(MessageManager.formatMessage(
-              "info.error_creating_file", "HTML"), pSessionId);
+      System.out.println(message);
     }
   }
 
index 71f4237..889359f 100755 (executable)
@@ -230,7 +230,6 @@ public class IdentifyFile
                 } catch (IOException ex)
                 {
                 }
-                ;
                 if (dta != null && dta.indexOf("*") > -1)
                 {
                   starterm = true;
@@ -250,34 +249,19 @@ public class IdentifyFile
           // read as a FASTA (probably)
           break;
         }
-        if ((data.indexOf("<") > -1)) // possible Markup Language data i.e HTML,
+        int lessThan = data.indexOf("<");
+        if ((lessThan > -1)) // possible Markup Language data i.e HTML,
                                       // RNAML, XML
         {
-          // FIXME this is nuts - it consumes the rest of the file if no match
-          boolean identified = false;
-          do
-          {
-            if (data.matches("<(?i)html(\"[^\"]*\"|'[^']*'|[^'\">])*>"))
-            {
-              reply = HtmlFile.FILE_DESC;
-              identified = true;
-              break;
-            }
-
-            if (data.matches("<(?i)rnaml (\"[^\"]*\"|'[^']*'|[^'\">])*>"))
-            {
-              reply = "RNAML";
-              identified = true;
-              break;
-            }
-          } while ((data = source.nextLine()) != null);
-
-          if (identified)
+          String upper = data.toUpperCase();
+          if (upper.substring(lessThan).startsWith("<HTML"))
           {
+            reply = HtmlFile.FILE_DESC;
             break;
           }
-          if (data == null)
+          if (upper.substring(lessThan).startsWith("<RNAML"))
           {
+            reply = "RNAML";
             break;
           }
         }
index 3a7419c..6a236fd 100644 (file)
@@ -26,6 +26,7 @@ public abstract class StructureFile extends AlignFile
   private String id;
 
   private String dbRefType;
+
   /**
    * set to true to add derived sequence annotations (temp factor read from
    * file, or computed secondary structure) to the alignment
@@ -117,14 +118,11 @@ public abstract class StructureFile extends AlignFile
     sourceDBRef.setSource(DBRefSource.PDB);
     sourceDBRef.setStartRes(pdbSequence.getStart());
     sourceDBRef.setEndRes(pdbSequence.getEnd());
-
-    SequenceI chainseq = pdbSequence.deriveSequence();
-    chainseq.setSourceDBRef(sourceDBRef);
-    chainseq.addPDBId(entry);
-    chainseq.addDBRef(sourceDBRef);
-
+    pdbSequence.setSourceDBRef(sourceDBRef);
+    pdbSequence.addPDBId(entry);
+    pdbSequence.addDBRef(sourceDBRef);
+    SequenceI chainseq = pdbSequence;
     seqs.addElement(chainseq);
-
     AlignmentAnnotation[] chainannot = chainseq.getAnnotation();
 
     if (chainannot != null && visibleChainAnnotation)
@@ -185,8 +183,7 @@ public abstract class StructureFile extends AlignFile
 
   @SuppressWarnings("unchecked")
   protected void replaceAndUpdateChains(List<SequenceI> prot,
-          AlignmentI al,
-          String pep, boolean b)
+          AlignmentI al, String pep, boolean b)
   {
     List<List<? extends Object>> replaced = AlignSeq
             .replaceMatchingSeqsWith(seqs, annotations, prot, al, pep,
@@ -259,8 +256,7 @@ public abstract class StructureFile extends AlignFile
   }
 
   @SuppressWarnings({ "unchecked", "rawtypes" })
-  private void processWithJmolParser(List<SequenceI> prot)
-          throws Exception
+  private void processWithJmolParser(List<SequenceI> prot) throws Exception
   {
     try
     {
@@ -268,13 +264,11 @@ public abstract class StructureFile extends AlignFile
       Class cl = Class.forName("jalview.ext.jmol.JmolParser");
       if (cl != null)
       {
-        final Constructor constructor = cl
-.getConstructor(new Class[] {
+        final Constructor constructor = cl.getConstructor(new Class[] {
             boolean.class, boolean.class, boolean.class, FileParse.class });
         final Object[] args = new Object[] { visibleChainAnnotation,
             predictSecondaryStructure, externalSecondaryStructure,
-            new FileParse(getDataName(),
-                type) };
+            new FileParse(getDataName(), type) };
 
         StructureViewSettings.setShowSeqFeatures(false);
         StructureViewSettings.setVisibleChainAnnotation(false);
@@ -303,6 +297,7 @@ public abstract class StructureFile extends AlignFile
     } catch (ClassNotFoundException q)
     {
     }
+    StructureViewSettings.setShowSeqFeatures(true);
   }
 
   public PDBChain findChain(String id) throws Exception
index c4c737c..90053f5 100755 (executable)
@@ -201,7 +201,7 @@ public class GPreferences extends JPanel
   /*
    * Output tab components
    */
-  protected JComboBox<String> epsRendering = new JComboBox<String>();
+  protected JComboBox<Object> epsRendering = new JComboBox<Object>();
 
   protected JLabel userIdWidthlabel = new JLabel();
 
@@ -1236,7 +1236,7 @@ public class GPreferences extends JPanel
             .getString("label.open_overview"));
     openoverv.setHorizontalAlignment(SwingConstants.RIGHT);
     openoverv.setHorizontalTextPosition(SwingConstants.LEFT);
-    openoverv.setText(MessageManager.getString(("label.open_overview")));
+    openoverv.setText(MessageManager.getString("label.open_overview"));
     JPanel jPanel2 = new JPanel();
     jPanel2.setBounds(new Rectangle(7, 17, 158, 310));
     jPanel2.setLayout(new GridLayout(14, 1));
index a5b03d8..44f659d 100644 (file)
@@ -61,6 +61,7 @@ import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 import javax.swing.event.DocumentEvent;
 import javax.swing.event.DocumentListener;
+import javax.swing.table.TableColumn;
 
 @SuppressWarnings("serial")
 /**
@@ -158,8 +159,65 @@ public abstract class GStructureChooser extends JPanel implements
 
   protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
 
-  protected JTable tbl_summary = new JTable()
+  protected JTable tbl_local_pdb = new JTable();
+
+  protected JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
+
+  private JTabbedPane pnl_filter = new JTabbedPane();
+
+  protected FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences(
+          PreferenceSource.STRUCTURE_CHOOSER,
+          PDBFTSRestClient.getInstance());
+
+  protected FTSDataColumnI[] previousWantedFields;
+
+  private JTable tbl_summary = new JTable()
   {
+    private boolean inLayout;
+
+    @Override
+    public boolean getScrollableTracksViewportWidth()
+    {
+      return hasExcessWidth();
+
+    }
+
+    @Override
+    public void doLayout()
+    {
+      if (hasExcessWidth())
+      {
+        autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
+      }
+      inLayout = true;
+      super.doLayout();
+      inLayout = false;
+      autoResizeMode = AUTO_RESIZE_OFF;
+    }
+
+    protected boolean hasExcessWidth()
+    {
+      return getPreferredSize().width < getParent().getWidth();
+    }
+
+    @Override
+    public void columnMarginChanged(ChangeEvent e)
+    {
+      if (isEditing())
+      {
+        removeEditor();
+      }
+      TableColumn resizingColumn = getTableHeader().getResizingColumn();
+      // Need to do this here, before the parent's
+      // layout manager calls getPreferredSize().
+      if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF
+              && !inLayout)
+      {
+        resizingColumn.setPreferredWidth(resizingColumn.getWidth());
+      }
+      resizeAndRepaint();
+    }
+
     @Override
     public String getToolTipText(MouseEvent evt)
     {
@@ -190,17 +248,6 @@ public abstract class GStructureChooser extends JPanel implements
 
   protected JScrollPane scrl_foundStructures = new JScrollPane(tbl_summary);
 
-  protected JTable tbl_local_pdb = new JTable();
-
-  protected JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
-
-  private JTabbedPane pnl_filter = new JTabbedPane();
-
-  private FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences(
-          PreferenceSource.STRUCTURE_CHOOSER, PDBFTSRestClient.getInstance());
-
-  protected FTSDataColumnI[] previousWantedFields;
-
   public GStructureChooser()
   {
     try
@@ -393,11 +440,9 @@ public abstract class GStructureChooser extends JPanel implements
       }
     });
 
-    scrl_foundStructures.setPreferredSize(new Dimension(500, 300));
-    scrl_foundStructures
-            .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+    scrl_foundStructures.setPreferredSize(new Dimension(800, 400));
 
-    scrl_localPDB.setPreferredSize(new Dimension(500, 300));
+    scrl_localPDB.setPreferredSize(new Dimension(800, 400));
     scrl_localPDB
             .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
 
@@ -405,9 +450,8 @@ public abstract class GStructureChooser extends JPanel implements
     chk_invertFilter.setFont(new java.awt.Font("Verdana", 0, 12));
     chk_rememberSettings.setFont(new java.awt.Font("Verdana", 0, 12));
     chk_rememberSettings.setVisible(false);
-
-    txt_search.setToolTipText(MessageManager
-            .getString("label.enter_pdb_id"));
+    txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
+            MessageManager.getString("label.enter_pdb_id")));
     cmb_filterOption.setToolTipText(MessageManager
             .getString("info.select_filter_option"));
     txt_search.getDocument().addDocumentListener(new DocumentListener()
@@ -474,9 +518,9 @@ public abstract class GStructureChooser extends JPanel implements
           btn_cancel.setEnabled(false);
           btn_view.setVisible(false);
           btn_cancel.setVisible(false);
-          previousWantedFields = PDBFTSRestClient.getInstance()
-                  .getAllDefaulDisplayedDataColumns()
-                  .toArray(new FTSDataColumnI[0]);
+          previousWantedFields = pdbDocFieldPrefs
+                  .getStructureSummaryFields().toArray(
+                          new FTSDataColumnI[0]);
         }
         if (sourceTabbedPane.getTitleAt(index)
                 .equals(foundStructureSummary))
@@ -494,7 +538,7 @@ public abstract class GStructureChooser extends JPanel implements
       }
     };
     pnl_filter.addChangeListener(changeListener);
-    pnl_filter.setPreferredSize(new Dimension(500, 300));
+    pnl_filter.setPreferredSize(new Dimension(800, 400));
     pnl_filter.add(foundStructureSummary, scrl_foundStructures);
     pnl_filter.add(configureCols, pdbDocFieldPrefs);
 
@@ -518,7 +562,7 @@ public abstract class GStructureChooser extends JPanel implements
     mainFrame.setVisible(true);
     mainFrame.setContentPane(this);
     mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
-    Desktop.addInternalFrame(mainFrame, frameTitle, 800, 400);
+    Desktop.addInternalFrame(mainFrame, frameTitle, 900, 500);
   }
 
   public boolean wantedFieldsUpdated()
@@ -527,12 +571,12 @@ public abstract class GStructureChooser extends JPanel implements
     {
       return true;
     }
-
-    return Arrays.equals(
-            PDBFTSRestClient.getInstance()
-                    .getAllDefaulDisplayedDataColumns()
-            .toArray(new FTSDataColumnI[0]),
-            previousWantedFields) ? false : true;
+    
+    FTSDataColumnI[] currentWantedFields = pdbDocFieldPrefs
+            .getStructureSummaryFields()
+            .toArray(new FTSDataColumnI[0]);
+    return Arrays.equals(currentWantedFields, previousWantedFields) ? false
+            : true;
 
   }
 
@@ -706,6 +750,10 @@ public abstract class GStructureChooser extends JPanel implements
     }
   }
 
+  public JTable getResultTable()
+  {
+    return tbl_summary;
+  }
   public JComboBox<FilterOption> getCmbFilterOption()
   {
     return cmb_filterOption;
diff --git a/src/jalview/renderer/ScaleRenderer.java b/src/jalview/renderer/ScaleRenderer.java
new file mode 100644 (file)
index 0000000..7f1e074
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.renderer;
+
+import jalview.api.AlignViewportI;
+import jalview.datamodel.SequenceI;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Calculate and display alignment rulers
+ * 
+ * @author jprocter
+ *
+ */
+public class ScaleRenderer
+{
+  /**
+   * calculate positions markers on the alignment ruler
+   * 
+   * @param av
+   * @param startx
+   *          left-most column in visible view
+   * @param endx
+   *          - right-most column in visible view
+   * @return List { Object { .. } } Boolean: true/false for major/minor mark,
+   *         Integer: marker position in alignment column coords, String: null
+   *         or a String to be rendered at the position.
+   */
+  public static List<Object[]> calculateMarks(AlignViewportI av,
+          int startx, int endx)
+  {
+    new ArrayList<Object[]>();
+
+    int scalestartx = (startx / 10) * 10;
+
+    SequenceI refSeq = av.getAlignment().getSeqrep();
+    int refSp = 0, refStartI = 0, refEndI = -1;
+    if (refSeq != null)
+    {
+      // find bounds and set origin appopriately
+      // locate first visible position for this sequence
+      int[] refbounds = av.getColumnSelection()
+              .locateVisibleBoundsOfSequence(refSeq);
+
+      refSp = refbounds[0];
+      refStartI = refbounds[4];
+      refEndI = refbounds[5];
+      scalestartx = refSp + ((scalestartx - refSp) / 10) * 10;
+    }
+
+    if (refSeq == null && scalestartx % 10 == 0)
+    {
+      scalestartx += 5;
+    }
+    List<Object[]> marks = new ArrayList<Object[]>();
+    String string;
+    int refN, iadj;
+    // todo: add a 'reference origin column' to set column number relative to
+    for (int i = scalestartx; i < endx; i += 5)
+    {
+      Object[] amark = new Object[3];
+      if (((i - refSp) % 10) == 0)
+      {
+        if (refSeq == null)
+        {
+          iadj = av.getColumnSelection().adjustForHiddenColumns(i - 1) + 1;
+          string = String.valueOf(iadj);
+        }
+        else
+        {
+          iadj = av.getColumnSelection().adjustForHiddenColumns(i - 1);
+          refN = refSeq.findPosition(iadj);
+          // TODO show bounds if position is a gap
+          // - ie L--R -> "1L|2R" for
+          // marker
+          if (iadj < refStartI)
+          {
+            string = String.valueOf(iadj - refStartI);
+          }
+          else if (iadj > refEndI)
+          {
+            string = "+" + String.valueOf(iadj - refEndI);
+          }
+          else
+          {
+            string = String.valueOf(refN) + refSeq.getCharAt(iadj);
+          }
+        }
+        amark[0] = Boolean.TRUE;
+        amark[1] = Integer.valueOf(i - startx - 1);
+        amark[2] = string;
+
+      }
+      else
+      {
+        amark[0] = Boolean.FALSE;
+        amark[1] = Integer.valueOf(i - startx - 1);
+        amark[2] = null;
+      }
+      marks.add(amark);
+    }
+    return marks;
+  }
+
+}
index 8c248d2..8c6bc5e 100644 (file)
@@ -401,7 +401,7 @@ public class FeatureRenderer extends FeatureRendererModel
 
     }
 
-    if (transparency != 1.0f && g != null && transparencyAvailable)
+    if (transparency != 1.0f && g != null)
     {
       Graphics2D g2 = (Graphics2D) g;
       g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
@@ -409,19 +409,6 @@ public class FeatureRenderer extends FeatureRendererModel
     }
   }
 
-  boolean transparencyAvailable = true;
-
-  protected void setTransparencyAvailable(boolean isTransparencyAvailable)
-  {
-    transparencyAvailable = isTransparencyAvailable;
-  }
-
-  @Override
-  public boolean isTransparencyAvailable()
-  {
-    return transparencyAvailable;
-  }
-
   /**
    * Called when alignment in associated view has new/modified features to
    * discover and display.
index a5d9736..fb96b22 100644 (file)
@@ -501,29 +501,67 @@ public class StructureSelectionManager
       if (isMapUsingSIFTs)
       {
         setProgressBar(null);
-        setProgressBar("Obtaining mapping with SIFTS");
+        setProgressBar(MessageManager
+                .getString("status.obtaining_mapping_with_sifts"));
         jalview.datamodel.Mapping sqmpping = maxAlignseq
                 .getMappingFromS1(false);
         if (targetChainId != null && !targetChainId.trim().isEmpty())
         {
-          StructureMapping mapping = getStructureMapping(seq, pdbFile,
-                  targetChainId, pdb, maxChain, sqmpping, maxAlignseq);
-          seqToStrucMapping.add(mapping);
+          StructureMapping siftsMapping;
+          try
+          {
+            siftsMapping = getStructureMapping(seq, pdbFile, targetChainId,
+                    pdb, maxChain, sqmpping, maxAlignseq);
+            seqToStrucMapping.add(siftsMapping);
+            maxChain.makeExactMapping(maxAlignseq, seq);
+            maxChain.transferRESNUMFeatures(seq, null);
+            maxChain.transferResidueAnnotation(siftsMapping, sqmpping);
+          } catch (SiftsException e)
+          {
+            // fall back to NW alignment
+            System.err.println(e.getMessage());
+            StructureMapping nwMapping = getNWMappings(seq, pdbFile,
+                    targetChainId, maxChain, pdb, maxAlignseq);
+            seqToStrucMapping.add(nwMapping);
+          }
         }
         else
         {
+          ArrayList<StructureMapping> foundSiftsMappings = new ArrayList<StructureMapping>();
           for (PDBChain chain : pdb.getChains())
           {
-            StructureMapping mapping = getStructureMapping(seq, pdbFile,
-                    chain.id, pdb, chain, sqmpping, maxAlignseq);
-            seqToStrucMapping.add(mapping);
+            try
+            {
+              StructureMapping siftsMapping = getStructureMapping(seq,
+                      pdbFile,
+                      chain.id, pdb, chain, sqmpping, maxAlignseq);
+              foundSiftsMappings.add(siftsMapping);
+            } catch (SiftsException e)
+            {
+              System.err.println(e.getMessage());
+            }
+          }
+          if (!foundSiftsMappings.isEmpty())
+          {
+            seqToStrucMapping.addAll(foundSiftsMappings);
+            maxChain.makeExactMapping(maxAlignseq, seq);
+            maxChain.transferRESNUMFeatures(seq, null);
+            maxChain.transferResidueAnnotation(foundSiftsMappings.get(0),
+                    sqmpping);
+          }
+          else
+          {
+            StructureMapping nwMapping = getNWMappings(seq, pdbFile,
+                    maxChainId, maxChain, pdb, maxAlignseq);
+            seqToStrucMapping.add(nwMapping);
           }
         }
       }
       else
       {
         setProgressBar(null);
-        setProgressBar("Obtaining mapping with NW alignment");
+        setProgressBar(MessageManager
+                .getString("status.obtaining_mapping_with_nw_alignment"));
         seqToStrucMapping.add(getNWMappings(seq, pdbFile, maxChainId,
                 maxChain, pdb, maxAlignseq));
       }
@@ -546,11 +584,8 @@ public class StructureSelectionManager
   private StructureMapping getStructureMapping(SequenceI seq,
           String pdbFile, String targetChainId, StructureFile pdb,
           PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
-          AlignSeq maxAlignseq)
+          AlignSeq maxAlignseq) throws SiftsException
   {
-    String maxChainId = targetChainId;
-    try
-    {
       StructureMapping curChainMapping = siftsClient
               .getSiftsStructureMapping(seq, pdbFile, targetChainId);
       try
@@ -565,15 +600,6 @@ public class StructureSelectionManager
         e.printStackTrace();
       }
       return curChainMapping;
-    } catch (SiftsException e)
-    {
-      System.err.println(e.getMessage());
-      System.err.println(">>> Now switching mapping with NW alignment...");
-      setProgressBar(null);
-      setProgressBar(">>> Now switching mapping with NW alignment...");
-      return getNWMappings(seq, pdbFile, maxChainId, maxChain, pdb,
-              maxAlignseq);
-    }
   }
 
   private StructureMapping getNWMappings(SequenceI seq,
index 42fbfa9..dc42315 100644 (file)
@@ -598,6 +598,10 @@ public abstract class AAStructureBindingModel extends
       for (String file : files)
       {
         notLoaded = file;
+        if (file == null)
+        {
+          continue;
+        }
         try
         {
           StructureMapping[] sm = getSsm().getMapping(file);
diff --git a/src/jalview/util/DnaUtils.java b/src/jalview/util/DnaUtils.java
new file mode 100644 (file)
index 0000000..9582e2e
--- /dev/null
@@ -0,0 +1,133 @@
+package jalview.util;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class DnaUtils
+{
+
+  /**
+   * Parses an ENA/GenBank format location specifier and returns a list of
+   * [start, end] ranges. Throws an exception if not able to parse.
+   * <p>
+   * Currently we do not parse "order()" specifiers, or indeterminate ranges of
+   * the format "&lt;start..end" or "start..&gt;end" or "start.end" or
+   * "start^end"
+   * 
+   * @param location
+   * @return
+   * @throws ParseException
+   *           if unable to parse the location (the exception message is the
+   *           location specifier being parsed); we use ParseException in
+   *           preference to the unchecked IllegalArgumentException
+   * @see http://www.insdc.org/files/feature_table.html#3.4
+   */
+  public static List<int[]> parseLocation(String location)
+          throws ParseException
+  {
+    if (location.startsWith("join("))
+    {
+      return parseJoin(location);
+    }
+    else if (location.startsWith("complement("))
+    {
+      return parseComplement(location);
+    }
+    if (location.startsWith("order("))
+    {
+      throw new ParseException(location, 0);
+    }
+
+    /*
+     * try to parse m..n (or simply m)
+     */
+    String[] range = location.split("\\.\\.");
+    if (range.length == 1 || range.length == 2)
+    {
+      try
+      {
+        int start = Integer.valueOf(range[0]);
+        int end = range.length == 1 ? start : Integer.valueOf(range[1]);
+        return Collections.singletonList(new int[] { start, end });
+      } catch (NumberFormatException e)
+      {
+        /*
+         * could be a location like <1..888 or 1..>888
+         */
+        throw new ParseException(location, 0);
+      }
+    }
+    else
+    {
+      /*
+       * could be a location like 102.110 or 123^124
+       */
+      throw new ParseException(location, 0);
+    }
+  }
+
+  /**
+   * Parses a complement(locationSpec) into a list of start-end ranges
+   * 
+   * @param location
+   * @return
+   * @throws ParseException
+   */
+  static List<int[]> parseComplement(String location) throws ParseException
+  {
+    /*
+     * take what is inside complement()
+     */
+    if (!location.endsWith(")"))
+    {
+      throw new ParseException(location, 0);
+    }
+    String toComplement = location.substring("complement(".length(),
+            location.length() - 1);
+    List<int[]> ranges = parseLocation(toComplement);
+
+    /*
+     * reverse the order and direction of ranges
+     */
+    Collections.reverse(ranges);
+    for (int[] range : ranges)
+    {
+      int temp = range[0];
+      range[0] = range[1];
+      range[1] = temp;
+    }
+    return ranges;
+  }
+
+  /**
+   * Parses a join(loc1,loc2,...,locn) into a list of start-end ranges
+   * 
+   * @param location
+   * @return
+   * @throws ParseException
+   */
+  static List<int[]> parseJoin(String location) throws ParseException
+  {
+    List<int[]> ranges = new ArrayList<int[]>();
+
+    /*
+     * take what is inside join()
+     */
+    if (!location.endsWith(")"))
+    {
+      throw new ParseException(location, 0);
+    }
+    String joinedLocs = location.substring("join(".length(),
+            location.length() - 1);
+    String[] locations = joinedLocs.split(",");
+    for (String loc : locations)
+    {
+      List<int[]> range = parseLocation(loc);
+      ranges.addAll(range);
+    }
+    return ranges;
+  }
+
+}
index b7aa4ca..fcea21d 100755 (executable)
@@ -54,6 +54,12 @@ public class ImageMaker
 
   TYPE type;
 
+  private IProgressIndicator pIndicator;
+
+  private long pSessionId;
+
+  private boolean headless;
+
   public enum TYPE
   {
     EPS("EPS", MessageManager.getString("label.eps_file"), getEPSChooser()), PNG(
@@ -94,17 +100,14 @@ public class ImageMaker
           int height, File file, String fileTitle,
           IProgressIndicator pIndicator, long pSessionId, boolean headless)
   {
+    this.pIndicator = pIndicator;
     this.type = type;
-
+    this.pSessionId = pSessionId;
+    this.headless = headless;
     if (file == null)
     {
-      if (pIndicator != null && !headless)
-      {
-        pIndicator.setProgressBar(
-                MessageManager.formatMessage(
-                        "status.waiting_for_user_to_select_output_file",
-                        type.name), pSessionId);
-      }
+      setProgressMessage(MessageManager.formatMessage(
+              "status.waiting_for_user_to_select_output_file", type.name));
       JalviewFileChooser chooser;
       chooser = type.getChooser();
       chooser.setFileView(new jalview.io.JalviewFileView());
@@ -120,12 +123,8 @@ public class ImageMaker
       }
       else
       {
-        if (pIndicator != null && !headless)
-        {
-          pIndicator.setProgressBar(MessageManager.formatMessage(
-                  "status.cancelled_image_export_operation", type.name),
-                  pSessionId);
-        }
+        setProgressMessage(MessageManager.formatMessage(
+                "status.cancelled_image_export_operation", type.name));
       }
     }
 
@@ -134,6 +133,9 @@ public class ImageMaker
       try
       {
         out = new FileOutputStream(file);
+        setProgressMessage(null);
+        setProgressMessage(MessageManager.formatMessage(
+                "status.exporting_alignment_as_x_file", type.getName()));
         if (type == TYPE.SVG)
         {
           setupSVG(width, height, fileTitle);
@@ -146,19 +148,13 @@ public class ImageMaker
         {
           setupPNG(width, height);
         }
-        if (pIndicator != null && !headless)
-        {
-          pIndicator.setProgressBar(
-MessageManager.formatMessage(
-                  "status.export_complete", type.getName()),
-                  pSessionId);
-        }
+
       } catch (Exception ex)
       {
         System.out.println("Error creating " + type.getName() + " file.");
 
-        pIndicator.setProgressBar(MessageManager.formatMessage(
-                "info.error_creating_file", type.getName()), pSessionId);
+        setProgressMessage(MessageManager.formatMessage(
+                "info.error_creating_file", type.getName()));
       }
     }
   }
@@ -214,6 +210,8 @@ MessageManager.formatMessage(
 
       if (renderStyle == null || eps.cancelled)
       {
+        setProgressMessage(MessageManager.formatMessage(
+                "status.cancelled_image_export_operation", "EPS"));
         return;
       }
     }
@@ -233,6 +231,8 @@ MessageManager.formatMessage(
       pg.setAccurateTextMode(accurateText);
 
       graphics = pg;
+      setProgressMessage(MessageManager.formatMessage(
+              "status.export_complete", type.getName()));
     } catch (Exception ex)
     {
     }
@@ -245,6 +245,8 @@ MessageManager.formatMessage(
     Graphics2D ig2 = (Graphics2D) graphics;
     ig2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
             RenderingHints.VALUE_ANTIALIAS_ON);
+    setProgressMessage(MessageManager.formatMessage(
+            "status.export_complete", type.getName()));
 
   }
 
@@ -268,16 +270,20 @@ MessageManager.formatMessage(
 
       if (renderStyle == null || svgOption.cancelled)
       {
+        setProgressMessage(MessageManager.formatMessage(
+                "status.cancelled_image_export_operation", "SVG"));
         return;
       }
     }
 
-    if (renderStyle.equalsIgnoreCase("lineart"))
+    if (renderStyle.equalsIgnoreCase("Lineart"))
     {
       ig2.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
               SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
     }
 
+    setProgressMessage(MessageManager.formatMessage(
+            "status.export_complete", type.getName()));
     graphics = g2;
   }
 
@@ -307,6 +313,14 @@ MessageManager.formatMessage(
             "Encapsulated Postscript");
   }
 
+  private void setProgressMessage(String message)
+  {
+    if (pIndicator != null && !headless)
+    {
+      pIndicator.setProgressBar(message, pSessionId);
+    }
+  }
+
   static JalviewFileChooser getSVGChooser()
   {
     if (Jalview.isHeadlessMode())
index b812feb..786f5bf 100644 (file)
@@ -20,6 +20,9 @@
  */
 package jalview.util;
 
+import java.awt.Toolkit;
+import java.awt.event.MouseEvent;
+
 /**
  * System platform information used by Applet and Application
  * 
@@ -74,4 +77,11 @@ public class Platform
     f.append(file.substring(lastp));
     return f.toString();
   }
+
+  public static boolean isControlDown(MouseEvent e)
+  {
+    return (jalview.util.Platform.isAMac() ? (Toolkit.getDefaultToolkit()
+            .getMenuShortcutKeyMask() & e.getModifiers()) != 0 : e
+            .isControlDown());
+  }
 }
index 6044655..ccc2012 100644 (file)
@@ -299,4 +299,108 @@ public class StringUtils
     }
     return result;
   }
+
+  /**
+   * Compares two versions formatted as e.g. "3.4.5" and returns -1, 0 or 1 as
+   * the first version precedes, is equal to, or follows the second
+   * 
+   * @param v1
+   * @param v2
+   * @return
+   */
+  public static int compareVersions(String v1, String v2)
+  {
+    return compareVersions(v1, v2, null);
+  }
+
+  /**
+   * Compares two versions formatted as e.g. "3.4.5b1" and returns -1, 0 or 1 as
+   * the first version precedes, is equal to, or follows the second
+   * 
+   * @param v1
+   * @param v2
+   * @param pointSeparator
+   *          a string used to delimit point increments in sub-tokens of the
+   *          version
+   * @return
+   */
+  public static int compareVersions(String v1, String v2,
+          String pointSeparator)
+  {
+    if (v1 == null || v2 == null)
+    {
+      return 0;
+    }
+    String[] toks1 = v1.split("\\.");
+    String[] toks2 = v2.split("\\.");
+    int i = 0;
+    for (; i < toks1.length; i++)
+    {
+      if (i >= toks2.length)
+      {
+        /*
+         * extra tokens in v1
+         */
+        return 1;
+      }
+      String tok1 = toks1[i];
+      String tok2 = toks2[i];
+      if (pointSeparator != null)
+      {
+        /*
+         * convert e.g. 5b2 into decimal 5.2 for comparison purposes
+         */
+        tok1 = tok1.replace(pointSeparator, ".");
+        tok2 = tok2.replace(pointSeparator, ".");
+      }
+      try
+      {
+        float f1 = Float.valueOf(tok1);
+        float f2 = Float.valueOf(tok2);
+        int comp = Float.compare(f1, f2);
+        if (comp != 0)
+        {
+          return comp;
+        }
+      } catch (NumberFormatException e)
+      {
+        System.err.println("Invalid version format found: "
+                + e.getMessage());
+        return 0;
+      }
+    }
+
+    if (i < toks2.length)
+    {
+      /*
+       * extra tokens in v2 
+       */
+      return -1;
+    }
+
+    /*
+     * same length, all tokens match
+     */
+    return 0;
+  }
+
+  /**
+   * Converts the string to all lower-case except the first character which is
+   * upper-cased
+   * 
+   * @param s
+   * @return
+   */
+  public static String toSentenceCase(String s)
+  {
+    if (s == null)
+    {
+      return s;
+    }
+    if (s.length() <= 1)
+    {
+      return s.toUpperCase();
+    }
+    return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
+  }
 }
index b70e92b..0f6d66b 100644 (file)
@@ -1078,6 +1078,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
     {
       updateHiddenColumns();
     }
+    isColSelChanged(true);
   }
 
   /**
@@ -1206,8 +1207,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
    */
   public boolean isColSelChanged(boolean b)
   {
-    int hc = (colSel == null || colSel.isEmpty()) ? -1 : colSel
-            .hashCode();
+    int hc = (colSel == null || colSel.isEmpty()) ? -1 : colSel.hashCode();
     if (hc != -1 && hc != colselhash)
     {
       if (b)
@@ -1308,7 +1308,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
 
     colSel.hideSelectedColumns();
     setSelectionGroup(null);
-
+    isColSelChanged(true);
   }
 
   public void hideColumns(int start, int end)
@@ -1321,17 +1321,19 @@ public abstract class AlignmentViewport implements AlignViewportI,
     {
       colSel.hideColumns(start, end);
     }
+    isColSelChanged(true);
   }
 
   public void showColumn(int col)
   {
     colSel.revealHiddenColumns(col);
-
+    isColSelChanged(true);
   }
 
   public void showAllHiddenColumns()
   {
     colSel.revealAllHiddenColumns();
+    isColSelChanged(true);
   }
 
   // common hide/show seq stuff
@@ -1463,13 +1465,42 @@ public abstract class AlignmentViewport implements AlignViewportI,
 
   }
 
+  /**
+   * 
+   * @return null or the current reference sequence
+   */
+  public SequenceI getReferenceSeq()
+  {
+    return alignment.getSeqrep();
+  }
+
+  /**
+   * @param seq
+   * @return true iff seq is the reference for the alignment
+   */
+  public boolean isReferenceSeq(SequenceI seq)
+  {
+    return alignment.getSeqrep() == seq;
+  }
+
+  /**
+   * 
+   * @param seq
+   * @return true if there are sequences represented by this sequence that are
+   *         currently hidden
+   */
   public boolean isHiddenRepSequence(SequenceI seq)
   {
-    return alignment.getSeqrep() == seq
-            || (hiddenRepSequences != null && hiddenRepSequences
+    return (hiddenRepSequences != null && hiddenRepSequences
                     .containsKey(seq));
   }
 
+  /**
+   * 
+   * @param seq
+   * @return null or a sequence group containing the sequences that seq
+   *         represents
+   */
   public SequenceGroup getRepresentedSequences(SequenceI seq)
   {
     return (SequenceGroup) (hiddenRepSequences == null ? null
@@ -1557,6 +1588,13 @@ public abstract class AlignmentViewport implements AlignViewportI,
   @Override
   public String[] getViewAsString(boolean selectedRegionOnly)
   {
+    return getViewAsString(selectedRegionOnly, true);
+  }
+
+  @Override
+  public String[] getViewAsString(boolean selectedRegionOnly,
+          boolean exportHiddenSeqs)
+  {
     String[] selection = null;
     SequenceI[] seqs = null;
     int i, iSize;
@@ -1570,13 +1608,13 @@ public abstract class AlignmentViewport implements AlignViewportI,
     }
     else
     {
-      if (hasHiddenRows())
+      if (hasHiddenRows() && exportHiddenSeqs)
       {
-        iSize = alignment.getHiddenSequences().getFullAlignment()
-                .getHeight();
-        seqs = alignment.getHiddenSequences().getFullAlignment()
-                .getSequencesArray();
-        end = alignment.getHiddenSequences().getFullAlignment().getWidth();
+        AlignmentI fullAlignment = alignment.getHiddenSequences()
+                .getFullAlignment();
+        iSize = fullAlignment.getHeight();
+        seqs = fullAlignment.getSequencesArray();
+        end = fullAlignment.getWidth();
       }
       else
       {
@@ -2688,4 +2726,6 @@ public abstract class AlignmentViewport implements AlignViewportI,
       }
     }
   }
+
+
 }
index 0d317e6..ee0721d 100644 (file)
@@ -560,31 +560,6 @@ public abstract class FeatureRendererModel implements
   }
 
   /**
-   * return a nominal colour for this feature
-   * 
-   * @param featureType
-   * @return standard color, or maximum colour for graduated colourscheme
-   */
-  public Color getColour(String featureType)
-  {
-    Object fc = getFeatureStyle(featureType);
-
-    if (fc instanceof Color)
-    {
-      return (Color) fc;
-    }
-    else
-    {
-      if (fc instanceof GraduatedColor)
-      {
-        return ((GraduatedColor) fc).getMaxColor();
-      }
-    }
-    throw new Error("Implementation Error: Unrecognised render object "
-            + fc.getClass() + " for features of type " + featureType);
-  }
-
-  /**
    * calculate the render colour for a specific feature using current feature
    * settings.
    * 
@@ -837,6 +812,9 @@ public abstract class FeatureRendererModel implements
     return renderOrder != null;
   }
 
+  /**
+   * Returns feature types in ordering of rendering, where last means on top
+   */
   public List<String> getRenderOrder()
   {
     if (renderOrder == null)
@@ -946,7 +924,7 @@ public abstract class FeatureRendererModel implements
     while (en.hasNext())
     {
       String col = en.next();
-      fcols.put(col, getColour(col));
+      fcols.put(col, featureColours.get(col));
     }
     return fcols;
   }
index ee48c73..f804a19 100644 (file)
@@ -2,10 +2,10 @@ package jalview.workers;
 
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
+import jalview.bin.Jalview;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.gui.AlignFrame;
-import jalview.gui.Desktop;
 
 import java.awt.Color;
 
@@ -32,7 +32,7 @@ public class AlignmentAnnotationFactory
   {
     // TODO need an interface for AlignFrame by which to access
     // its AlignViewportI and AlignmentViewPanel
-    AlignFrame currentAlignFrame = Desktop.getCurrentAlignFrame();
+    AlignFrame currentAlignFrame = Jalview.getCurrentAlignFrame() ;
     if (currentAlignFrame != null)
     {
       newCalculator(currentAlignFrame.getViewport(), currentAlignFrame
@@ -69,7 +69,7 @@ public class AlignmentAnnotationFactory
   {
     // TODO need an interface for AlignFrame by which to access
     // its AlignViewportI and AlignmentViewPanel
-    AlignFrame currentAlignFrame = Desktop.getCurrentAlignFrame();
+    AlignFrame currentAlignFrame = Jalview.getCurrentAlignFrame() ;
     if (currentAlignFrame != null)
     {
       newCalculator(currentAlignFrame.getViewport(), currentAlignFrame
index 40c88c1..3ba0e34 100644 (file)
@@ -141,7 +141,7 @@ public class DBRefFetcher implements Runnable
       String[] defdb = null, otherdb = sfetcher
               .getDbInstances(jalview.ws.dbsources.das.datamodel.DasSequenceSource.class);
       List<DbSourceProxy> selsources = new ArrayList<DbSourceProxy>();
-      Vector dasselsrc = (featureSettings != null) ? featureSettings
+      Vector<jalviewSourceI> dasselsrc = (featureSettings != null) ? featureSettings
               .getSelectedSources() : new jalview.gui.DasSourceBrowser()
               .getSelectedSources();
       Enumeration<jalviewSourceI> en = dasselsrc.elements();
@@ -190,6 +190,16 @@ public class DBRefFetcher implements Runnable
   }
 
   /**
+   * Constructor with only sequences provided
+   * 
+   * @param sequences
+   */
+  public DBRefFetcher(SequenceI[] sequences)
+  {
+    this(sequences, null, null, null, false);
+  }
+
+  /**
    * Add a listener to be notified when sequence fetching is complete
    * 
    * @param l
index d7ba24d..5f9b2d9 100644 (file)
@@ -22,11 +22,13 @@ package jalview.ws;
 
 import jalview.bin.Cache;
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
 import jalview.gui.FeatureSettings;
+import jalview.util.DBRefUtils;
 import jalview.util.MessageManager;
 import jalview.util.UrlLink;
 import jalview.ws.dbsources.das.api.DasSourceRegistryI;
@@ -186,8 +188,7 @@ public class DasSequenceFeatureFetcher
       {
         for (int j = 0; j < dbref.length; j++)
         {
-          if (dbref[j].getSource().equals(
-                  jalview.datamodel.DBRefSource.UNIPROT))
+          if (dbref[j].getSource().equals(DBRefSource.UNIPROT))
           {
             refCount++;
             break;
@@ -252,10 +253,10 @@ public class DasSequenceFeatureFetcher
     public void run()
     {
       running = true;
-      boolean isNuclueotide = af.getViewport().getAlignment()
+      boolean isNucleotide = af.getViewport().getAlignment()
               .isNucleotide();
-      new jalview.ws.DBRefFetcher(sequences, af, null, af.featureSettings,
-              isNuclueotide).fetchDBRefs(true);
+      new DBRefFetcher(sequences, af, null, af.featureSettings,
+              isNucleotide).fetchDBRefs(true);
 
       startFetching();
       setGuiFetchComplete();
@@ -286,7 +287,7 @@ public class DasSequenceFeatureFetcher
       {
         jalviewSourceI[] sources = sourceRegistry.getSources().toArray(
                 new jalviewSourceI[0]);
-        String active = jalview.bin.Cache.getDefault("DAS_ACTIVE_SOURCE",
+        String active = Cache.getDefault("DAS_ACTIVE_SOURCE",
                 "uniprot");
         StringTokenizer st = new StringTokenizer(active, "\t");
         selectedSources = new Vector();
@@ -643,10 +644,10 @@ public class DasSequenceFeatureFetcher
     {
       return null;
     }
-    DBRefEntry[] uprefs = jalview.util.DBRefUtils.selectRefs(
+    DBRefEntry[] uprefs = DBRefUtils.selectRefs(
             seq.getDBRefs(), new String[] {
             // jalview.datamodel.DBRefSource.PDB,
-            jalview.datamodel.DBRefSource.UNIPROT,
+            DBRefSource.UNIPROT,
             // jalview.datamodel.DBRefSource.EMBL - not tested on any EMBL coord
             // sys sources
             });
@@ -665,7 +666,7 @@ public class DasSequenceFeatureFetcher
 
         for (COORDINATES csys : dasSource.getVersion().getCOORDINATES())
         {
-          if (jalview.util.DBRefUtils.isDasCoordinateSystem(
+          if (DBRefUtils.isDasCoordinateSystem(
                   csys.getAuthority(), uprefs[j]))
           {
             debug("Launched fetcher for coordinate system "
index 1f8c28a..65179a2 100644 (file)
@@ -66,8 +66,6 @@ public class SequenceFetcher extends ASequenceFetcher
     addDBRefSourceImpl(Pdb.class);
     addDBRefSourceImpl(PfamFull.class);
     addDBRefSourceImpl(PfamSeed.class);
-    // ensures Seed alignment is 'default' for PFAM
-    addDBRefSourceImpl(RfamFull.class);
     addDBRefSourceImpl(RfamSeed.class);
     if (addDas)
     {
index 0085221..2049766 100644 (file)
@@ -63,7 +63,7 @@ public abstract class EmblXmlSource extends EbiFileRetrievedProxy
     try
     {
       reply = dbFetch.fetchDataAsFile(
-              emprefx.toLowerCase() + ":" + query.trim(), "emblxml", null,
+              emprefx.toLowerCase() + ":" + query.trim(), "display=xml",
               ".xml");
     } catch (Exception e)
     {
index 4a089f7..b0b5e92 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
  * Copyright (C) $$Year-Rel$$ The Jalview Authors
@@ -53,7 +54,7 @@ public class Pdb extends EbiFileRetrievedProxy
 
   public static final String FEATURE_RES_NUM = "RESNUM";
 
-  private static String currentDefaultFomart = DBRefSource.PDB;
+  private static String currentDefaultFormat = DBRefSource.PDB;
 
   /*
    * (non-Javadoc)
@@ -132,11 +133,11 @@ public class Pdb extends EbiFileRetrievedProxy
       stopQuery();
       return null;
     }
-    String ext = getCurrentDefaultFomart().equalsIgnoreCase("mmcif") ? ".cif"
+    String ext = getCurrentDefaultFormat().equalsIgnoreCase("mmcif") ? ".cif"
             : ".xml";
     EBIFetchClient ebi = new EBIFetchClient();
     file = ebi.fetchDataAsFile("pdb:" + id,
-            getCurrentDefaultFomart().toLowerCase(), "raw", ext)
+            getCurrentDefaultFormat().toLowerCase(), ext)
             .getAbsolutePath();
     stopQuery();
     if (file == null)
@@ -148,7 +149,7 @@ public class Pdb extends EbiFileRetrievedProxy
 
       pdbAlignment = new FormatAdapter().readFile(file,
               jalview.io.AppletFormatAdapter.FILE,
-              getCurrentDefaultFomart());
+              getCurrentDefaultFormat());
       if (pdbAlignment != null)
       {
         List<SequenceI> toremove = new ArrayList<SequenceI>();
@@ -243,12 +244,12 @@ public class Pdb extends EbiFileRetrievedProxy
   }
 
   /**
-   * obtain human glyoxalase chain A sequence
+   * human glyoxalase
    */
   @Override
   public String getTestQuery()
   {
-    return "1QIPA";
+    return "1QIP";
   }
 
   @Override
@@ -263,14 +264,14 @@ public class Pdb extends EbiFileRetrievedProxy
     return 0;
   }
 
-  public static String getCurrentDefaultFomart()
+  public static String getCurrentDefaultFormat()
   {
-    return currentDefaultFomart;
+    return currentDefaultFormat;
   }
 
-  public static void setCurrentDefaultFomart(String currentDefaultFomart)
+  public static void setCurrentDefaultFormat(String currentDefaultFomart)
   {
-    Pdb.currentDefaultFomart = currentDefaultFomart;
+    Pdb.currentDefaultFormat = currentDefaultFomart;
   }
 
   /**
index 4f5b8f5..62b9686 100644 (file)
@@ -40,7 +40,7 @@ public class PfamFull extends Pfam
   @Override
   protected String getXFAMURL()
   {
-    return "http://pfam.sanger.ac.uk/family/alignment/download/format?alnType=full&format=stockholm&order=t&case=l&gaps=default&entry=";
+    return "http://pfam.xfam.org/family/alignment/download/format?alnType=full&format=stockholm&order=t&case=l&gaps=default&entry=";
   }
 
   /*
index be8f044..053953c 100644 (file)
@@ -42,7 +42,7 @@ public class PfamSeed extends Pfam
   @Override
   protected String getXFAMURL()
   {
-    return "http://pfam.sanger.ac.uk/family/alignment/download/format?alnType=seed&format=stockholm&order=t&case=l&gaps=default&entry=";
+    return "http://pfam.xfam.org/family/alignment/download/format?alnType=seed&format=stockholm&order=t&case=l&gaps=default&entry=";
   }
 
   /*
index e1e9e9a..3053363 100644 (file)
@@ -42,7 +42,8 @@ public class RfamFull extends Rfam
   @Override
   protected String getXFAMURL()
   {
-    return "http://rfam.sanger.ac.uk/family/alignment/download/format?alnType=full&nseLabels=0&format=stockholm&acc=";
+    return "http://rfam.xfam.org/family/alignment/download/format?alnType=full&nseLabels=0&format=stockholm&acc=";
+
   }
 
   /*
index 2850fd5..77fb841 100644 (file)
@@ -42,11 +42,16 @@ public class RfamSeed extends Rfam
   @Override
   protected String getXFAMURL()
   {
-    return "http://rfam.sanger.ac.uk/family/alignment/download/format?alnType=seed&nseLabels=0&format=stockholm&acc=";
+    return "http://rfam.xfam.org/family/";
     // Janelia Farms url
     // "http://rfam.janelia.org/cgi-bin/getalignment?type=seed&fmt=stockholm&acc=";
   }
 
+  @Override
+  public String getXFAMURLSUFFIX()
+  {
+    return "/alignment";
+  }
   /*
    * (non-Javadoc)
    * 
index 17f1842..8cc0ce4 100644 (file)
@@ -165,7 +165,7 @@ public class Uniprot extends DbSourceProxyImpl
       // uniprotxml parameter required since december 2007
       // uniprotkb dbname changed introduced december 2008
       File file = ebi.fetchDataAsFile("uniprotkb:" + queries, "uniprotxml",
-              null, ".xml");
+              ".xml");
       Vector<UniprotEntry> entries = getUniprotEntries(new FileReader(file));
 
       if (entries != null)
index 26c9997..508047d 100644 (file)
@@ -55,7 +55,9 @@ public abstract class Xfam extends DbSourceProxyImpl
     startQuery();
     // TODO: trap HTTP 404 exceptions and return null
     AlignmentI rcds = new FormatAdapter().readFile(getXFAMURL()
-            + queries.trim().toUpperCase(), FormatAdapter.URL, "STH");
+            + queries.trim().toUpperCase() + getXFAMURLSUFFIX(),
+            jalview.io.FormatAdapter.URL,
+            "STH");
     for (int s = 0, sNum = rcds.getHeight(); s < sNum; s++)
     {
       rcds.getSequenceAt(s).addDBRef(new DBRefEntry(getXfamSource(),
@@ -81,4 +83,14 @@ public abstract class Xfam extends DbSourceProxyImpl
     return true;
   }
 
+  /**
+   * default suffix to append the retrieval URL for this source.
+   * 
+   * @return "" for most Xfam sources
+   */
+  public String getXFAMURLSUFFIX()
+  {
+    return "";
+  }
+
 }
index 9f6bc65..1dff32f 100644 (file)
@@ -42,9 +42,6 @@ import java.util.StringTokenizer;
  */
 public class EBIFetchClient
 {
-  String format = "default";
-
-  String style = "raw";
 
   /**
    * Creates a new EBIFetchClient object.
@@ -93,14 +90,13 @@ public class EBIFetchClient
    *          the query formatted as db:query1;query2;query3
    * @param format
    *          the format wanted
-   * @param s
-   *          - unused parameter
+   * @param extension
+   *          for the temporary file to hold response
    * @return the file holding the response
    * @throws OutOfMemoryError
    */
 
-  public File fetchDataAsFile(String ids, String format, String s,
-          String ext)
+  public File fetchDataAsFile(String ids, String format, String ext)
           throws OutOfMemoryError
   {
     File outFile = null;
@@ -108,7 +104,7 @@ public class EBIFetchClient
     {
       outFile = File.createTempFile("jalview", ext);
       outFile.deleteOnExit();
-      fetchData(ids, format, s, outFile);
+      fetchData(ids, format, outFile);
       if (outFile.length() == 0)
       {
         outFile.delete();
@@ -121,92 +117,92 @@ public class EBIFetchClient
   }
 
   /**
-   * Single DB multiple record retrieval
+   * Fetches queries and either saves the response to a file or returns as
+   * string data
    * 
    * @param ids
-   *          db:query1;query2;query3
    * @param format
-   *          raw/xml
-   * @param s
-   *          not used - remove?
-   * 
-   * @return Raw string array result of query set
+   * @param outFile
+   * @return
+   * @throws OutOfMemoryError
    */
-  public String[] fetchData(String ids, String format, String s)
+  String[] fetchData(String ids, String format, File outFile)
           throws OutOfMemoryError
   {
-    return fetchData(ids, format, s, null);
+    StringBuilder querystring = new StringBuilder(ids.length());
+    String database = parseIds(ids, querystring);
+    if (database == null)
+    {
+      System.err.println("Invalid Query string : '" + ids + "'");
+      System.err.println("Should be of form 'dbname:q1;q2;q3;q4'");
+      return null;
+    }
+
+    // note: outFile is currently always specified, so return value is null
+    String[] rslt = fetchBatch(querystring.toString(), database, format, outFile);
+
+    return (rslt != null && rslt.length > 0 ? rslt : null);
   }
 
-  String[] fetchData(String ids, String f, String s, File outFile)
-          throws OutOfMemoryError
+  /**
+   * Parses ids formatted as dbname:q1;q2;q3, returns the dbname and adds
+   * queries as comma-separated items to the querystring. dbname must be
+   * specified for at least one queryId. Returns null if a mixture of different
+   * dbnames is found (ignoring case).
+   * 
+   * @param ids
+   * @param queryString
+   * @return
+   */
+  static String parseIds(String ids, StringBuilder queryString)
   {
-    // Need to split
-    // ids of the form uniprot:25KD_SARPE;ADHR_DROPS;
-    String[] rslts = new String[0];
+    String database = null;
     StringTokenizer queries = new StringTokenizer(ids, ";");
-    String db = null;
-    StringBuffer querystring = null;
-    int nq = 0;
+    boolean appending = queryString.length() > 0;
     while (queries.hasMoreTokens())
     {
       String query = queries.nextToken();
-      int p;
-      if ((p = query.indexOf(':')) > -1)
+      int p = query.indexOf(':');
+      if (p > -1)
       {
-        db = query.substring(0, p);
+        String db = query.substring(0, p);
+        if (database != null && !db.equalsIgnoreCase(database))
+        {
+          /*
+           * different databases mixed in together - invalid
+           */
+          return null;
+        }
+        database = db;
         query = query.substring(p + 1);
       }
-      if (querystring == null)
-      {
-        querystring = new StringBuffer(query);
-        nq++;
-      }
-      else
-      {
-        querystring.append("," + query);
-        nq++;
-      }
-    }
-    if (db == null)
-    {
-      System.err.println("Invalid Query string : '" + ids
-              + "'\nShould be of form 'dbname:q1;q2;q3;q4'");
-      return null;
-    }
-    String[] rslt = fetchBatch(querystring.toString(), db, f, s, outFile);
-    if (rslt != null)
-    {
-      String[] nrslts = new String[rslt.length + rslts.length];
-      System.arraycopy(rslts, 0, nrslts, 0, rslts.length);
-      System.arraycopy(rslt, 0, nrslts, rslts.length, rslt.length);
-      rslts = nrslts;
+      queryString.append(appending ? "," : "");
+      queryString.append(query);
+      appending = true;
     }
-
-    return (rslts.length == 0 ? null : rslts);
+    return database;
   }
 
-  public String[] fetchBatch(String ids, String dbPath, String format, String s,
+  /**
+   * Fetches queries and either saves the response to a file or (if no file
+   * specified) returns as string data
+   * 
+   * @param ids
+   * @param database
+   * @param format
+   * @param outFile
+   * @return
+   * @throws OutOfMemoryError
+   */
+  String[] fetchBatch(String ids, String database, String format,
           File outFile) throws OutOfMemoryError
   {
     // long time = System.currentTimeMillis();
-    /*
-     * JAL-1855 dbfetch from ena_sequence, ena_coding
-     */
-    if (dbPath.equalsIgnoreCase(DBRefSource.EMBL))
-    {
-      dbPath = "ena_sequence";
-    }
-    else if (dbPath.equalsIgnoreCase(DBRefSource.EMBLCDS))
-    {
-      dbPath = "ena_coding";
-    }
+    String url = buildUrl(ids, database, format);
 
     try
     {
-      URL rcall = new URL("http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/"
-              + dbPath.toLowerCase() + "/" + ids.toLowerCase()
-              + (format != null ? "/" + format : ""));
+      URL rcall = new URL(url);
 
       InputStream is = new BufferedInputStream(rcall.openStream());
       if (outFile != null)
@@ -234,8 +230,7 @@ public class EBIFetchClient
       }
     } catch (OutOfMemoryError er)
     {
-
-      System.out.println("OUT OF MEMORY DOWNLOADING QUERY FROM " + dbPath
+      System.out.println("OUT OF MEMORY DOWNLOADING QUERY FROM " + database
               + ":\n" + ids);
       throw er;
     } catch (Exception ex)
@@ -246,7 +241,7 @@ public class EBIFetchClient
         return null;
       }
       System.err.println("Unexpected exception when retrieving from "
-              + dbPath
+              + database
               + "\nQuery was : '" + ids + "'");
       ex.printStackTrace(System.err);
       return null;
@@ -257,4 +252,30 @@ public class EBIFetchClient
     }
     return null;
   }
+
+  /**
+   * Constructs the URL to fetch from
+   * 
+   * @param ids
+   * @param database
+   * @param format
+   * @return
+   */
+  static String buildUrl(String ids, String database, String format)
+  {
+    String url;
+    if (database.equalsIgnoreCase(DBRefSource.EMBL)
+            || database.equalsIgnoreCase(DBRefSource.EMBLCDS))
+    {
+      url = "http://www.ebi.ac.uk/ena/data/view/" + ids.toLowerCase()
+              + (format != null ? "&" + format : "");
+    }
+    else
+    {
+      url = "http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/"
+              + database.toLowerCase() + "/" + ids.toLowerCase()
+              + (format != null ? "/" + format : "");
+    }
+    return url;
+  }
 }
index c0b701b..8855d96 100644 (file)
@@ -256,11 +256,8 @@ public abstract class Jws2Client extends jalview.ws.WSClient
       });
       wsmenu.add(aaConEnabled);
       final JMenuItem modifyParams = new JMenuItem(aaui.getAAeditSettings());
-      modifyParams
-              .setToolTipText("<html><p>"
-                      + JvSwingUtils.wrapTooltip(false,
-                              aaui.getAAeditSettingsTooltip() + "</p>")
-                      + "</html>");
+      modifyParams.setToolTipText(JvSwingUtils.wrapTooltip(true,
+              aaui.getAAeditSettingsTooltip()));
       modifyParams.addActionListener(new ActionListener()
       {
 
index 47130a3..c83ef0f 100644 (file)
@@ -216,6 +216,7 @@ public class MsaWSClient extends Jws2Client
     return (WebServiceName.indexOf("lustal") > -1); // cheat!
   }
 
+  @Override
   public void attachWSMenuEntry(JMenu rmsawsmenu,
           final Jws2Instance service, final AlignFrame alignFrame)
   {
@@ -263,6 +264,7 @@ public class MsaWSClient extends Jws2Client
 
       method.addActionListener(new ActionListener()
       {
+        @Override
         public void actionPerformed(ActionEvent e)
         {
           AlignmentView msa = alignFrame.gatherSequencesForAlignment();
@@ -288,6 +290,7 @@ public class MsaWSClient extends Jws2Client
 
         method.addActionListener(new ActionListener()
         {
+          @Override
           public void actionPerformed(ActionEvent e)
           {
             AlignmentView msa = alignFrame.gatherSequencesForAlignment();
@@ -335,17 +338,19 @@ public class MsaWSClient extends Jws2Client
               }
 
             });
-            methodR.setToolTipText(JvSwingUtils.wrapTooltip(
+            String tooltip = JvSwingUtils.wrapTooltip(
                     true,
-                    "<p><strong>"
+                            "<strong>"
                             + (preset.isModifiable() ? MessageManager
                                     .getString("label.user_preset")
                                     : MessageManager
                                             .getString("label.service_preset"))
-                            + "</strong><br/>" + preset.getDescription()
-                            + "</p>"));
+                                    + "</strong><br/>"
+                                    + preset.getDescription());
+            methodR.setToolTipText(tooltip);
             methodR.addActionListener(new ActionListener()
             {
+              @Override
               public void actionPerformed(ActionEvent e)
               {
                 AlignmentView msa = alignFrame
index e04bbb7..6c11dd2 100644 (file)
@@ -96,11 +96,9 @@ public class SiftsClient implements SiftsClientI
 
   private static final int PDB_ATOM_POS = 1;
 
-  private static final String NOT_FOUND = "Not_Found";
-
   private static final String NOT_OBSERVED = "Not_Observed";
 
-  private static final String SIFTS_FTP_BASE_URL = "ftp://ftp.ebi.ac.uk/pub/databases/msd/sifts/xml/";
+  private static final String SIFTS_FTP_BASE_URL = "http://ftp.ebi.ac.uk/pub/databases/msd/sifts/xml/";
 
   private final static String NEWLINE = System.lineSeparator();
 
@@ -225,8 +223,9 @@ public class SiftsClient implements SiftsClientI
    */
   public static File getSiftsFile(String pdbId) throws SiftsException
   {
-    File siftsFile = new File(SiftsSettings.getSiftDownloadDirectory()
-            + pdbId.toLowerCase() + ".xml.gz");
+    String siftsFileName = SiftsSettings.getSiftDownloadDirectory()
+            + pdbId.toLowerCase() + ".xml.gz";
+    File siftsFile = new File(siftsFileName);
     if (siftsFile.exists())
     {
       // The line below is required for unit testing... don't comment it out!!!
@@ -235,12 +234,28 @@ public class SiftsClient implements SiftsClientI
       if (isFileOlderThanThreshold(siftsFile,
               SiftsSettings.getCacheThresholdInDays()))
       {
-        // System.out.println("Downloaded file is out of date, hence re-downloading...");
-        siftsFile = downloadSiftsFile(pdbId.toLowerCase());
+        File oldSiftsFile = new File(siftsFileName + "_old");
+        siftsFile.renameTo(oldSiftsFile);
+        try
+        {
+          siftsFile = downloadSiftsFile(pdbId.toLowerCase());
+          oldSiftsFile.delete();
+          return siftsFile;
+        } catch (IOException e)
+        {
+          e.printStackTrace();
+          oldSiftsFile.renameTo(siftsFile);
+          return new File(siftsFileName);
+        }
       }
-      return siftsFile;
     }
-    siftsFile = downloadSiftsFile(pdbId.toLowerCase());
+    try
+    {
+      siftsFile = downloadSiftsFile(pdbId.toLowerCase());
+    } catch (IOException e)
+    {
+      throw new SiftsException(e.getMessage());
+    }
     return siftsFile;
   }
 
@@ -278,8 +293,10 @@ public class SiftsClient implements SiftsClientI
    * @param pdbId
    * @return downloaded SIFTs XML file
    * @throws SiftsException
+   * @throws IOException
    */
-  public static File downloadSiftsFile(String pdbId) throws SiftsException
+  public static File downloadSiftsFile(String pdbId) throws SiftsException,
+          IOException
   {
     if (pdbId.contains(".cif"))
     {
@@ -295,8 +312,6 @@ public class SiftsClient implements SiftsClientI
     {
       siftsDownloadDir.mkdirs();
     }
-    try
-    {
       // System.out.println(">> Download ftp url : " + siftsFileFTPURL);
       URL url = new URL(siftsFileFTPURL);
       URLConnection conn = url.openConnection();
@@ -312,10 +327,6 @@ public class SiftsClient implements SiftsClientI
       outputStream.close();
       inputStream.close();
       // System.out.println(">>> File downloaded : " + downloadedSiftsFile);
-    } catch (IOException ex)
-    {
-      throw new SiftsException(ex.getMessage());
-    }
     return new File(downloadedSiftsFile);
   }
 
@@ -360,7 +371,8 @@ public class SiftsClient implements SiftsClientI
       DBRefEntry[] dbRefs = seq.getDBRefs();
       if (dbRefs == null || dbRefs.length < 1)
       {
-        throw new SiftsException("Could not get source DB Ref");
+        throw new SiftsException(
+                "Source DBRef could not be determined. DBRefs might not have been retrieved.");
       }
 
       for (DBRefEntryI dbRef : dbRefs)
@@ -374,6 +386,7 @@ public class SiftsClient implements SiftsClientI
                 && (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT) || dbRef
                         .getSource().equalsIgnoreCase(DBRefSource.PDB)))
         {
+          seq.setSourceDBRef(dbRef);
           return dbRef;
         }
       }
@@ -413,7 +426,8 @@ public class SiftsClient implements SiftsClientI
                 .getMapRegion();
         for (MapRegion mapRegion : mapRegions)
         {
-          accessions.add(mapRegion.getDb().getDbAccessionId());
+          accessions
+                  .add(mapRegion.getDb().getDbAccessionId().toLowerCase());
         }
       }
     }
@@ -464,12 +478,9 @@ public class SiftsClient implements SiftsClientI
             jalview.util.Comparison.GapChars, seq.getSequenceAsString());
     HashMap<Integer, int[]> mapping = new HashMap<Integer, int[]>();
     DBRefEntryI sourceDBRef = seq.getSourceDBRef();
-    if (sourceDBRef == null)
-    {
-      sourceDBRef = getValidSourceDBRef(seq);
-      // TODO ensure sequence start/end is in the same coordinate system and
-      // consistent with the choosen sourceDBRef
-    }
+    sourceDBRef = getValidSourceDBRef(seq);
+    // TODO ensure sequence start/end is in the same coordinate system and
+    // consistent with the choosen sourceDBRef
 
     // set sequence coordinate system - default value is UniProt
     if (sourceDBRef.getSource().equalsIgnoreCase(DBRefSource.PDB))
@@ -752,8 +763,9 @@ public class SiftsClient implements SiftsClientI
 
   private boolean isFoundInSiftsEntry(String accessionId)
   {
+    HashSet<String> siftsDBRefs = getAllMappingAccession();
     return accessionId != null
-            && getAllMappingAccession().contains(accessionId);
+            && siftsDBRefs.contains(accessionId.toLowerCase());
   }
 
   /**
index 860d979..2fc5325 100644 (file)
@@ -1968,60 +1968,65 @@ public class AlignmentUtilsTests
     SequenceFeature sf = sfs[0];
     assertEquals(1, sf.getBegin());
     assertEquals(1, sf.getEnd());
-    assertEquals("K->E", sf.getDescription());
+    assertEquals("p.Lys1Glu", sf.getDescription());
     assertEquals("var1.125A>G", sf.getValue("ID"));
     assertNull(sf.getValue("clinical_significance"));
     assertEquals("ID=var1.125A>G", sf.getAttributes());
     assertEquals(1, sf.links.size());
     // link to variation is urlencoded
     assertEquals(
-            "K->E var1.125A>G|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var1.125A%3EG",
+            "p.Lys1Glu var1.125A>G|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var1.125A%3EG",
             sf.links.get(0));
+    assertEquals("Jalview", sf.getFeatureGroup());
     sf = sfs[1];
     assertEquals(1, sf.getBegin());
     assertEquals(1, sf.getEnd());
-    assertEquals("K->Q", sf.getDescription());
+    assertEquals("p.Lys1Gln", sf.getDescription());
     assertEquals("var2", sf.getValue("ID"));
     assertEquals("Dodgy", sf.getValue("clinical_significance"));
     assertEquals("ID=var2;clinical_significance=Dodgy", sf.getAttributes());
     assertEquals(1, sf.links.size());
     assertEquals(
-            "K->Q var2|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var2",
+            "p.Lys1Gln var2|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var2",
             sf.links.get(0));
+    assertEquals("Jalview", sf.getFeatureGroup());
     sf = sfs[2];
     assertEquals(1, sf.getBegin());
     assertEquals(1, sf.getEnd());
-    assertEquals("K->N", sf.getDescription());
+    assertEquals("p.Lys1Asn", sf.getDescription());
     assertEquals("var4", sf.getValue("ID"));
     assertEquals("Benign", sf.getValue("clinical_significance"));
     assertEquals("ID=var4;clinical_significance=Benign", sf.getAttributes());
     assertEquals(1, sf.links.size());
     assertEquals(
-            "K->N var4|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var4",
+            "p.Lys1Asn var4|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var4",
             sf.links.get(0));
+    assertEquals("Jalview", sf.getFeatureGroup());
     sf = sfs[3];
     assertEquals(3, sf.getBegin());
     assertEquals(3, sf.getEnd());
-    assertEquals("P->H", sf.getDescription());
+    assertEquals("p.Pro3His", sf.getDescription());
     assertEquals("var6", sf.getValue("ID"));
     assertEquals("Good", sf.getValue("clinical_significance"));
     assertEquals("ID=var6;clinical_significance=Good", sf.getAttributes());
     assertEquals(1, sf.links.size());
     assertEquals(
-            "P->H var6|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var6",
+            "p.Pro3His var6|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var6",
             sf.links.get(0));
     // var5 generates two distinct protein variant features
+    assertEquals("Jalview", sf.getFeatureGroup());
     sf = sfs[4];
     assertEquals(3, sf.getBegin());
     assertEquals(3, sf.getEnd());
-    assertEquals("P->R", sf.getDescription());
+    assertEquals("p.Pro3Arg", sf.getDescription());
     assertEquals("var6", sf.getValue("ID"));
     assertEquals("Good", sf.getValue("clinical_significance"));
     assertEquals("ID=var6;clinical_significance=Good", sf.getAttributes());
     assertEquals(1, sf.links.size());
     assertEquals(
-            "P->R var6|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var6",
+            "p.Pro3Arg var6|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var6",
             sf.links.get(0));
+    assertEquals("Jalview", sf.getFeatureGroup());
   }
 
   /**
index eb0fc47..9d3e3b6 100644 (file)
@@ -50,6 +50,10 @@ public class SequenceIdMatcherTest
     assertTrue(testee.equals("A12345,"));
     assertTrue(testee.equals("A12345?"));
     assertTrue(testee.equals("A12345_"));
+    /*
+     * case insensitive matching
+     */
+    assertTrue(testee.equals("a12345"));
 
     /*
      * matcher name = target name + word separator...
@@ -58,13 +62,21 @@ public class SequenceIdMatcherTest
     assertTrue(testee.equals("A12345"));
 
     /*
+     * case insensitive matching
+     */
+    assertTrue(testee.equals("a12345"));
+
+    /*
      * miscellaneous failing cases
      */
     testee = sequenceIdMatcher.new SeqIdName("A12345");
     assertFalse(testee.equals((Object) null));
     assertFalse(testee.equals(""));
-    assertFalse(testee.equals("a12345"));
     assertFalse(testee.equals("A12346|A12345"));
+    /*
+     * case insensitive matching
+     */
+    assertTrue(testee.equals("a12345"));
 
     testee = sequenceIdMatcher.new SeqIdName("A12345?B23456");
     assertFalse(testee.equals("B23456"));
@@ -74,5 +86,9 @@ public class SequenceIdMatcherTest
     testee = sequenceIdMatcher.new SeqIdName("A12345<");
     assertFalse(testee.equals("A12345?"));
     assertTrue(testee.equals("A12345<")); // bug? inconsistent
+    /*
+     * case insensitive matching
+     */
+    assertTrue(testee.equals("a12345"));
   }
 }
diff --git a/test/jalview/bin/ArgsParserTest.java b/test/jalview/bin/ArgsParserTest.java
new file mode 100644 (file)
index 0000000..06e79de
--- /dev/null
@@ -0,0 +1,65 @@
+package jalview.bin;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertTrue;
+
+import org.testng.annotations.Test;
+
+public class ArgsParserTest
+{
+  @Test(groups = "Functional")
+  public void testGetValue()
+  {
+    ArgsParser ap = new ArgsParser(new String[] { "-name", "Henry", "-job",
+        "Tester" });
+    assertEquals(4, ap.getSize());
+    assertNull(ap.getValue("rubbish"));
+    assertEquals("Tester", ap.getValue("job"));
+    // call to getValue removes the argument and its value
+    assertEquals(2, ap.getSize());
+    assertNull(ap.getValue("job"));
+    assertFalse(ap.contains("job"));
+    assertFalse(ap.contains("Tester"));
+
+    assertEquals("Henry", ap.getValue("name"));
+    assertEquals(0, ap.getSize());
+    assertNull(ap.getValue("name"));
+  }
+
+  @Test(groups = "Functional")
+  public void testGetValue_decoded()
+  {
+    ArgsParser ap = new ArgsParser(new String[] { "-name%241", "Henry",
+        "-job", "Test%203%2a" });
+    // parameter value is decoded
+    assertEquals("Test 3*", ap.getValue("job", true));
+    // parameter name is not decoded
+    assertNull(ap.getValue("name$1", true));
+    assertEquals("Henry", ap.getValue("name%241", true));
+  }
+
+  @Test(groups = "Functional")
+  public void testNextValue()
+  {
+    ArgsParser ap = new ArgsParser(new String[] { "-name", "Henry", "-job",
+        "Tester" });
+    assertEquals("name", ap.nextValue());
+    assertEquals("Henry", ap.nextValue());
+    assertEquals("job", ap.nextValue());
+    assertEquals("Tester", ap.nextValue());
+  }
+
+  @Test(groups = "Functional")
+  public void testContains()
+  {
+    ArgsParser ap = new ArgsParser(new String[] { "-name", "Henry", "-job",
+        "Tester" });
+    assertFalse(ap.contains("Susan"));
+    assertFalse(ap.contains("-name"));
+    assertTrue(ap.contains("name"));
+    // testing for contains removes the argument
+    assertFalse(ap.contains("name"));
+  }
+}
index 0245b15..1a7ae32 100644 (file)
@@ -93,6 +93,83 @@ public class ColumnSelectionTest
     assertEquals(2, cs.findColumnPosition(5));
   }
 
+  /**
+   * Test the code used to locate the reference sequence ruler origin
+   */
+  @Test(groups = { "Functional" })
+  public void testLocateVisibleBoundsofSequence()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---");
+    assertEquals(2, seq.findIndex(seq.getStart()));
+
+    // no hidden columns
+    assertEquals(
+            Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
+                seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+    // hidden column on gap after end of sequence - should not affect bounds
+    cs.hideColumns(13);
+    assertEquals(
+            Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
+                seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+    cs.revealAllHiddenColumns();
+    // hidden column on gap before beginning of sequence - should vis bounds by
+    // one
+    cs.hideColumns(0);
+    assertEquals(
+            Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 2,
+                seq.findIndex(seq.getEnd()) - 2, seq.getStart(),
+                seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+    cs.revealAllHiddenColumns();
+    // hide columns around most of sequence - leave one residue remaining
+    cs.hideColumns(1, 3);
+    cs.hideColumns(6, 11);
+    assertEquals("-D",
+            cs.getVisibleSequenceStrings(0, 5, new SequenceI[] { seq })[0]);
+    assertEquals(
+            Arrays.toString(new int[] { 1, 1, 3, 3,
+                seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+    cs.revealAllHiddenColumns();
+
+    // hide whole sequence - should just get location of hidden region
+    // containing sequence
+    cs.hideColumns(1, 11);
+    assertEquals(
+            Arrays.toString(new int[] { 0, 1, 0, 0,
+                seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+  }
+
+  @Test(groups={"Functional"})
+  public void testLocateVisibleBoundsPathologicals()
+  {
+    // test some pathological cases we missed
+    AlignmentI al = new Alignment(new SequenceI[] { new Sequence("refseqGaptest","KTDVTI----------NFI-----G----L")});
+    ColumnSelection cs = new ColumnSelection();
+    cs.hideInsertionsFor(al.getSequenceAt(0));
+    assertEquals(
+            "G",
+            ""
+                    + al.getSequenceAt(0).getCharAt(
+                            cs.adjustForHiddenColumns(9)));
+
+
+  }
   @Test(groups = { "Functional" })
   public void testHideColumns()
   {
@@ -401,4 +478,53 @@ public class ColumnSelectionTest
     cs.addElement(0);
     assertEquals(0, cs.getMin());
   }
+
+  @Test(groups = { "Functional" })
+  public void testEquals()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(0);
+    cs.addElement(513);
+    cs.addElement(1);
+    cs.hideColumns(3);
+    cs.hideColumns(7);
+    cs.hideColumns(5,9);
+
+    // same selections added in a different order
+    ColumnSelection cs2 = new ColumnSelection();
+    cs2.addElement(1);
+    cs2.addElement(513);
+    cs2.addElement(0);
+
+    // with no hidden columns
+    assertFalse(cs.equals(cs2));
+    assertFalse(cs2.equals(cs));
+
+    // with hidden columns added in a different order
+    cs2.hideColumns(6, 9);
+    cs2.hideColumns(5, 8);
+    cs2.hideColumns(3);
+    
+    assertTrue(cs.equals(cs2));
+    assertTrue(cs.equals(cs));
+    assertTrue(cs2.equals(cs));
+    assertTrue(cs2.equals(cs2));
+
+    cs2.addElement(12);
+    assertFalse(cs.equals(cs2));
+    assertFalse(cs2.equals(cs));
+
+    cs2.removeElement(12);
+    assertTrue(cs.equals(cs2));
+
+    cs2.hideColumns(88);
+    assertFalse(cs.equals(cs2));
+    /*
+     * unhiding a column adds it to selection!
+     */
+    cs2.revealHiddenColumns(88);
+    assertFalse(cs.equals(cs2));
+    cs.addElement(88);
+    assertTrue(cs.equals(cs2));
+  }
 }
index b3376a6..ae6dcda 100644 (file)
@@ -20,7 +20,9 @@
  */
 package jalview.datamodel;
 
+import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.util.MapList;
@@ -60,4 +62,80 @@ public class DBRefEntryTest
     assertTrue(ref1.equalRef(ref2));
     assertTrue(ref2.equalRef(ref1));
   }
+
+  /**
+   * Tests for the method that may update a DBRefEntry from another with a
+   * mapping or 'real' version
+   */
+  @Test(groups = { "Functional" })
+  public void testUpdateFrom()
+  {
+    DBRefEntry ref1 = new DBRefEntry("UNIPROT", "1", "V71633");
+
+    assertFalse(ref1.updateFrom(null));
+
+    /*
+     * equivalent other dbref
+     */
+    DBRefEntry ref2 = new DBRefEntry("uniprot", "1", "v71633");
+    assertTrue(ref1.updateFrom(ref2));
+    assertEquals("UNIPROT", ref1.getSource()); // unchanged
+    assertEquals("V71633", ref1.getAccessionId()); // unchanged
+  
+    /*
+     * ref1 has no mapping, acquires mapping from ref2
+     */
+    Mapping map = new Mapping(new MapList(new int[] { 1, 3 }, new int[] {
+        1, 1 }, 3, 1));
+    ref2.setMap(map);
+    assertTrue(ref1.updateFrom(ref2));
+    assertSame(map, ref1.getMap()); // null mapping updated
+
+    /*
+     * ref1 has a mapping, does not acquire mapping from ref2
+     */
+    ref2.setMap(new Mapping(map));
+    assertTrue(ref1.updateFrom(ref2));
+    assertSame(map, ref1.getMap()); // non-null mapping not updated
+
+    /*
+     * ref2 has a different source, accession or version
+     */
+    ref2.setSource("pdb");
+    assertFalse(ref1.updateFrom(ref2));
+    ref2.setSource(ref1.getSource());
+    ref2.setAccessionId("P12345");
+    assertFalse(ref1.updateFrom(ref2));
+    ref2.setAccessionId(ref1.getAccessionId());
+    ref1.setVersion("2");
+    assertFalse(ref1.updateFrom(ref2));
+
+    /*
+     * a non-null version supersedes "0" or "source:0"
+     */
+    ref2.setVersion(null);
+    assertFalse(ref1.updateFrom(ref2));
+    assertEquals("2", ref1.getVersion());
+    ref2.setVersion("3");
+    ref1.setVersion("0");
+    assertTrue(ref1.updateFrom(ref2));
+    assertEquals("3", ref1.getVersion());
+    ref1.setVersion("UNIPROT:0");
+    assertTrue(ref1.updateFrom(ref2));
+    assertEquals("3", ref1.getVersion());
+
+    /*
+     * version "source:n" with n>0 is not superseded
+     */
+    ref1.setVersion("UNIPROT:1");
+    assertFalse(ref1.updateFrom(ref2));
+    assertEquals("UNIPROT:1", ref1.getVersion());
+
+    /*
+     * version "10" is not superseded
+     */
+    ref1.setVersion("10");
+    assertFalse(ref1.updateFrom(ref2));
+    assertEquals("10", ref1.getVersion());
+  }
 }
index ab11c09..17dfcdc 100644 (file)
@@ -29,11 +29,14 @@ import static org.testng.AssertJUnit.assertTrue;
 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
 
 import jalview.datamodel.PDBEntry.Type;
+import jalview.util.MapList;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Vector;
 
+import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
@@ -397,7 +400,71 @@ public class SequenceTest
     sq.setStart(3);
     sq.setEnd(4);
 
+    sq.setDescription("Test sequence description..");
+    sq.setVamsasId("TestVamsasId");
+    sq.setSourceDBRef(new DBRefEntry("PDB", "version0", "1TST"));
+
+    sq.addDBRef(new DBRefEntry("PDB", "version1", "1Tst"));
+    sq.addDBRef(new DBRefEntry("PDB", "version2", "2Tst"));
+    sq.addDBRef(new DBRefEntry("PDB", "version3", "3Tst"));
+    sq.addDBRef(new DBRefEntry("PDB", "version4", "4Tst"));
+
+    sq.addPDBId(new PDBEntry("1PDB", "A", Type.PDB, "filePath/test1"));
+    sq.addPDBId(new PDBEntry("1PDB", "B", Type.PDB, "filePath/test1"));
+    sq.addPDBId(new PDBEntry("2PDB", "A", Type.MMCIF, "filePath/test2"));
+    sq.addPDBId(new PDBEntry("2PDB", "B", Type.MMCIF, "filePath/test2"));
+
+    sq.getDatasetSequence().addDBRef(
+            new DBRefEntry("PDB", "version1", "1Tst"));
+    sq.getDatasetSequence().addDBRef(
+            new DBRefEntry("PDB", "version2", "2Tst"));
+    sq.getDatasetSequence().addDBRef(
+            new DBRefEntry("PDB", "version3", "3Tst"));
+    sq.getDatasetSequence().addDBRef(
+            new DBRefEntry("PDB", "version4", "4Tst"));
+
+    sq.getDatasetSequence().addPDBId(
+            new PDBEntry("1PDB", "A", Type.PDB, "filePath/test1"));
+    sq.getDatasetSequence().addPDBId(
+            new PDBEntry("1PDB", "B", Type.PDB, "filePath/test1"));
+    sq.getDatasetSequence().addPDBId(
+            new PDBEntry("2PDB", "A", Type.MMCIF, "filePath/test2"));
+    sq.getDatasetSequence().addPDBId(
+            new PDBEntry("2PDB", "B", Type.MMCIF, "filePath/test2"));
+
+    ArrayList<Annotation> annotsList = new ArrayList<Annotation>();
+    System.out.println(">>>>>> " + sq.getSequenceAsString().length());
+    annotsList.add(new Annotation("A", "A", 'X', 0.1f));
+    annotsList.add(new Annotation("A", "A", 'X', 0.1f));
+    Annotation[] annots = annotsList.toArray(new Annotation[0]);
+    sq.addAlignmentAnnotation(new AlignmentAnnotation("Test annot",
+            "Test annot description", annots));
+    sq.getDatasetSequence().addAlignmentAnnotation(
+            new AlignmentAnnotation("Test annot", "Test annot description",
+                    annots));
+    Assert.assertEquals(sq.getDescription(), "Test sequence description..");
+    Assert.assertEquals(sq.getDBRefs().length, 4);
+    Assert.assertEquals(sq.getAllPDBEntries().size(), 4);
+    Assert.assertNotNull(sq.getAnnotation());
+    Assert.assertEquals(sq.getAnnotation()[0].annotations.length, 2);
+    Assert.assertEquals(sq.getDatasetSequence().getDBRefs().length, 4);
+    Assert.assertEquals(sq.getDatasetSequence().getAllPDBEntries().size(),
+            4);
+    Assert.assertNotNull(sq.getDatasetSequence().getAnnotation());
+
     Sequence derived = (Sequence) sq.deriveSequence();
+
+    Assert.assertEquals(derived.getDescription(),
+            "Test sequence description..");
+    Assert.assertEquals(derived.getDBRefs().length, 4);
+    Assert.assertEquals(derived.getAllPDBEntries().size(), 4);
+    Assert.assertNotNull(derived.getAnnotation());
+    Assert.assertEquals(derived.getAnnotation()[0].annotations.length, 2);
+    Assert.assertEquals(derived.getDatasetSequence().getDBRefs().length, 4);
+    Assert.assertEquals(derived.getDatasetSequence().getAllPDBEntries()
+            .size(), 4);
+    Assert.assertNotNull(derived.getDatasetSequence().getAnnotation());
+
     assertEquals("CD", derived.getSequenceAsString());
     assertSame(sq.getDatasetSequence(), derived.getDatasetSequence());
 
@@ -550,4 +617,85 @@ public class SequenceTest
     assertEquals(' ', sq.getCharAt(5));
     assertEquals(' ', sq.getCharAt(-1));
   }
+
+  /**
+   * Tests for adding (or updating) dbrefs
+   * 
+   * @see DBRefEntry#updateFrom(DBRefEntry)
+   */
+  @Test(groups = { "Functional" })
+  public void testAddDBRef()
+  {
+    SequenceI sq = new Sequence("", "abcde");
+    assertNull(sq.getDBRefs());
+    DBRefEntry dbref = new DBRefEntry("Uniprot", "1", "P00340");
+    sq.addDBRef(dbref);
+    assertEquals(1, sq.getDBRefs().length);
+    assertSame(dbref, sq.getDBRefs()[0]);
+
+    /*
+     * change of version - new entry
+     */
+    DBRefEntry dbref2 = new DBRefEntry("Uniprot", "2", "P00340");
+    sq.addDBRef(dbref2);
+    assertEquals(2, sq.getDBRefs().length);
+    assertSame(dbref, sq.getDBRefs()[0]);
+    assertSame(dbref2, sq.getDBRefs()[1]);
+
+    /*
+     * matches existing entry - not added
+     */
+    sq.addDBRef(new DBRefEntry("UNIPROT", "1", "p00340"));
+    assertEquals(2, sq.getDBRefs().length);
+
+    /*
+     * different source = new entry
+     */
+    DBRefEntry dbref3 = new DBRefEntry("UniRef", "1", "p00340");
+    sq.addDBRef(dbref3);
+    assertEquals(3, sq.getDBRefs().length);
+    assertSame(dbref3, sq.getDBRefs()[2]);
+
+    /*
+     * different ref = new entry
+     */
+    DBRefEntry dbref4 = new DBRefEntry("UniRef", "1", "p00341");
+    sq.addDBRef(dbref4);
+    assertEquals(4, sq.getDBRefs().length);
+    assertSame(dbref4, sq.getDBRefs()[3]);
+
+    /*
+     * matching ref with a mapping - map updated
+     */
+    DBRefEntry dbref5 = new DBRefEntry("UniRef", "1", "p00341");
+    Mapping map = new Mapping(new MapList(new int[] { 1, 3 }, new int[] {
+        1, 1 }, 3, 1));
+    dbref5.setMap(map);
+    sq.addDBRef(dbref5);
+    assertEquals(4, sq.getDBRefs().length);
+    assertSame(dbref4, sq.getDBRefs()[3]);
+    assertSame(map, dbref4.getMap());
+
+    /*
+     * 'real' version replaces "0" version
+     */
+    dbref2.setVersion("0");
+    DBRefEntry dbref6 = new DBRefEntry(dbref2.getSource(), "3",
+            dbref2.getAccessionId());
+    sq.addDBRef(dbref6);
+    assertEquals(4, sq.getDBRefs().length);
+    assertSame(dbref2, sq.getDBRefs()[1]);
+    assertEquals("3", dbref2.getVersion());
+
+    /*
+     * 'real' version replaces "source:0" version
+     */
+    dbref3.setVersion("Uniprot:0");
+    DBRefEntry dbref7 = new DBRefEntry(dbref3.getSource(), "3",
+            dbref3.getAccessionId());
+    sq.addDBRef(dbref7);
+    assertEquals(4, sq.getDBRefs().length);
+    assertSame(dbref3, sq.getDBRefs()[2]);
+    assertEquals("3", dbref2.getVersion());
+  }
 }
index 9fffc45..3de5e3f 100644 (file)
@@ -3,10 +3,14 @@ package jalview.datamodel.xdb.embl;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertSame;
 
-import jalview.util.MappingUtils;
+import jalview.analysis.SequenceIdMatcher;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
 
+import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Vector;
+import java.util.List;
 
 import org.testng.annotations.Test;
 
@@ -21,288 +25,94 @@ public class EmblEntryTest
      * Make a (CDS) Feature with 4 locations
      */
     EmblFeature cds = new EmblFeature();
-    Vector<EmblFeatureLocations> locs = new Vector<EmblFeatureLocations>();
-    cds.setLocations(locs);
-
-    /*
-     * single range [10-20]
-     */
-    EmblFeatureLocations loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(false);
-    Vector<EmblFeatureLocElement> elements = new Vector<EmblFeatureLocElement>();
-    EmblFeatureLocElement locElement = new EmblFeatureLocElement();
-    BasePosition b1 = new BasePosition();
-    b1.setPos("10");
-    BasePosition b2 = new BasePosition();
-    b2.setPos("20");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-
-    /*
-     * complement range [30-40]
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(true);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("30");
-    b2 = new BasePosition();
-    b2.setPos("40");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-
-    /*
-     * join range [50-60], [70-80]
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("join");
-    loc.setLocationComplement(false);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("50");
-    b2 = new BasePosition();
-    b2.setPos("60");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("70");
-    b2 = new BasePosition();
-    b2.setPos("80");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-
-    /*
-     * complement range [90-100], [110-120]
-     * this should be the same as complement(join(90..100,110.120))
-     * which is "join 90-100 and 110-120, then complement"
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("join");
-    loc.setLocationComplement(true);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("90");
-    b2 = new BasePosition();
-    b2.setPos("100");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("110");
-    b2 = new BasePosition();
-    b2.setPos("120");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
+    cds.setLocation("join(10..20,complement(30..40),50..60,70..80,complement(110..120))");
 
     int[] exons = testee.getCdsRanges(cds);
-    assertEquals("[10, 20, 40, 30, 50, 60, 70, 80, 120, 110, 100, 90]",
+    assertEquals("[10, 20, 40, 30, 50, 60, 70, 80, 120, 110]",
             Arrays.toString(exons));
   }
 
   @Test(groups = "Functional")
-  public void testGetCdsRanges_badData()
+  public void testParseCodingFeature()
   {
-    EmblEntry testee = new EmblEntry();
+    // not the whole sequence but enough for this test...
+    SequenceI dna = new Sequence("J03321", "GGATCCGTAAGTTAGACGAAATT");
+    List<SequenceI> peptides = new ArrayList<SequenceI>();
+    SequenceIdMatcher matcher = new SequenceIdMatcher(peptides);
+    EmblFile ef = EmblTestHelper.getEmblFile();
 
     /*
-     * Make a (CDS) Feature with 4 locations
-     */
-    EmblFeature cds = new EmblFeature();
-    Vector<EmblFeatureLocations> locs = new Vector<EmblFeatureLocations>();
-    cds.setLocations(locs);
-
-    /*
-     * single range [10-20]
-     */
-    EmblFeatureLocations loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(false);
-    Vector<EmblFeatureLocElement> elements = new Vector<EmblFeatureLocElement>();
-    EmblFeatureLocElement locElement = new EmblFeatureLocElement();
-    BasePosition b1 = new BasePosition();
-    b1.setPos("10");
-    BasePosition b2 = new BasePosition();
-    b2.setPos("20");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-
-    /*
-     * single range with missing end position - should be skipped
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(false);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("30");
-    locElement.setBasePositions(new BasePosition[] { b1 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-
-    /*
-     * single range with extra base position - should be skipped
+     * parse two CDS features, one with two Uniprot cross-refs,
+     * the other with one
      */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(false);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("30");
-    locElement.setBasePositions(new BasePosition[] { b1, b1, b1 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-
-    /*
-     * single valid range [50-60] to finish
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(false);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("50");
-    b2 = new BasePosition();
-    b2.setPos("60");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-
-    int[] exons = testee.getCdsRanges(cds);
-    assertEquals("[10, 20, 50, 60]", Arrays.toString(exons));
-  }
-
-  /**
-   * Test retrieval of exon locations matching an accession id
-   */
-  @Test(groups = "Functional")
-  public void testGetCdsRanges_forAccession()
-  {
     EmblEntry testee = new EmblEntry();
-    String accession = "A1234";
-    testee.setAccession(accession);
-    /*
-     * Make a (CDS) Feature with 4 locations
-     */
-    EmblFeature cds = new EmblFeature();
-    Vector<EmblFeatureLocations> locs = new Vector<EmblFeatureLocations>();
-    cds.setLocations(locs);
-  
-    /*
-     * single range [10-20] for 'this' accession
-     */
-    EmblFeatureLocations loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(false);
-    Vector<EmblFeatureLocElement> elements = new Vector<EmblFeatureLocElement>();
-    EmblFeatureLocElement locElement = new EmblFeatureLocElement();
-    locElement.setAccession(accession);
-    BasePosition b1 = new BasePosition();
-    b1.setPos("10");
-    BasePosition b2 = new BasePosition();
-    b2.setPos("20");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-  
-    /*
-     * complement range [30-40] - no accession
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(true);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("30");
-    b2 = new BasePosition();
-    b2.setPos("40");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-  
-    /*
-     * join range [50-60] this accession, [70-80] another
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("join");
-    loc.setLocationComplement(false);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    locElement.setAccession(accession);
-    b1 = new BasePosition();
-    b1.setPos("50");
-    b2 = new BasePosition();
-    b2.setPos("60");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    locElement = new EmblFeatureLocElement();
-    locElement.setAccession("notme");
-    b1 = new BasePosition();
-    b1.setPos("70");
-    b2 = new BasePosition();
-    b2.setPos("80");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-  
-    /*
-     * complement range [90-100] wrong accession, [110-120] good 
-     * this should be the same as complement(join(90..100,110.120))
-     * which is "join 90-100 and 110-120, then complement"
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("join");
-    loc.setLocationComplement(true);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    locElement.setAccession("wrong");
-    b1 = new BasePosition();
-    b1.setPos("90");
-    b2 = new BasePosition();
-    b2.setPos("100");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    locElement = new EmblFeatureLocElement();
-    locElement.setAccession(accession);
-    b1 = new BasePosition();
-    b1.setPos("110");
-    b2 = new BasePosition();
-    b2.setPos("120");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-  
-    /*
-     * verify we pick out only ranges for A1234
-     */
-    int[] exons = testee.getCdsRanges(cds);
-    assertEquals("[10, 20, 50, 60, 120, 110]",
-            Arrays.toString(exons));
+    for (EmblFeature feature : ef.getEntries().get(0).getFeatures())
+    {
+      if ("CDS".equals(feature.getName()))
+      {
+        testee.parseCodingFeature(feature, "EMBL", dna, peptides, matcher);
+      }
+    }
+
+    /*
+     * peptides should now have five entries:
+     * EMBL product and two Uniprot accessions for the first CDS / translation
+     * EMBL product and one Uniprot accession for the second CDS / translation
+     */
+    assertEquals(5, peptides.size());
+    assertEquals("CAA30420.1", peptides.get(0).getName());
+    assertEquals("MLCF", peptides.get(0).getSequenceAsString());
+    assertEquals("UNIPROT|B0BCM4", peptides.get(1).getName());
+    assertEquals("MLCF", peptides.get(1).getSequenceAsString());
+    assertEquals("UNIPROT|P0CE20", peptides.get(2).getName());
+    assertEquals("MLCF", peptides.get(2).getSequenceAsString());
+    assertEquals("CAA30421.1", peptides.get(3).getName());
+    assertEquals("MSSS", peptides.get(3).getSequenceAsString());
+    assertEquals("UNIPROT|B0BCM3", peptides.get(4).getName());
+    assertEquals("MSSS", peptides.get(4).getSequenceAsString());
+
+    /*
+     * verify dna sequence has dbrefs with mappings to the peptide 'products'
+     */
+    DBRefEntry[] dbrefs = dna.getDBRefs();
+    assertEquals(3, dbrefs.length);
+    DBRefEntry dbRefEntry = dbrefs[0];
+    assertEquals("UNIPROT", dbRefEntry.getSource());
+    assertEquals("B0BCM4", dbRefEntry.getAccessionId());
+    assertSame(peptides.get(1), dbRefEntry.getMap().getTo());
+    List<int[]> fromRanges = dbRefEntry.getMap().getMap().getFromRanges();
+    assertEquals(1, fromRanges.size());
+    assertEquals(57, fromRanges.get(0)[0]);
+    assertEquals(46, fromRanges.get(0)[1]);
+    List<int[]> toRanges = dbRefEntry.getMap().getMap().getToRanges();
+    assertEquals(1, toRanges.size());
+    assertEquals(1, toRanges.get(0)[0]);
+    assertEquals(4, toRanges.get(0)[1]);
+
+    dbRefEntry = dbrefs[1];
+    assertEquals("UNIPROT", dbRefEntry.getSource());
+    assertEquals("P0CE20", dbRefEntry.getAccessionId());
+    assertSame(peptides.get(2), dbRefEntry.getMap().getTo());
+    fromRanges = dbRefEntry.getMap().getMap().getFromRanges();
+    assertEquals(1, fromRanges.size());
+    assertEquals(57, fromRanges.get(0)[0]);
+    assertEquals(46, fromRanges.get(0)[1]);
+    toRanges = dbRefEntry.getMap().getMap().getToRanges();
+    assertEquals(1, toRanges.size());
+    assertEquals(1, toRanges.get(0)[0]);
+    assertEquals(4, toRanges.get(0)[1]);
+
+    dbRefEntry = dbrefs[2];
+    assertEquals("UNIPROT", dbRefEntry.getSource());
+    assertEquals("B0BCM3", dbRefEntry.getAccessionId());
+    assertSame(peptides.get(4), dbRefEntry.getMap().getTo());
+    fromRanges = dbRefEntry.getMap().getMap().getFromRanges();
+    assertEquals(1, fromRanges.size());
+    assertEquals(4, fromRanges.get(0)[0]);
+    assertEquals(15, fromRanges.get(0)[1]);
+    toRanges = dbRefEntry.getMap().getMap().getToRanges();
+    assertEquals(1, toRanges.size());
+    assertEquals(1, toRanges.get(0)[0]);
+    assertEquals(4, toRanges.get(0)[1]);
   }
 }
index c6a94d7..6955833 100644 (file)
 package jalview.datamodel.xdb.embl;
 
 import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertNull;
-import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.datamodel.DBRefEntry;
 
-import java.io.StringReader;
 import java.util.Vector;
 
 import org.testng.annotations.Test;
 
 public class EmblFileTest
 {
-  // adapted from http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/embl/x53828/emblxml
-  private static final String TESTDATA = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
-          + "<EMBL_Services>"
-          + "<entry accession=\"X53828\" version=\"3\" lastUpdated=\"2005-04-18\" releaseCreated=\"25\" releaseLastUpdated=\"83\">"
-          + "<description>Chicken LDH-A mRNA for lactate dehydrogenase A chain (EC 1.1.1.27)</description>"
-          + "<keyword>L-lactate dehydrogenase</keyword><keyword>chutney</keyword>"
-          + "<dbreference db=\"EuropePMC\" primary=\"PMC1460223\" secondary=\"9649548\" />"
-          + "<dbreference db=\"MD5\" primary=\"d3b68\" />"
-          + "<feature name=\"CDS\"><dbreference db=\"GOA\" primary=\"P00340\" secondary=\"2.1\" /><dbreference db=\"InterPro\" primary=\"IPR001236\" />"
-          + "<qualifier name=\"note\"><value>L-lactate dehydrogenase A-chain</value><value>pickle</value></qualifier>"
-          + "<qualifier name=\"translation\"><value>MSLKDHLIHN</value><evidence>Keith</evidence></qualifier>"
-          + "<location type=\"single\" complement=\"true\">"
-          + "<locationElement type=\"range\" accession=\"X53828\" version=\"1\" complement=\"false\">"
-          + "<basePosition type=\"simple\">60</basePosition><basePosition type=\"join\">1058</basePosition>"
-          + "</locationElement></location></feature>"
-          + "<sequence type=\"mRNA\" version=\"2\">GTGACG</sequence></entry></EMBL_Services>";
 
   @Test(groups = { "Functional" })
   public void testGetEmblFile()
   {
-    Vector<EmblEntry> entries = EmblFile.getEmblFile(
-            new StringReader(TESTDATA)).getEntries();
+    Vector<EmblEntry> entries = EmblTestHelper.getEmblFile().getEntries();
     assertEquals(1, entries.size());
     EmblEntry entry = entries.get(0);
 
-    assertEquals("X53828", entry.getAccession());
-    assertEquals(
-            "Chicken LDH-A mRNA for lactate dehydrogenase A chain (EC 1.1.1.27)",
-            entry.getDesc());
-    assertEquals("2005-04-18", entry.getLastUpdated());
+    assertEquals("X07547", entry.getAccession());
+    assertEquals("C. trachomatis plasmid", entry.getDescription());
+    assertEquals("STD", entry.getDataClass());
+    assertEquals("PRO", entry.getTaxonomicDivision());
+    assertEquals("1999-02-10", entry.getLastUpdatedDate());
+    assertEquals("58", entry.getLastUpdatedRelease());
+    assertEquals("1988-11-10", entry.getFirstPublicDate());
+    assertEquals("18", entry.getFirstPublicRelease());
+    assertEquals("genomic DNA", entry.getMoleculeType());
+    assertEquals("1", entry.getSequenceVersion());
+    assertEquals("8", entry.getEntryVersion());
+    assertEquals("linear", entry.getTopology());
+    assertEquals("7499", entry.getSequenceLength());
 
     /*
      * FIXME these assertions fail - values are null - why?? Adding or removing
      * attributes in the test XML modifies behaviour. eg. inserting an attribute
      * _before_ lastUpdated results in a null value in this field.
      */
-    // assertEquals("25", entry.getRCreated());
-    // assertEquals("83", entry.getRLastUpdated());
+    assertEquals("1988-11-10", entry.getFirstPublicDate());
+    assertEquals("18", entry.getFirstPublicRelease());
 
     assertEquals(2, entry.getKeywords().size());
-    assertEquals("L-lactate dehydrogenase", entry.getKeywords().get(0));
-    assertEquals("chutney", entry.getKeywords().get(1));
+    assertEquals("plasmid", entry.getKeywords().get(0));
+    assertEquals("unidentified reading frame", entry.getKeywords().get(1));
 
     /*
      * dbrefs
@@ -83,72 +71,81 @@ public class EmblFileTest
     assertEquals(2, entry.getDbRefs().size());
     DBRefEntry dbref = entry.getDbRefs().get(0);
     assertEquals("EuropePMC", dbref.getSource());
-    assertEquals("PMC1460223", dbref.getAccessionId());
-    assertEquals("9649548", dbref.getVersion());
+    assertEquals("PMC107176", dbref.getAccessionId());
+    assertEquals("9573186", dbref.getVersion());
     dbref = entry.getDbRefs().get(1);
     assertEquals("MD5", dbref.getSource());
-    assertEquals("d3b68", dbref.getAccessionId());
+    assertEquals("ac73317", dbref.getAccessionId());
     // blank version has been converted to "0"
     assertEquals("0", dbref.getVersion());
 
     /*
-     * sequence features
+     * two sequence features for CDS
+     */
+    assertEquals(2, entry.getFeatures().size());
+    /*
+     * first CDS
      */
-    assertEquals(1, entry.getFeatures().size());
     EmblFeature ef = entry.getFeatures().get(0);
     assertEquals("CDS", ef.getName());
+    assertEquals("complement(46..57)", ef.getLocation());
     assertEquals(2, ef.getDbRefs().size());
     dbref = ef.getDbRefs().get(0);
-    assertEquals("GOA", dbref.getSource());
-    assertEquals("P00340", dbref.getAccessionId());
+    assertEquals("UniProtKB/Swiss-Prot", dbref.getSource());
+    assertEquals("B0BCM4", dbref.getAccessionId());
     assertEquals("2.1", dbref.getVersion());
     dbref = ef.getDbRefs().get(1);
-    assertEquals("InterPro", dbref.getSource());
-    assertEquals("IPR001236", dbref.getAccessionId());
-    // blank version converted to "0":
+    assertEquals("UniProtKB/Swiss-Prot", dbref.getSource());
+    assertEquals("P0CE20", dbref.getAccessionId());
+    // blank version gets converted to "0":
     assertEquals("0", dbref.getVersion());
-    assertEquals(2, ef.getQualifiers().size());
-
-    // feature qualifiers
+    // CDS feature qualifiers
+    assertEquals(3, ef.getQualifiers().size());
     Qualifier q = ef.getQualifiers().get(0);
     assertEquals("note", q.getName());
     assertEquals(2, q.getValues().length);
-    assertEquals("L-lactate dehydrogenase A-chain", q.getValues()[0]);
+    assertEquals("ORF 8 (AA 1-330)", q.getValues()[0]);
     assertEquals("pickle", q.getValues()[1]);
     assertNull(q.getEvidence());
     q = ef.getQualifiers().get(1);
+    assertEquals("protein_id", q.getName());
+    assertEquals(1, q.getValues().length);
+    assertEquals("CAA30420.1", q.getValues()[0]);
+    q = ef.getQualifiers().get(2);
     assertEquals("translation", q.getName());
     assertEquals(1, q.getValues().length);
-    assertEquals("MSLKDHLIHN", q.getValues()[0]);
+    assertEquals("MLCF", q.getValues()[0]);
     assertEquals(1, q.getEvidence().length);
     assertEquals("Keith", q.getEvidence()[0]);
 
-    // feature locations
-    assertEquals(1, ef.getLocations().size());
-    EmblFeatureLocations fl = ef.getLocations().get(0);
-    assertEquals("single", fl.getLocationType());
-    assertTrue(fl.isLocationComplement());
-    assertEquals(1, fl.getLocElements().size());
-    EmblFeatureLocElement le = fl.getLocElements().get(0);
-    assertEquals("range", le.getType());
-    assertEquals("X53828", le.getAccession());
-    assertEquals("1", le.getVersion());
-    assertFalse(le.isComplement());
-    assertEquals(2, le.getBasePositions().length);
-    BasePosition bp = le.getBasePositions()[0];
-    assertEquals("simple", bp.getType());
-    assertEquals("60", bp.getPos());
-    bp = le.getBasePositions()[1];
-    assertEquals("join", bp.getType());
-    assertEquals("1058", bp.getPos());
+    /*
+     * second CDS
+     */
+    ef = entry.getFeatures().get(1);
+    assertEquals("CDS", ef.getName());
+    assertEquals("4..15", ef.getLocation());
+    assertEquals(1, ef.getDbRefs().size());
+    dbref = ef.getDbRefs().get(0);
+    assertEquals("UniProtKB/Swiss-Prot", dbref.getSource());
+    assertEquals("B0BCM3", dbref.getAccessionId());
+    assertEquals("0", dbref.getVersion());
+    assertEquals(2, ef.getQualifiers().size());
+    q = ef.getQualifiers().get(0);
+    assertEquals("protein_id", q.getName());
+    assertEquals(1, q.getValues().length);
+    assertEquals("CAA30421.1", q.getValues()[0]);
+    q = ef.getQualifiers().get(1);
+    assertEquals("translation", q.getName());
+    assertEquals(1, q.getValues().length);
+    assertEquals("MSSS", q.getValues()[0]);
 
     /*
-     * Sequence
+     * Sequence - verify newline not converted to space (JAL-2029)
      */
     EmblSequence seq = entry.getSequence();
-    assertEquals("mRNA", seq.getType());
-    assertEquals("2", seq.getVersion());
-    assertEquals("GTGACG", seq.getSequence());
+    assertEquals(
+            "GGTATGTCCTCTAGTACAAACACCCCCAATATTGTGATATAATTAAAAACATAGCAT",
+            seq.getSequence());
 
     /*
      * getSequence() converts empty DBRefEntry.version to "0"
diff --git a/test/jalview/datamodel/xdb/embl/EmblTestHelper.java b/test/jalview/datamodel/xdb/embl/EmblTestHelper.java
new file mode 100644 (file)
index 0000000..9957c72
--- /dev/null
@@ -0,0 +1,53 @@
+package jalview.datamodel.xdb.embl;
+
+import java.io.StringReader;
+
+public class EmblTestHelper
+{
+  // adapted from http://www.ebi.ac.uk/ena/data/view/X07547&display=xml
+  // dna and translations truncated for convenience
+  private static final String TESTDATA = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
+          + "<ROOT>"
+          + "<entry accession=\"X07547\" version=\"1\" entryVersion=\"8\""
+          + " dataClass=\"STD\" taxonomicDivision=\"PRO\""
+          + " moleculeType=\"genomic DNA\" sequenceLength=\"7499\" topology=\"linear\""
+          + " firstPublic=\"1988-11-10\" firstPublicRelease=\"18\""
+          + " lastUpdated=\"1999-02-10\" lastUpdatedRelease=\"58\">"
+          + "<secondaryAccession>X07574</secondaryAccession>"
+          + "<description>C. trachomatis plasmid</description>"
+          + "<keyword>plasmid</keyword><keyword>unidentified reading frame</keyword>"
+          + "<xref db=\"EuropePMC\" id=\"PMC107176\" secondaryId=\"9573186\" />"
+          + "<xref db=\"MD5\" id=\"ac73317\" />"
+          /*
+           * first CDS (range and translation changed to keep test data manageable)
+           */
+          + "<feature name=\"CDS\" location=\"complement(46..57)\">"
+          // test the case of >1 cross-ref to the same database (JAL-2029)
+          + "<xref db=\"UniProtKB/Swiss-Prot\" id=\"B0BCM4\" secondaryId=\"2.1\" />"
+          + "<xref db=\"UniProtKB/Swiss-Prot\" id=\"P0CE20\" />"
+          + "<qualifier name=\"note\"><value>ORF 8 (AA 1-330)</value><value>pickle</value></qualifier>"
+          + "<qualifier name=\"protein_id\"><value>CAA30420.1</value></qualifier>"
+          + "<qualifier name=\"translation\"><value>MLCF</value><evidence>Keith</evidence></qualifier>"
+          + "</feature>"
+          /*
+           * second CDS (range and translation changed to keep test data manageable)
+           */
+          + "<feature name=\"CDS\" location=\"4..15\">"
+          + "<xref db=\"UniProtKB/Swiss-Prot\" id=\"B0BCM3\" />"
+          + "<qualifier name=\"protein_id\"><value>CAA30421.1</value></qualifier>"
+          + "<qualifier name=\"translation\"><value>MSSS</value></qualifier>"
+          + "</feature>"
+          /*
+           * sequence (modified for test purposes)
+           * emulates EMBL XML 1.2 which splits sequence data every 60 characters
+           * see EmblSequence.setSequence
+           */
+          + "<sequence>GGTATGTCCTCTAGTACAAAC\n"
+          + "ACCCCCAATATTGTGATATAATTAAAAACATAGCAT"
+          + "</sequence></entry></ROOT>";
+
+  static EmblFile getEmblFile()
+  {
+    return EmblFile.getEmblFile(new StringReader(TESTDATA));
+  }
+}
index 6f7c1ad..56e1339 100644 (file)
@@ -12,7 +12,7 @@ public class EnsemblRestClientTest
 {
 
   @Test(suiteName = "live")
-  public void testLiveCheckEnsembl()
+  public void testIsEnsemblAvailable()
   {
     EnsemblRestClient sf = new EnsemblRestClient()
     {
index 71f0212..6ce8a3b 100644 (file)
@@ -160,61 +160,6 @@ public class EnsemblSeqProxyTest
     }
   }
 
-  @Test(suiteName = "live")
-  public void testLiveCheckEnsembl()
-  {
-    EnsemblRestClient sf = new EnsemblRestClient()
-    {
-
-      @Override
-      public String getDbName()
-      {
-        // TODO Auto-generated method stub
-        return null;
-      }
-
-      @Override
-      public AlignmentI getSequenceRecords(String queries) throws Exception
-      {
-        // TODO Auto-generated method stub
-        return null;
-      }
-
-      @Override
-      protected URL getUrl(List<String> ids) throws MalformedURLException
-      {
-        // TODO Auto-generated method stub
-        return null;
-      }
-
-      @Override
-      protected boolean useGetRequest()
-      {
-        // TODO Auto-generated method stub
-        return false;
-      }
-
-      @Override
-      protected String getRequestMimeType(boolean b)
-      {
-        // TODO Auto-generated method stub
-        return null;
-      }
-
-      @Override
-      protected String getResponseMimeType()
-      {
-        // TODO Auto-generated method stub
-        return null;
-      }
-
-    };
-    boolean isAvailable = sf.isEnsemblAvailable();
-    System.out.println("Ensembl is "
-            + (isAvailable ? "UP!"
-                    : "DOWN or unreachable ******************* BAD!"));
-  }
-
   @Test(groups = "Functional")
   public void getGenomicRangesFromFeatures()
   {
index cde4afe..1dc9b8d 100644 (file)
@@ -21,7 +21,7 @@ public class EnsemblXrefTest
            "{\"primary_id\":\"GO:0000165\",\"dbname\":\"GO\"}]";
   //@formatter:on
 
-  @Test(groups = "functional")
+  @Test(groups = "Functional")
   public void testGetCrossReferences()
   {
     System.out.println(JSON);
index 679385a..4110863 100644 (file)
@@ -43,7 +43,7 @@ import compbio.util.FileUtil;
 public class TestAnnotate3D
 {
 
-  @Test(groups = { "Functional" }, enabled = false)
+  @Test(groups = { "Network" }, enabled = true)
   public void test1GIDbyId() throws Exception
   {
     // use same ID as standard tests given at
@@ -53,7 +53,7 @@ public class TestAnnotate3D
     testRNAMLcontent(ids, null);
   }
 
-  @Test(groups = { "Functional" }, enabled = false)
+  @Test(groups = { "Network" }, enabled = true)
   public void testIdVsContent2GIS() throws Exception
   {
     Iterator<Reader> ids = Annotate3D.getRNAMLForPDBId("2GIS");
@@ -97,7 +97,7 @@ public class TestAnnotate3D
    * 
    * @throws Exception
    */
-  @Test(groups = { "Functional" }, enabled = false)
+  @Test(groups = { "Network" }, enabled = true)
   public void testPDBfileVsRNAML() throws Exception
   {
     PDBfile pdbf = new PDBfile(true, false, true, "examples/2GIS.pdb",
@@ -111,7 +111,6 @@ public class TestAnnotate3D
     testRNAMLcontent(readers, pdbf);
   }
 
-  @Test(groups = { "Functional" }, enabled = false)
   private void testRNAMLcontent(Iterator<Reader> readers, PDBfile pdbf)
           throws Exception
   {
index 4a90c4e..eae5575 100644 (file)
@@ -24,7 +24,7 @@ public class FTSRestClientTest
       @Override
       public String getColumnDataConfigFileName()
       {
-        return "examples/testdata/test_fts_data_columns.conf";
+        return "/fts/uniprot_data_columns.txt";
       }
 
       @Override
@@ -40,7 +40,7 @@ public class FTSRestClientTest
   public void getPrimaryKeyColumIndexTest()
   {
     Collection<FTSDataColumnI> wantedFields = ftsRestClient
-            .getAllDefaulDisplayedDataColumns();
+            .getAllDefaultDisplayedFTSDataColumns();
     int foundIndex = -1;
     try
     {
@@ -61,34 +61,24 @@ public class FTSRestClientTest
   @Test(groups = { "Functional" })
   public void getAllDefaulDisplayedDataColumns()
   {
-    Assert.assertNotNull(ftsRestClient.getAllDefaulDisplayedDataColumns());
-    Assert.assertTrue(!ftsRestClient.getAllDefaulDisplayedDataColumns()
+    Assert.assertNotNull(ftsRestClient.getAllDefaultDisplayedFTSDataColumns());
+    Assert.assertTrue(!ftsRestClient.getAllDefaultDisplayedFTSDataColumns()
             .isEmpty());
-    Assert.assertEquals(ftsRestClient.getAllDefaulDisplayedDataColumns()
-            .size(), 6);
+    Assert.assertEquals(ftsRestClient.getAllDefaultDisplayedFTSDataColumns()
+            .size(), 7);
   }
 
   @Test(groups = { "Functional" })
   public void getDataColumnsFieldsAsCommaDelimitedString()
   {
     Collection<FTSDataColumnI> wantedFields = ftsRestClient
-            .getAllDefaulDisplayedDataColumns();
+            .getAllDefaultDisplayedFTSDataColumns();
     String actual = ftsRestClient
             .getDataColumnsFieldsAsCommaDelimitedString(wantedFields);
     Assert.assertEquals(actual,
-            "entry name,protein names,genes,organism,created,last-modified");
+            "id,entry name,protein names,genes,organism,reviewed,length");
   }
 
-  @Test(groups = { "Functional" })
-  public void getDataColumnsFieldsAsTabDelimitedString()
-  {
-    Collection<FTSDataColumnI> wantedFields = ftsRestClient
-            .getAllDefaulDisplayedDataColumns();
-    String actual = ftsRestClient
-            .getDataColumnsFieldsAsTabDelimitedString(wantedFields);
-    Assert.assertEquals(actual,
-            "Entry Name\tProtein names\tGene Names\tOrganism\tDate of creation\tDate of last modification");
-  }
 
   @Test(groups = { "Functional" })
   public void getAllFTSDataColumns()
@@ -96,7 +86,7 @@ public class FTSRestClientTest
     Collection<FTSDataColumnI> allFields = ftsRestClient
             .getAllFTSDataColumns();
     Assert.assertNotNull(allFields);
-    Assert.assertEquals(allFields.size(), 116);
+    Assert.assertEquals(allFields.size(), 117);
   }
 
   @Test(groups = { "Functional" })
@@ -105,7 +95,7 @@ public class FTSRestClientTest
     Collection<FTSDataColumnI> searchalbeFields = ftsRestClient
             .getSearchableDataColumns();
     Assert.assertNotNull(searchalbeFields);
-    Assert.assertEquals(searchalbeFields.size(), 28);
+    Assert.assertEquals(searchalbeFields.size(), 22);
   }
 
   @Test(groups = { "Functional" })
@@ -115,7 +105,7 @@ public class FTSRestClientTest
     try
     {
       expectedPKColumn = ftsRestClient
-              .getDataColumnByNameOrCode("Entry Name");
+              .getDataColumnByNameOrCode("Uniprot Id");
       Assert.assertNotNull(ftsRestClient.getPrimaryKeyColumn());
       Assert.assertEquals(ftsRestClient.getPrimaryKeyColumn(),
               expectedPKColumn);
@@ -161,7 +151,7 @@ public class FTSRestClientTest
   public void getDefaultResponsePageSize()
   {
     int defaultResSize = ftsRestClient.getDefaultResponsePageSize();
-    Assert.assertEquals(defaultResSize, 100);
+    Assert.assertEquals(defaultResSize, 500);
   }
 
   @Test(groups = { "Functional" })
@@ -223,10 +213,12 @@ public class FTSRestClientTest
       FTSDataColumnI foundDataCol = ftsRestClient
               .getDataColumnByNameOrCode("Protein names");
       Assert.assertNotNull(foundDataCol);
-      Assert.assertEquals(foundDataCol.getDataColumnClass(), String.class);
+      Assert.assertEquals(foundDataCol.getDataType().getDataTypeClass(),
+              String.class);
       foundDataCol = ftsRestClient.getDataColumnByNameOrCode("length");
       Assert.assertNotNull(foundDataCol);
-      Assert.assertEquals(foundDataCol.getDataColumnClass(), Integer.class);
+      Assert.assertEquals(foundDataCol.getDataType().getDataTypeClass(),
+              Integer.class);
       // foundDataCol = ftsRestClient.getDataColumnByNameOrCode("length");
       // Assert.assertNotNull(foundDataCol);
       // Assert.assertEquals(foundDataCol.getDataColumnClass(), Double.class);
@@ -245,18 +237,19 @@ public class FTSRestClientTest
             .getSearchableDataColumns();
     for (FTSDataColumnI foundCol : searchableCols)
     {
+      System.out.println(foundCol.toString());
       uniqueSet.add(foundCol);
       uniqueSet.add(foundCol);
     }
     Assert.assertTrue(!uniqueSet.isEmpty());
-    Assert.assertEquals(uniqueSet.size(), 28);
+    Assert.assertEquals(uniqueSet.size(), 22);
   }
 
   @Test(groups = { "Functional" })
   public void coverageForMiscellaneousBranches()
   {
     String actual = ftsRestClient.getPrimaryKeyColumn().toString();
-    Assert.assertEquals(actual, "Entry Name");
+    Assert.assertEquals(actual, "Uniprot Id");
 
     String actualGroupStr;
     try
@@ -272,7 +265,7 @@ public class FTSRestClientTest
     }
 
     String actualResourseFile = ftsRestClient
-            .getResourceFile("fts/uniprot_data_columns.conf");
+            .getResourceFile("/fts/uniprot_data_columns.txt");
     Assert.assertNotNull(actualResourseFile);
     Assert.assertTrue(actualResourseFile.length() > 31);
   }
index 6837847..ac1d304 100644 (file)
@@ -90,7 +90,7 @@ public class PDBFTSPanelTest
     assertEquals(expectedString, outcome);
   }
 
-  @Test(groups = { "Network", "External" }, timeOut = 7000)
+  @Test(groups = { "External" }, timeOut = 7000)
   public void txt_search_ActionPerformedTest()
   {
     PDBFTSPanel searchPanel = new PDBFTSPanel(null);
index d6203c6..ebc0405 100644 (file)
@@ -191,7 +191,7 @@ public class PDBFTSRestClientTest
   }
 
   @Test(
-    groups = { "External", "Network" },
+    groups = { "External" },
     expectedExceptions = Exception.class)
   public void testForExpectedRuntimeException() throws Exception
   {
@@ -206,6 +206,7 @@ public class PDBFTSRestClientTest
     PDBFTSRestClient.getInstance().executeRequest(request);
   }
 
+    // JBP: Is this actually external ?  Looks like it is mocked
   @Test(groups = { "External" })
   public void parsePDBJsonResponseTest()
   {
diff --git a/test/jalview/gui/AlignFrameTest.java b/test/jalview/gui/AlignFrameTest.java
new file mode 100644 (file)
index 0000000..80e3d5a
--- /dev/null
@@ -0,0 +1,71 @@
+package jalview.gui;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+public class AlignFrameTest
+{
+
+  @Test
+  public void testHideFeatureColumns()
+  {
+    SequenceI seq1 = new Sequence("Seq1", "ABCDEFGHIJ");
+    SequenceI seq2 = new Sequence("Seq2", "ABCDEFGHIJ");
+    seq1.addSequenceFeature(new SequenceFeature("Metal", "", 1, 5,
+            Float.NaN, null));
+    seq2.addSequenceFeature(new SequenceFeature("Metal", "", 6, 10,
+            Float.NaN, null));
+    seq1.addSequenceFeature(new SequenceFeature("Turn", "", 2, 4,
+            Float.NaN, null));
+    seq2.addSequenceFeature(new SequenceFeature("Turn", "", 7, 9,
+            Float.NaN, null));
+    AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
+    AlignFrame af = new AlignFrame(al, al.getWidth(), al.getHeight());
+
+    /*
+     * hiding a feature not present does nothing
+     */
+    assertFalse(af.hideFeatureColumns("exon", true));
+    assertTrue(af.getViewport().getColumnSelection().isEmpty());
+    assertTrue(af.getViewport().getColumnSelection().getHiddenColumns()
+            .isEmpty());
+    assertFalse(af.hideFeatureColumns("exon", false));
+    assertTrue(af.getViewport().getColumnSelection().isEmpty());
+    assertTrue(af.getViewport().getColumnSelection().getHiddenColumns()
+            .isEmpty());
+
+    /*
+     * hiding a feature in all columns does nothing
+     */
+    assertFalse(af.hideFeatureColumns("Metal", true));
+    assertTrue(af.getViewport().getColumnSelection().isEmpty());
+    List<int[]> hidden = af.getViewport().getColumnSelection()
+            .getHiddenColumns();
+    assertTrue(hidden.isEmpty());
+
+    /*
+     * hide a feature present in some columns
+     * sequence positions [2-4], [7-9] are column positions
+     * [1-3], [6-8] base zero
+     */
+    assertTrue(af.hideFeatureColumns("Turn", true));
+    hidden = af.getViewport().getColumnSelection()
+            .getHiddenColumns();
+    assertEquals(2, hidden.size());
+    assertEquals(1, hidden.get(0)[0]);
+    assertEquals(3, hidden.get(0)[1]);
+    assertEquals(6, hidden.get(1)[0]);
+    assertEquals(8, hidden.get(1)[1]);
+  }
+}
index c2209d6..ae6bf38 100644 (file)
@@ -116,4 +116,22 @@ public class StructureChooserTest
     assertTrue(sc.getDiscoveredStructuresSet().size() > 0);
 
   }
+
+  @Test(groups = { "Functional" })
+  public void sanitizeSeqNameTest()
+  {
+    String name = "ab_cdEF|fwxyz012349";
+    assertEquals(name, StructureChooser.sanitizeSeqName(name));
+
+    // remove a [nn] substring
+    name = "abcde12[345]fg";
+    assertEquals("abcde12fg", StructureChooser.sanitizeSeqName(name));
+
+    // remove characters other than a-zA-Z0-9 | or _
+    name = "ab[cd],.\t£$*!- \\\"@:e";
+    assertEquals("abcde", StructureChooser.sanitizeSeqName(name));
+
+    name = "abcde12[345a]fg";
+    assertEquals("abcde12345afg", StructureChooser.sanitizeSeqName(name));
+  }
 }
index 385e049..29bd567 100644 (file)
@@ -26,6 +26,7 @@ import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.api.FeatureRenderer;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceDummy;
@@ -75,53 +76,63 @@ public class FeaturesFileTest
      */
     SequenceFeature[] sfs = al.getSequenceAt(0).getDatasetSequence()
             .getSequenceFeatures(); // FER_CAPAA
-    assertEquals(7, sfs.length);
+    assertEquals(8, sfs.length);
     SequenceFeature sf = sfs[0];
+    assertEquals("Pfam family%LINK%", sf.description);
+    assertEquals(0, sf.begin);
+    assertEquals(0, sf.end);
+    assertEquals("uniprot", sf.featureGroup);
+    assertEquals("Pfam", sf.type);
+    assertEquals(1, sf.links.size());
+    assertEquals("Pfam family|http://pfam.xfam.org/family/PF00111",
+            sf.links.get(0));
+
+    sf = sfs[1];
     assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
     assertEquals(39, sf.begin);
     assertEquals(39, sf.end);
     assertEquals("uniprot", sf.featureGroup);
     assertEquals("METAL", sf.type);
-    sf = sfs[1];
+    sf = sfs[2];
     assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
     assertEquals(44, sf.begin);
     assertEquals(44, sf.end);
     assertEquals("uniprot", sf.featureGroup);
     assertEquals("METAL", sf.type);
-    sf = sfs[2];
+    sf = sfs[3];
     assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
     assertEquals(47, sf.begin);
     assertEquals(47, sf.end);
     assertEquals("uniprot", sf.featureGroup);
     assertEquals("METAL", sf.type);
-    sf = sfs[3];
+    sf = sfs[4];
     assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
     assertEquals(77, sf.begin);
     assertEquals(77, sf.end);
     assertEquals("uniprot", sf.featureGroup);
     assertEquals("METAL", sf.type);
-    sf = sfs[4];
+    sf = sfs[5];
     assertEquals("Fer2 Status: True Positive Pfam 8_8%LINK%",
             sf.description);
-    assertEquals("Pfam 8_8|http://pfam.sanger.ac.uk/family/PF00111",
-            sf.links.get(0).toString());
+    assertEquals("Pfam 8_8|http://pfam.xfam.org/family/PF00111",
+            sf.links.get(0));
     assertEquals(8, sf.begin);
     assertEquals(83, sf.end);
     assertEquals("uniprot", sf.featureGroup);
     assertEquals("Pfam", sf.type);
-    sf = sfs[5];
+    sf = sfs[6];
     assertEquals("Ferredoxin_fold Status: True Positive ", sf.description);
     assertEquals(3, sf.begin);
     assertEquals(93, sf.end);
     assertEquals("uniprot", sf.featureGroup);
     assertEquals("Cath", sf.type);
-    sf = sfs[6];
+    sf = sfs[7];
     assertEquals(
             "High confidence server. Only hits with scores over 0.8 are reported. PHOSPHORYLATION (T) 89_8%LINK%",
             sf.description);
     assertEquals(
             "PHOSPHORYLATION (T) 89_8|http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=P83527&amp;service=NetPhos-2.0",
-            sf.links.get(0).toString());
+            sf.links.get(0));
     assertEquals(89, sf.begin);
     assertEquals(89, sf.end);
     assertEquals("netphos", sf.featureGroup);
@@ -412,4 +423,73 @@ public class FeaturesFileTest
             parseResult);
     checkDatasetfromSimpleGff3(dataset);
   }
+
+  @Test(groups = { "Functional" })
+  public void testPrintJalviewFormat() throws Exception
+  {
+    File f = new File("examples/uniref50.fa");
+    AlignmentI al = readAlignmentFile(f);
+    AlignFrame af = new AlignFrame(al, 500, 500);
+    Map<String, Object> colours = af.getFeatureRenderer()
+            .getFeatureColours();
+    String features = "METAL\tcc9900\n"
+            + "GAMMA-TURN\tred|0,255,255|20.0|95.0|below|66.0\n"
+            + "Pfam\tred\n"
+            + "STARTGROUP\tuniprot\n"
+            + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\n"
+            + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\n"
+            + "<html>Pfam domain<a href=\"http://pfam.xfam.org/family/PF00111\">Pfam_3_4</a></html>\tFER_CAPAA\t-1\t20\t20\tPfam\n"
+            + "ENDGROUP\tuniprot\n";
+    FeaturesFile featuresFile = new FeaturesFile(features,
+            FormatAdapter.PASTE);
+    featuresFile.parse(al.getDataset(), colours, false);
+
+    /*
+     * first with no features displayed
+     */
+    FeatureRenderer fr = af.alignPanel.getFeatureRenderer();
+    Map<String, Object> visible = fr
+            .getDisplayedFeatureCols();
+    String exported = featuresFile.printJalviewFormat(
+            al.getSequencesArray(), visible);
+    String expected = "No Features Visible";
+    assertEquals(expected, exported);
+
+    /*
+     * set METAL (in uniprot group) and GAMMA-TURN visible, but not Pfam
+     */
+    fr.setVisible("METAL");
+    fr.setVisible("GAMMA-TURN");
+    visible = fr.getDisplayedFeatureCols();
+    exported = featuresFile.printJalviewFormat(al.getSequencesArray(),
+            visible);
+    expected = "METAL\tcc9900\n"
+            + "GAMMA-TURN\tff0000|00ffff|20.0|95.0|below|66.0\n"
+            + "\nSTARTGROUP\tuniprot\n"
+            + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n"
+            + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n"
+            + "ENDGROUP\tuniprot\n";
+    assertEquals(expected, exported);
+
+    /*
+     * now set Pfam visible
+     */
+    fr.setVisible("Pfam");
+    visible = fr.getDisplayedFeatureCols();
+    exported = featuresFile.printJalviewFormat(al.getSequencesArray(),
+            visible);
+    /*
+     * note the order of feature types is uncontrolled - derives from
+     * FeaturesDisplayed.featuresDisplayed which is a HashSet
+     */
+    expected = "METAL\tcc9900\n"
+            + "Pfam\tff0000\n"
+            + "GAMMA-TURN\tff0000|00ffff|20.0|95.0|below|66.0\n"
+            + "\nSTARTGROUP\tuniprot\n"
+            + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n"
+            + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n"
+            + "<html>Pfam domain<a href=\"http://pfam.xfam.org/family/PF00111\">Pfam_3_4</a></html>\tFER_CAPAA\t-1\t20\t20\tPfam\t0.0\n"
+            + "ENDGROUP\tuniprot\n";
+    assertEquals(expected, exported);
+  }
 }
index b1efb7a..c00cf06 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.io;
 
+import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertTrue;
 
@@ -41,24 +42,34 @@ public class IdentifyFileTest
   }
 
   /**
-   * Additional tests for (a) Jalview features file with no colour
-   * specifications (old style 'groups' file) and (b) Jalview features file with
-   * embedded GFF
+   * Additional tests for Jalview features file
    */
   @Test(groups = "Functional")
   public void testIdentify_featureFile()
   {
     IdentifyFile ider = new IdentifyFile();
 
-    // Jalview format with features only, no feature colours
+    /*
+     * Jalview format with features only, no feature colours
+     */
     String data = "Iron-sulfur (2Fe-2S)\tFER_CAPAA\t-1\t39\t39\tMETAL\n"
             + "Iron-phosphorus (2Fe-P)\tID_NOT_SPECIFIED\t2\t86\t87\tMETALLIC\n";
-    Assert.assertEquals(IdentifyFile.FeaturesFile, ider.identify(data, AppletFormatAdapter.PASTE));
+    assertEquals(IdentifyFile.FeaturesFile,
+            ider.identify(data, AppletFormatAdapter.PASTE));
 
-    // Jalview feature colour followed by GFF format feature data
+    /*
+     * Jalview feature colour followed by GFF format feature data
+     */
     data = "METAL\tcc9900\n" + "GFF\n"
             + "FER_CAPAA\tuniprot\tMETAL\t44\t45\t4.0\t.\t.\n";
-    Assert.assertEquals(IdentifyFile.FeaturesFile,
+    assertEquals(IdentifyFile.FeaturesFile,
+            ider.identify(data, AppletFormatAdapter.PASTE));
+
+    /*
+     * Feature with '<' in the name (JAL-2098)
+     */
+    data = "kD < 3\tred\n" + "Low kD\tFER_CAPAA\t-1\t39\t39\tkD < 3\n";
+    assertEquals(IdentifyFile.FeaturesFile,
             ider.identify(data, AppletFormatAdapter.PASTE));
   }
 
index b58a8a6..5e2ceb9 100644 (file)
@@ -422,6 +422,7 @@ public class Jalview2xmlTests
      */
     assertTrue(Jalview2XML.isVersionStringLaterThan(null, null));
     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", null));
+    assertTrue(Jalview2XML.isVersionStringLaterThan(null, "2.8.3"));
     assertTrue(Jalview2XML.isVersionStringLaterThan(null,
             "Development Build"));
     assertTrue(Jalview2XML.isVersionStringLaterThan(null,
diff --git a/test/jalview/util/DnaUtilsTest.java b/test/jalview/util/DnaUtilsTest.java
new file mode 100644 (file)
index 0000000..fbc95ad
--- /dev/null
@@ -0,0 +1,150 @@
+package jalview.util;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.fail;
+
+import java.text.ParseException;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+public class DnaUtilsTest
+{
+  /**
+   * Tests for parsing an ENA/GenBank location specifier
+   * 
+   * @throws ParseException
+   * 
+   * @see http://www.insdc.org/files/feature_table.html#3.4
+   */
+  @Test(groups = { "Functional" })
+  public void testParseLocation() throws ParseException
+  {
+    /*
+     * single locus
+     */
+    List<int[]> ranges = DnaUtils.parseLocation("467");
+    assertEquals(1, ranges.size());
+    assertEquals(467, ranges.get(0)[0]);
+    assertEquals(467, ranges.get(0)[1]);
+
+    /*
+     * simple range
+     */
+    ranges = DnaUtils.parseLocation("12..78");
+    assertEquals(1, ranges.size());
+    assertEquals(12, ranges.get(0)[0]);
+    assertEquals(78, ranges.get(0)[1]);
+
+    /*
+     * join of simple ranges
+     */
+    ranges = DnaUtils.parseLocation("join(12..78,134..202,322..345)");
+    assertEquals(3, ranges.size());
+    assertEquals(12, ranges.get(0)[0]);
+    assertEquals(78, ranges.get(0)[1]);
+    assertEquals(134, ranges.get(1)[0]);
+    assertEquals(202, ranges.get(1)[1]);
+    assertEquals(322, ranges.get(2)[0]);
+    assertEquals(345, ranges.get(2)[1]);
+
+    /*
+     * complement of a simple range
+     */
+    ranges = DnaUtils.parseLocation("complement(34..126)");
+    assertEquals(1, ranges.size());
+    assertEquals(126, ranges.get(0)[0]);
+    assertEquals(34, ranges.get(0)[1]);
+
+    /*
+     * complement of a join
+     */
+    ranges = DnaUtils
+            .parseLocation("complement(join(2691..4571,4918..5163))");
+    assertEquals(2, ranges.size());
+    assertEquals(5163, ranges.get(0)[0]);
+    assertEquals(4918, ranges.get(0)[1]);
+    assertEquals(4571, ranges.get(1)[0]);
+    assertEquals(2691, ranges.get(1)[1]);
+
+    /*
+     * join of two complements
+     */
+    ranges = DnaUtils
+            .parseLocation("join(complement(4918..5163),complement(2691..4571))");
+    assertEquals(2, ranges.size());
+    assertEquals(5163, ranges.get(0)[0]);
+    assertEquals(4918, ranges.get(0)[1]);
+    assertEquals(4571, ranges.get(1)[0]);
+    assertEquals(2691, ranges.get(1)[1]);
+
+    /*
+     * join complement to non-complement
+     * @see http://www.ncbi.nlm.nih.gov/genbank/genomesubmit_annotation/ Transpliced Genes
+     */
+    ranges = DnaUtils
+            .parseLocation("join(complement(36618..36700),86988..87064)");
+    assertEquals(2, ranges.size());
+    assertEquals(36700, ranges.get(0)[0]);
+    assertEquals(36618, ranges.get(0)[1]);
+    assertEquals(86988, ranges.get(1)[0]);
+    assertEquals(87064, ranges.get(1)[1]);
+
+    /*
+     * valid things we don't yet handle
+     */
+    checkForParseException("<34..126");
+    checkForParseException("35..>126");
+    checkForParseException("34.126");
+    checkForParseException("34^126");
+    checkForParseException("order(34..126,130..180)");
+
+    /*
+     * invalid things
+     */
+    checkForParseException("");
+    checkForParseException("JOIN(1..2)");
+    checkForParseException("join(1..2");
+    checkForParseException("join(1..2(");
+    checkForParseException("complement(1..2");
+    checkForParseException("complement(1..2(");
+    try
+    {
+      assertNull(DnaUtils.parseLocation(null));
+      fail("Expected exception");
+    } catch (NullPointerException e)
+    {
+      // expected
+    }
+
+    /*
+     * nested joins are not allowed; just as well since this fails to parse
+     * (splitting tokens by comma fragments the inner join expression)
+     */
+    checkForParseException("join(1..2,join(4..5,10..12),18..22)");
+    /*
+     * complement may not enclose multiple ranges 
+     * parsing fails for the same reason
+     */
+    checkForParseException("join(complement(36618..36700,4000..4200),86988..87064)");
+  }
+
+  /**
+   * Verifies that a ParseException is thrown when the given location is parsed
+   * 
+   * @param location
+   */
+  void checkForParseException(String location)
+  {
+    try
+    {
+      DnaUtils.parseLocation(location);
+      fail("Expected exception");
+    } catch (ParseException e)
+    {
+      // expected;
+    }
+  }
+
+}
index dc2555b..4dc44d4 100644 (file)
@@ -165,4 +165,57 @@ public class StringUtilsTest
     assertEquals(0,
             StringUtils.parseInt(String.valueOf(Integer.MAX_VALUE) + "1"));
   }
+
+  @Test(groups = { "Functional" })
+  public void testCompareVersions()
+  {
+    assertEquals(0, StringUtils.compareVersions(null, null));
+    assertEquals(0, StringUtils.compareVersions("2.8.3", null));
+
+    /*
+     * same version returns 0
+     */
+    assertEquals(0, StringUtils.compareVersions("2.8", "2.8"));
+    assertEquals(0, StringUtils.compareVersions("2.8.3", "2.8.3"));
+    assertEquals(0, StringUtils.compareVersions("2.8.3b1", "2.8.3b1", "b"));
+    assertEquals(0, StringUtils.compareVersions("2.8.3B1", "2.8.3b1", "b"));
+    assertEquals(0, StringUtils.compareVersions("2.8.3b1", "2.8.3B1", "b"));
+
+    /*
+     * v1 < v2 returns -1
+     */
+    assertEquals(-1, StringUtils.compareVersions("2.8.3", "2.8.4"));
+    assertEquals(-1, StringUtils.compareVersions("2.8.3", "2.9"));
+    assertEquals(-1, StringUtils.compareVersions("2.8.3", "2.9.2"));
+    assertEquals(-1, StringUtils.compareVersions("2.8", "2.8.3"));
+    assertEquals(-1, StringUtils.compareVersions("2.8.3", "2.8.3b1", "b"));
+    assertEquals(-1, StringUtils.compareVersions("2.8.3b1", "2.8.3b2", "b"));
+    assertEquals(-1, StringUtils.compareVersions("2.8", "2.8.0", "b"));
+    assertEquals(-1, StringUtils.compareVersions("2", "12"));
+    assertEquals(-1, StringUtils.compareVersions("3.2.4", "3.12.11"));
+
+    /*
+     * v1 > v2 returns +1
+     */
+    assertEquals(1, StringUtils.compareVersions("2.8.3", "2.8"));
+    assertEquals(1, StringUtils.compareVersions("2.8.0", "2.8"));
+    assertEquals(1, StringUtils.compareVersions("2.8.4", "2.8.3"));
+    assertEquals(1, StringUtils.compareVersions("2.8.3b1", "2.8.3", "b"));
+    assertEquals(1, StringUtils.compareVersions("2.8.3", "2.8.2b1", "b"));
+    assertEquals(1, StringUtils.compareVersions("2.8.0b2", "2.8.0b1", "b"));
+    assertEquals(1, StringUtils.compareVersions("12", "2"));
+    assertEquals(1, StringUtils.compareVersions("3.12.11", "3.2.4"));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testToSentenceCase()
+  {
+    assertEquals("John", StringUtils.toSentenceCase("john"));
+    assertEquals("John", StringUtils.toSentenceCase("JOHN"));
+    assertEquals("John and james",
+            StringUtils.toSentenceCase("JOHN and JAMES"));
+    assertEquals("J", StringUtils.toSentenceCase("j"));
+    assertEquals("", StringUtils.toSentenceCase(""));
+    assertNull(StringUtils.toSentenceCase(null));
+  }
 }
index d020173..b560f01 100644 (file)
@@ -76,4 +76,39 @@ public class PDBSequenceFetcherTest
     }
   }
 
+  @Test(groups = { "Network" }, enabled = true)
+  public void testPdbSeqRetrieve() throws Exception
+  {
+    Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
+            Boolean.TRUE.toString());
+    testRetrieveProteinSeqFromPDB();
+  }
+
+  @Test(groups = { "Network" }, enabled = true)
+  public void testmmCifSeqRetrieve() throws Exception
+  {
+    Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
+            Boolean.FALSE.toString());
+    testRetrieveProteinSeqFromPDB();
+  }
+
+  private void testRetrieveProteinSeqFromPDB() throws Exception
+  {
+    List<DbSourceProxy> sps = sf.getSourceProxy("PDB");
+    AlignmentI response = sps.get(0).getSequenceRecords("1QIP");
+    assertTrue(response != null);
+    assertTrue(response.getHeight() == 4);
+    for (SequenceI sq : response.getSequences())
+    {
+      assertTrue("No annotation transfered to sequence.",
+              sq.getAnnotation().length > 0);
+      assertTrue("No PDBEntry on sequence.",
+              sq.getAllPDBEntries().size() > 0);
+      org.testng.Assert
+              .assertEquals(sq.getEnd() - sq.getStart() + 1,
+                      sq.getLength(),
+                      "Sequence start/end doesn't match number of residues in sequence");
+    }
+  }
+
 }
diff --git a/test/jalview/ws/dbsources/XfamFetcherTest.java b/test/jalview/ws/dbsources/XfamFetcherTest.java
new file mode 100644 (file)
index 0000000..c894fd1
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.ws.dbsources;
+
+import jalview.datamodel.AlignmentI;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class XfamFetcherTest
+{
+  @Test(groups = { "External" })
+  public void testRfamSeed() throws Exception
+  {
+    // RfamFull rff = new RfamFull();
+    RfamSeed rfs = new RfamSeed();
+
+    AlignmentI seedrf = rfs.getSequenceRecords(rfs.getTestQuery());
+    Assert.assertNotNull(seedrf, "Seed Alignment for " + rfs.getTestQuery()
+            + " didn't retrieve.");
+    Assert.assertTrue(seedrf.getHeight() > 1,
+            "Seed Alignment for " + rfs.getTestQuery()
+                    + " didn't contain more than one sequence.");
+  }
+
+  @Test(groups = { "External" })
+  public void testPfamFullAndSeed() throws Exception
+  {
+    PfamFull pff = new PfamFull();
+    PfamSeed pfseed = new PfamSeed();
+
+    AlignmentI fullpf = pff.getSequenceRecords(pff.getTestQuery());
+    Assert.assertNotNull(fullpf, "Full Alignment for " + pff.getTestQuery()
+            + " didn't retrieve.");
+    Assert.assertTrue(fullpf.getHeight() > 1,
+            "Full Alignment for " + pff.getTestQuery()
+                    + " didn't have more than one sequence.");
+    AlignmentI seedpf = pfseed.getSequenceRecords(pff.getTestQuery());
+    Assert.assertNotNull(seedpf, "Seed Alignment for " + pff.getTestQuery()
+            + " didn't retrieve.");
+
+    Assert.assertTrue(seedpf.getHeight() < fullpf.getHeight(),
+            "Expected Full alignment to have more sequences than seed for "
+                    + pff.getTestQuery());
+  }
+}
diff --git a/test/jalview/ws/ebi/EBIFetchClientTest.java b/test/jalview/ws/ebi/EBIFetchClientTest.java
new file mode 100644 (file)
index 0000000..4eaa5b1
--- /dev/null
@@ -0,0 +1,113 @@
+package jalview.ws.ebi;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNull;
+
+import org.testng.annotations.Test;
+
+public class EBIFetchClientTest
+{
+  /**
+   * Test method that constructs URL to fetch from
+   */
+  @Test(groups = "Functional")
+  public void testBuildUrl()
+  {
+    /*
+     * EMBL
+     */
+    assertEquals("http://www.ebi.ac.uk/ena/data/view/x53838&display=xml",
+            EBIFetchClient.buildUrl("X53838", "EMBL", "display=xml"));
+
+    /*
+     * EMBLCDS
+     */
+    assertEquals("http://www.ebi.ac.uk/ena/data/view/caa37824&display=xml",
+            EBIFetchClient.buildUrl("CAA37824", "EMBL", "display=xml"));
+
+    /*
+     * Uniprot
+     */
+    assertEquals(
+            "http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/uniprot/p00340/uniprotxml",
+            EBIFetchClient.buildUrl("P00340", "UNIPROT", "uniprotxml"));
+
+    /*
+     * PDB / pdb
+     */
+    assertEquals("http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/pdb/3a6s/pdb",
+            EBIFetchClient.buildUrl("3A6S", "PDB", "pdb"));
+
+    /*
+     * PDB / mmCIF
+     */
+    assertEquals(
+            "http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/pdb/3a6s/mmCIF",
+            EBIFetchClient.buildUrl("3A6S", "PDB", "mmCIF"));
+  }
+
+  /**
+   * Test method that parses db:id;id;id
+   */
+  @Test(groups = "Functional")
+  public void testParseIds()
+  {
+    /*
+     * pdb, two accessions
+     */
+    StringBuilder queries = new StringBuilder();
+    String db = EBIFetchClient.parseIds("pdb:3a6s;1A70", queries);
+    assertEquals("pdb", db);
+    assertEquals("3a6s,1A70", queries.toString());
+
+    /*
+     * pdb specified on second accession
+     */
+    queries.setLength(0);
+    queries = new StringBuilder();
+    db = EBIFetchClient.parseIds("3a6s;pdb:1A70", queries);
+    assertEquals("pdb", db);
+    assertEquals("3a6s,1A70", queries.toString());
+
+    /*
+     * uniprot, one accession
+     */
+    queries.setLength(0);
+    db = EBIFetchClient.parseIds("uniprot:P00340", queries);
+    assertEquals("uniprot", db);
+    assertEquals("P00340", queries.toString());
+
+    /*
+     * uniprot, one accession, appending to existing queries
+     */
+    queries.setLength(0);
+    queries.append("P30419");
+    db = EBIFetchClient.parseIds("uniprot:P00340", queries);
+    assertEquals("uniprot", db);
+    assertEquals("P30419,P00340", queries.toString());
+
+    /*
+     * pdb and uniprot mixed - rejected
+     */
+    queries.setLength(0);
+    db = EBIFetchClient.parseIds("pdb:3a6s;1a70;uniprot:P00340", queries);
+    assertNull(db);
+    assertEquals("3a6s,1a70", queries.toString());
+
+    /*
+     * pdb and PDB mixed - ok
+     */
+    queries.setLength(0);
+    db = EBIFetchClient.parseIds("pdb:3a6s;pdb:1a70;PDB:1QIP", queries);
+    assertEquals("PDB", db);
+    assertEquals("3a6s,1a70,1QIP", queries.toString());
+
+    /*
+     * no database (improper format)
+     */
+    queries.setLength(0);
+    db = EBIFetchClient.parseIds("P00340", queries);
+    assertNull(db);
+    assertEquals("P00340", queries.toString());
+  }
+}
index 64840c2..557ef7e 100644 (file)
@@ -40,7 +40,7 @@ import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
-@Test(groups = { "Network" })
+@Test(groups = { "External" })
 public class DisorderAnnotExportImport
 {
   public static String testseqs = "examples/uniref50.fa";
index a1c2c9a..28113d6 100644 (file)
@@ -26,6 +26,7 @@ import jalview.datamodel.SequenceI;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.IOException;
 import java.io.PrintStream;
 import java.util.HashMap;
 
@@ -122,9 +123,16 @@ public class SiftsClientTest
     // Assert that file isn't yet downloaded - if already downloaded, assert it
     // is deleted
     Assert.assertTrue(SiftsClient.deleteSiftsFileByPDBId(testPDBId));
-    File siftsFile = SiftsClient.downloadSiftsFile(testPDBId);
-    FileAssert.assertFile(siftsFile);
-    SiftsClient.downloadSiftsFile(testPDBId);
+    File siftsFile;
+    try
+    {
+      siftsFile = SiftsClient.downloadSiftsFile(testPDBId);
+      FileAssert.assertFile(siftsFile);
+      SiftsClient.downloadSiftsFile(testPDBId);
+    } catch (IOException e)
+    {
+      e.printStackTrace();
+    }
   }
 
   @Test(groups = { "Functional" })
diff --git a/utils/HelpLinksChecker.java b/utils/HelpLinksChecker.java
new file mode 100644 (file)
index 0000000..1f666a4
--- /dev/null
@@ -0,0 +1,491 @@
+
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A class to check help file cross-references, and external URLs if internet
+ * access is available
+ * 
+ * @author gmcarstairs
+ *
+ */
+public class HelpLinksChecker
+{
+  private static final String HELP_HS = "help.hs";
+
+  private static final String HELP_TOC_XML = "helpTOC.xml";
+
+  private static final String HELP_JHM = "help.jhm";
+
+  private static boolean internetAvailable = true;
+
+  private int targetCount = 0;
+
+  private int mapCount = 0;
+
+  private int internalHrefCount = 0;
+
+  private int anchorRefCount = 0;
+
+  private int externalHrefCount = 0;
+
+  private int invalidMapUrlCount = 0;
+
+  private int invalidTargetCount = 0;
+
+  private int invalidImageCount = 0;
+
+  private int invalidInternalHrefCount = 0;
+
+  private int invalidExternalHrefCount = 0;
+
+  /**
+   * The only parameter should be a path to the root of the help directory in
+   * the workspace
+   * 
+   * @param args
+   *          [0] path to the /html folder in the workspace
+   * @param args
+   *          [1] (optional) -nointernet to suppress external link checking for
+   *          a fast check of internal links only
+   * @throws IOException
+   */
+  public static void main(String[] args) throws IOException
+  {
+    if (args.length == 0 || args.length > 2
+            || (args.length == 2 && !args[1].equals("-nointernet")))
+    {
+      System.out.println("Usage: <pathToHelpFolder> [-nointernet]");
+      return;
+    }
+
+    if (args.length == 2)
+    {
+      internetAvailable = false;
+    }
+
+    new HelpLinksChecker().checkLinks(args[0]);
+  }
+
+  /**
+   * Checks help links and reports results
+   * 
+   * @param helpDirectoryPath
+   * @throws IOException
+   */
+  void checkLinks(String helpDirectoryPath) throws IOException
+  {
+    System.out.println("Checking help file links");
+    File helpFolder = new File(helpDirectoryPath);
+    if (!helpFolder.exists())
+    {
+      System.out.println("Can't find " + helpDirectoryPath);
+      return;
+    }
+
+    internetAvailable &= connectToUrl("http://www.example.com");
+
+    Map<String, String> tocTargets = checkHelpMappings(helpFolder);
+
+    Map<String, String> unusedTargets = new HashMap<String, String>(
+            tocTargets);
+
+    checkTableOfContents(helpFolder, tocTargets, unusedTargets);
+
+    checkHelpSet(helpFolder, tocTargets, unusedTargets);
+
+    checkHtmlFolder(new File(helpFolder, "html"));
+
+    reportResults(unusedTargets);
+  }
+
+  /**
+   * Checks all html files in the given directory or its sub-directories
+   * 
+   * @param folder
+   * @throws IOException
+   */
+  private void checkHtmlFolder(File folder) throws IOException
+  {
+    File[] files = folder.listFiles();
+    for (File f : files)
+    {
+      if (f.isDirectory())
+      {
+        checkHtmlFolder(f);
+      }
+      else
+      {
+        if (f.getAbsolutePath().endsWith(".html"))
+        {
+          checkHtmlFile(f, folder);
+        }
+      }
+    }
+  }
+
+  /**
+   * Checks that any image attribute in help.hs is a valid target
+   * 
+   * @param helpFolder
+   * @param tocTargets
+   * @param unusedTargets
+   *          used targets are removed from here
+   */
+  private void checkHelpSet(File helpFolder,
+          Map<String, String> tocTargets, Map<String, String> unusedTargets)
+          throws IOException
+  {
+    BufferedReader br = new BufferedReader(new FileReader(new File(
+            helpFolder, HELP_HS)));
+    String data = br.readLine();
+    int lineNo = 0;
+
+    while (data != null)
+    {
+      lineNo++;
+      String image = getAttribute(data, "image");
+      if (image != null)
+      {
+        unusedTargets.remove(image);
+        if (!tocTargets.containsKey(image))
+        {
+          System.out.println(String.format(
+                  "Invalid image '%s' at line %d of %s", image, lineNo,
+                  HELP_HS));
+          invalidImageCount++;
+        }
+      }
+      data = br.readLine();
+    }
+    br.close();
+  }
+
+  /**
+   * Print counts to sysout
+   * 
+   * @param unusedTargets
+   */
+  private void reportResults(Map<String, String> unusedTargets)
+  {
+    System.out.println("\nResults:");
+    System.out.println(targetCount + " distinct help targets");
+    System.out.println(mapCount + " help mappings");
+    System.out.println(invalidTargetCount + " invalid targets");
+    System.out.println(unusedTargets.size() + " unused targets");
+    for (String target : unusedTargets.keySet())
+    {
+      System.out.println(String.format("    %s: %s", target,
+              unusedTargets.get(target)));
+    }
+    System.out.println(invalidMapUrlCount + " invalid map urls");
+    System.out.println(invalidImageCount + " invalid image attributes");
+    System.out.println(String.format(
+            "%d internal href links (%d with anchors - not checked)",
+            internalHrefCount, anchorRefCount));
+    System.out.println(invalidInternalHrefCount
+            + " invalid internal href links");
+    System.out.println(externalHrefCount + " external href links");
+    if (internetAvailable)
+    {
+      System.out.println(invalidExternalHrefCount
+              + " invalid external href links");
+    }
+    else
+    {
+      System.out
+              .println("External links not verified as internet not available");
+    }
+
+  }
+
+  /**
+   * Reads the given html file and checks any href attibute values are either
+   * <ul>
+   * <li>a valid relative file path, or</li>
+   * <li>a valid absolute URL (if external link checking is enabled)</li>
+   * </ul>
+   * 
+   * @param htmlFile
+   * @param htmlFolder
+   *          the parent folder (for validation of relative paths)
+   */
+  private void checkHtmlFile(File htmlFile, File htmlFolder)
+          throws IOException
+  {
+    BufferedReader br = new BufferedReader(new FileReader(htmlFile));
+    String data = br.readLine();
+    int lineNo = 0;
+    while (data != null)
+    {
+      lineNo++;
+      String href = getAttribute(data, "href");
+      if (href != null)
+      {
+        String anchor = null;
+        int anchorPos = href.indexOf("#");
+        if (anchorPos != -1)
+        {
+          anchor = href.substring(anchorPos + 1);
+          href = href.substring(0, anchorPos);
+        }
+        boolean badLink = false;
+        if (href.startsWith("http"))
+        {
+          externalHrefCount++;
+          if (internetAvailable)
+          {
+            if (!connectToUrl(href))
+            {
+              badLink = true;
+              invalidExternalHrefCount++;
+            }
+          }
+        }
+        else
+        {
+          internalHrefCount++;
+          File hrefFile = href.equals("") ? htmlFile : new File(htmlFolder,
+                  href);
+          if (!hrefFile.exists())
+          {
+            badLink = true;
+            invalidInternalHrefCount++;
+          }
+          if (anchor != null)
+          {
+            anchorRefCount++;
+            if (!badLink)
+            {
+              if (!checkAnchorExists(hrefFile, anchor))
+              {
+                System.out.println(String.format(
+                        "Invalid anchor: %s at line %d of %s", anchor,
+                        lineNo, getPath(htmlFile)));
+              }
+            }
+          }
+        }
+        if (badLink)
+        {
+          System.out.println(String.format(
+                  "Invalid href %s at line %d of %s", href, lineNo,
+                  getPath(htmlFile)));
+        }
+      }
+      data = br.readLine();
+    }
+    br.close();
+  }
+
+  /**
+   * Reads the file and checks for the presence of the given html anchor
+   * 
+   * @param hrefFile
+   * @param anchor
+   * @return true if anchor is found else false
+   */
+  private boolean checkAnchorExists(File hrefFile, String anchor)
+  {
+    String nameAnchor = "<a name=\"" + anchor + "\"";
+    String idAnchor = "<a id=\"" + anchor + "\"";
+    boolean found = false;
+    try
+    {
+      BufferedReader br = new BufferedReader(new FileReader(hrefFile));
+      String data = br.readLine();
+      while (data != null)
+      {
+        if (data.contains(nameAnchor) || data.contains(idAnchor))
+        {
+          found = true;
+          break;
+        }
+        data = br.readLine();
+      }
+      br.close();
+    } catch (IOException e)
+    {
+      // ignore
+    }
+    return found;
+  }
+
+  /**
+   * Returns the part of the file path starting from /help/
+   * 
+   * @param helpFile
+   * @return
+   */
+  private String getPath(File helpFile)
+  {
+    String path = helpFile.getPath();
+    int helpPos = path.indexOf("/help/");
+    return helpPos == -1 ? path : path.substring(helpPos);
+  }
+
+  /**
+   * Returns true if the URL returns an input stream, or false if the URL
+   * returns an error code or we cannot connect to it (e.g. no internet
+   * available)
+   * 
+   * @param url
+   * @return
+   */
+  private boolean connectToUrl(String url)
+  {
+    try
+    {
+      URL u = new URL(url);
+      InputStream connection = u.openStream();
+      connection.close();
+      return true;
+    } catch (Throwable t)
+    {
+      return false;
+    }
+  }
+
+  /**
+   * Reads file help.jhm and checks that
+   * <ul>
+   * <li>each target attribute is in tocTargets</li>
+   * <li>each url attribute is a valid relative file link</li>
+   * </ul>
+   * 
+   * @param helpFolder
+   */
+  private Map<String, String> checkHelpMappings(File helpFolder)
+          throws IOException
+  {
+    Map<String, String> targets = new HashMap<String, String>();
+    BufferedReader br = new BufferedReader(new FileReader(new File(
+            helpFolder, HELP_JHM)));
+    String data = br.readLine();
+    int lineNo = 0;
+    while (data != null)
+    {
+      lineNo++;
+
+      /*
+       * record target, check for duplicates
+       */
+      String target = getAttribute(data, "target");
+      if (target != null)
+      {
+        mapCount++;
+        if (targets.containsKey(target))
+        {
+          System.out.println(String.format(
+                  "Duplicate target mapping to %s at line %d of %s",
+                  target, lineNo, HELP_JHM));
+        }
+        else
+        {
+          targetCount++;
+        }
+      }
+
+      /*
+       * validate url
+       */
+      String url = getAttribute(data, "url");
+      if (url != null)
+      {
+        targets.put(target, url);
+        int anchorPos = url.indexOf("#");
+        if (anchorPos != -1)
+        {
+          url = url.substring(0, anchorPos);
+        }
+        if (!new File(helpFolder, url).exists())
+        {
+          System.out.println(String.format(
+                  "Invalid url path '%s' at line %d of %s", url, lineNo,
+                  HELP_JHM));
+          invalidMapUrlCount++;
+        }
+      }
+      data = br.readLine();
+    }
+    br.close();
+    return targets;
+  }
+
+  /**
+   * Reads file helpTOC.xml and reports any invalid targets
+   * 
+   * @param helpFolder
+   * @param tocTargets
+   * @param unusedTargets
+   *          used targets are removed from this map
+   * 
+   * @return
+   * @throws IOException
+   */
+  private void checkTableOfContents(File helpFolder,
+          Map<String, String> tocTargets, Map<String, String> unusedTargets)
+          throws IOException
+  {
+    BufferedReader br = new BufferedReader(new FileReader(new File(
+            helpFolder, HELP_TOC_XML)));
+    String data = br.readLine();
+    int lineNo = 0;
+    while (data != null)
+    {
+      lineNo++;
+      /*
+       * assuming no more than one "target" per line of file here
+       */
+      String target = getAttribute(data, "target");
+      if (target != null)
+      {
+        unusedTargets.remove(target);
+        if (!tocTargets.containsKey(target))
+        {
+          System.out.println(String.format(
+                  "Invalid target '%s' at line %d of %s", target, lineNo,
+                  HELP_TOC_XML));
+          invalidTargetCount++;
+        }
+      }
+      data = br.readLine();
+    }
+    br.close();
+  }
+
+  /**
+   * Returns the value of an attribute if found in the data, else null
+   * 
+   * @param data
+   * @param attName
+   * @return
+   */
+  private static String getAttribute(String data, String attName)
+  {
+    /*
+     * make a partial attempt at ignoring within <!-- html comments -->
+     * (doesn't work if multi-line)
+     */
+    int commentStartPos = data.indexOf("<!--");
+    int commentEndPos = commentStartPos == -1 ? -1 : data.substring(
+            commentStartPos + 4).indexOf("-->");
+    String value = null;
+    String match = attName + "=\"";
+    int attPos = data.indexOf(match);
+    if (attPos > 0
+            && (commentStartPos == -1 || attPos < commentStartPos || attPos > commentEndPos))
+    {
+      data = data.substring(attPos + match.length());
+      value = data.substring(0, data.indexOf("\""));
+    }
+    return value;
+  }
+}
index 83d1a98..fc799bb 100755 (executable)
@@ -2025,7 +2025,7 @@ and any path to a file to save to the file]]></string>
                                                                <string><![CDATA[664]]></string>
                                                        </property>
                                                        <property name="sourceName">
-                                                               <string><![CDATA[groovy-all-1.8.2.jar]]></string>
+                                                               <string><![CDATA[groovy-all-2.4.6-indy.jar]]></string>
                                                        </property>
                                                        <property name="overrideUnixPermissions">
                                                                <boolean>false</boolean>
@@ -2043,7 +2043,7 @@ and any path to a file to save to the file]]></string>
                                                                <boolean>true</boolean>
                                                        </property>
                                                        <property name="destinationName">
-                                                               <string><![CDATA[groovy-all-1.8.2.jar]]></string>
+                                                               <string><![CDATA[groovy-all-2.4.6-indy.jar]]></string>
                                                        </property>
                                                        <property name="fileSize">
                                                                <long>6149494</long>
@@ -2891,6 +2891,58 @@ and any path to a file to save to the file]]></string>
                                                        </property>
                                                </object>
                                        </method>
+                                       <method name="addElement">
+                                               <object class="com.zerog.ia.installer.actions.InstallZipfile" objectID="1000ddddfab939">
+                                                       <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[servlet-api-3.1.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[servlet-api-3.1.jar]]></string>
+                                                       </property>
+                                                       <property name="fileSize">
+                                                               <long>16046</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>
                                </object>
                        </property>
                        <property name="rulesFailedMessage">
@@ -7360,6 +7412,7 @@ and any path to a file to read from that file]]></string>
                                                                                <object refID="1f46efeefab93"/>
                                                                                <object refID="1936efeefab93"/>
                                                                                <object refID="1000ddddfab93"/>
+                                                                               <object refID="1000ddddfab939"/>
                                                                                <object refID="10936efeefab93"/>
                                                                                <object refID="11936efeefab93"/>
                                                                                <object refID="12936efeefab93"/>
@@ -7948,6 +8001,7 @@ and any path to a file to read from that file]]></string>
                                                                                                <object refID="1f46efeefab93"/>
                                                                                                <object refID="1936efeefab93"/>
                                                                                                <object refID="1000ddddfab93"/>
+                                                                                               <object refID="1000ddddfab939"/>
                                                                                                <object refID="10936efeefab93"/>
                                                                                                <object refID="11936efeefab93"/>
                                                                                                <object refID="12936efeefab93"/>
diff --git a/utils/MessageBundleChecker.java b/utils/MessageBundleChecker.java
new file mode 100644 (file)
index 0000000..7850eb5
--- /dev/null
@@ -0,0 +1,309 @@
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.TreeSet;
+
+/**
+ * This class scans Java source files for calls to MessageManager and reports
+ * <ul>
+ * <li>calls using keys not found in Messages.properties</li>
+ * <li>any unused keys in Messages.properties</li>
+ * </ul>
+ * It does not handle dynamically constructed keys, these are reported as
+ * possible errors for manual inspection. <br>
+ * For comparing translated bundles with Messages.properties, see i18nAnt.xml
+ * 
+ * @author gmcarstairs
+ *
+ */
+public class MessageBundleChecker
+{
+  /*
+   * number of text lines to read at a time in order to parse
+   * code that is split over several lines
+   */
+  static int bufferSize = 3;
+
+  static final String METHOD1 = "MessageManager.getString(";
+
+  static final String METHOD2 = "MessageManager.getStringOrReturn(";
+
+  static final String METHOD3 = "MessageManager.formatMessage(";
+
+  static final String[] METHODS = { METHOD1, METHOD2, METHOD3 };
+
+  /*
+   * root of the Java source folders we want to scan
+   */
+  String sourcePath;
+
+  /*
+   * contents of Messages.properties
+   */
+  private Properties messages;
+
+  /*
+   * keys from Messages.properties
+   * we remove entries from here as they are found to be used
+   * any left over are unused entries
+   */
+  private TreeSet<String> messageKeys;
+
+  private int javaCount;
+
+  private HashSet<String> invalidKeys;
+
+  /**
+   * Runs the scan given the path to the root of Java source directories
+   * 
+   * @param args
+   *          [0] path to the source folder to scan
+   * @param args
+   *          [1] (optional) read buffer size (default is 3); increasing this
+   *          may detect more results but will give higher error counts due to
+   *          double counting of the same code
+   * @throws IOException
+   */
+  public static void main(String[] args) throws IOException
+  {
+    if (args.length != 1 && args.length != 2)
+    {
+      System.out.println("Usage: <pathToSourceFolder> [readBufferSize]");
+      return;
+    }
+    if (args.length == 2)
+    {
+      bufferSize = Integer.valueOf(args[1]);
+    }
+    new MessageBundleChecker().doMain(args[0]);
+  }
+
+  /**
+   * Main method to perform the work
+   * 
+   * @param srcPath
+   * @throws IOException
+   */
+  private void doMain(String srcPath) throws IOException
+  {
+    System.out.println("Scanning " + srcPath
+            + " for calls to MessageManager");
+    sourcePath = srcPath;
+    loadMessages();
+    File dir = new File(srcPath);
+    if (!dir.exists())
+    {
+      System.out.println(srcPath + " not found");
+      return;
+    }
+    invalidKeys = new HashSet<String>();
+    if (dir.isDirectory())
+    {
+      scanDirectory(dir);
+    }
+    else
+    {
+      scanFile(dir);
+    }
+    reportResults();
+  }
+
+  /**
+   * Prints out counts to sysout
+   */
+  private void reportResults()
+  {
+    System.out.println("\nScanned " + javaCount + " source files");
+    System.out.println("Message.properties has " + messages.size()
+            + " keys");
+    System.out.println("Found " + invalidKeys.size()
+            + " possibly invalid parameter calls");
+
+    System.out.println(messageKeys.size()
+            + " keys not found, possibly unused");
+    for (String key : messageKeys)
+    {
+      System.out.println("    " + key);
+    }
+  }
+
+  /**
+   * Scan all files within a directory
+   * 
+   * @param dir
+   * @throws IOException
+   */
+  private void scanDirectory(File dir) throws IOException
+  {
+    File[] files = dir.listFiles();
+    if (files != null)
+    {
+      for (File f : files)
+      {
+        if (f.isDirectory())
+        {
+          scanDirectory(f);
+        }
+        else
+        {
+          scanFile(f);
+        }
+      }
+    }
+  }
+
+  /**
+   * Scan a Java file
+   * 
+   * @param f
+   */
+  private void scanFile(File f) throws IOException
+  {
+    String path = f.getPath();
+    if (!path.endsWith(".java"))
+    {
+      return;
+    }
+    javaCount++;
+
+    String[] lines = new String[bufferSize];
+    BufferedReader br = new BufferedReader(new FileReader(f));
+    for (int i = 0; i < bufferSize; i++)
+    {
+      String readLine = br.readLine();
+      lines[i] = stripCommentsAndTrim(readLine);
+    }
+
+    int lineNo = 0;
+
+    while (lines[bufferSize - 1] != null)
+    {
+      lineNo++;
+      inspectSourceLines(path, lineNo, lines);
+
+      for (int i = 0; i < bufferSize - 1; i++)
+      {
+        lines[i] = lines[i + 1];
+      }
+      lines[bufferSize - 1] = stripCommentsAndTrim(br.readLine());
+    }
+    br.close();
+
+  }
+
+  /*
+   * removes anything after (and including) '//'
+   */
+  private String stripCommentsAndTrim(String line)
+  {
+    if (line != null)
+    {
+      int pos = line.indexOf("//");
+      if (pos != -1)
+      {
+        line = line.substring(0, pos);
+      }
+      line = line.replace("\t", " ").trim();
+    }
+    return line;
+  }
+
+  /**
+   * Look for calls to MessageManager methods, possibly split over two or more
+   * lines
+   * 
+   * @param path
+   * @param lineNo
+   * @param lines
+   */
+  private void inspectSourceLines(String path, int lineNo, String[] lines)
+  {
+    String lineNos = String.format("%d-%d", lineNo, lineNo + lines.length
+            - 1);
+    String combined = combineLines(lines);
+    for (String method : METHODS)
+    {
+      int pos = combined.indexOf(method);
+      if (pos == -1)
+      {
+        continue;
+      }
+      String methodArgs = combined.substring(pos + method.length());
+      if ("".equals(methodArgs))
+      {
+        /*
+         * continues on next line - catch in the next read loop iteration
+         */
+        continue;
+      }
+      if (!methodArgs.startsWith("\""))
+      {
+        System.out.println(String.format(
+                "Possible dynamic key at %s line %s %s",
+                path.substring(sourcePath.length()), lineNos, combined));
+        continue;
+      }
+      methodArgs = methodArgs.substring(1);
+      int quotePos = methodArgs.indexOf("\"");
+      if (quotePos == -1)
+      {
+        System.out.println(String.format("Trouble parsing %s line %s %s",
+                path.substring(sourcePath.length()), lineNos, combined));
+        continue;
+      }
+      String messageKey = methodArgs.substring(0, quotePos);
+      if (!this.messages.containsKey(messageKey))
+      {
+        System.out.println(String.format(
+                "Unmatched key '%s' at line %s of %s", messageKey, lineNos,
+                path.substring(sourcePath.length())));
+        if (!invalidKeys.contains(messageKey))
+        {
+          invalidKeys.add(messageKey);
+        }
+      }
+      messageKeys.remove(messageKey);
+    }
+  }
+
+  private String combineLines(String[] lines)
+  {
+    String combined = "";
+    if (lines != null)
+    {
+      for (String line : lines)
+      {
+        if (line != null)
+        {
+          combined += line;
+        }
+      }
+    }
+    return combined;
+  }
+
+  /**
+   * Loads properties from Message.properties
+   * 
+   * @throws IOException
+   */
+  void loadMessages() throws IOException
+  {
+    messages = new Properties();
+    FileReader reader = new FileReader(new File(sourcePath,
+            "../resources/lang/Messages.properties"));
+    messages.load(reader);
+    reader.close();
+
+    messageKeys = new TreeSet<String>();
+    for (Object key : messages.keySet())
+    {
+      messageKeys.add((String) key);
+    }
+
+  }
+
+}