Merge branch 'develop' into spike/JAL-1950_hmmer3client
authorJim Procter <jprocter@issues.jalview.org>
Wed, 29 Jun 2016 06:14:49 +0000 (07:14 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Wed, 29 Jun 2016 06:14:49 +0000 (07:14 +0100)
240 files changed:
.classpath
build.xml
doc/AddingGroovySupport.html
doc/building.html
examples/appletDeployment.html
examples/appletParameters.html
examples/applets.html
examples/embedded.html
examples/embeddedWJmol.html
examples/exampleFeatures.txt
examples/formComplete.html
examples/groovy/featureCounter.groovy
examples/groovy/printtitle.groovy
examples/javascriptLaunch.html
examples/linkedapplets_ng.html
examples/plantfdx.features
examples/testdata/simpleGff3.gff
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
help/html/whatsNew.html
lib/Jmol-14.2.14_2015.06.11.jar
lib/VARNAv3-93.jar
lib/groovy-all-1.8.2.jar [deleted file]
lib/groovy-all-2.4.6-indy.jar [new file with mode: 0644]
lib/xercesImpl.jar [changed mode: 0755->0644]
resources/embl_mapping.xml
resources/fts/pdb_data_columns.txt
resources/fts/uniprot_data_columns.txt
resources/lang/Messages.properties
resources/lang/Messages_es.properties
schemas/jalview.xsd
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/SequenceIdMatcher.java
src/jalview/api/AlignViewControllerI.java
src/jalview/api/AlignViewportI.java
src/jalview/api/DBRefEntryI.java
src/jalview/api/FeatureColourI.java
src/jalview/api/FeatureRenderer.java
src/jalview/api/SiftsClientI.java
src/jalview/appletgui/APopupMenu.java
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AnnotationLabels.java
src/jalview/appletgui/FeatureColourChooser.java
src/jalview/appletgui/FeatureRenderer.java
src/jalview/appletgui/FeatureSettings.java
src/jalview/appletgui/IdPanel.java
src/jalview/appletgui/SeqPanel.java
src/jalview/appletgui/SequenceRenderer.java
src/jalview/appletgui/UserDefinedColours.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/HiddenSequences.java
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceFeature.java
src/jalview/datamodel/SequenceGroup.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/core/DecimalFormatTableCellRenderer.java [new file with mode: 0644]
src/jalview/fts/core/FTSDataColumnPreferences.java
src/jalview/fts/core/FTSRestClient.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/AnnotationExporter.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureColourChooser.java
src/jalview/gui/FeatureRenderer.java
src/jalview/gui/FeatureSettings.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/SequenceRenderer.java
src/jalview/gui/StructureChooser.java
src/jalview/gui/TextColourChooser.java
src/jalview/gui/TreePanel.java
src/jalview/io/AnnotationFile.java
src/jalview/io/FeaturesFile.java
src/jalview/io/HtmlSvgOutput.java
src/jalview/io/IdentifyFile.java
src/jalview/io/JSONFile.java
src/jalview/io/PDBFeatureSettings.java
src/jalview/io/StructureFile.java
src/jalview/io/packed/JalviewDataset.java
src/jalview/io/packed/ParsePackedSet.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/schemabinding/version2/.castor.cdr
src/jalview/schemabinding/version2/JSeq.java
src/jalview/schemabinding/version2/descriptors/AnnotationColoursDescriptor.java
src/jalview/schemabinding/version2/descriptors/FeaturesDescriptor.java
src/jalview/schemabinding/version2/descriptors/JSeqDescriptor.java
src/jalview/schemabinding/version2/descriptors/JalviewUserColoursDescriptor.java
src/jalview/schemabinding/version2/descriptors/UserColourSchemeDescriptor.java
src/jalview/schemabinding/version2/descriptors/VamsasModelDescriptor.java
src/jalview/schemes/FeatureColour.java [new file with mode: 0644]
src/jalview/schemes/FeatureColourAdapter.java [deleted file]
src/jalview/schemes/GraduatedColor.java [deleted file]
src/jalview/schemes/RNAHelicesColour.java
src/jalview/schemes/RNAHelicesColourChooser.java
src/jalview/schemes/UserColourScheme.java
src/jalview/structure/StructureMapping.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/viewmodel/seqfeatures/FeatureRendererSettings.java
src/jalview/workers/AlignmentAnnotationFactory.java
src/jalview/workers/StrucConsensusThread.java
src/jalview/ws/DBRefFetcher.java
src/jalview/ws/DasSequenceFeatureFetcher.java
src/jalview/ws/dbsources/EmblXmlSource.java
src/jalview/ws/dbsources/Pdb.java
src/jalview/ws/dbsources/Uniprot.java
src/jalview/ws/ebi/EBIFetchClient.java
src/jalview/ws/jws1/SeqSearchWSThread.java
src/jalview/ws/jws2/AADisorderClient.java
src/jalview/ws/jws2/Jws2Client.java
src/jalview/ws/jws2/MsaWSClient.java
src/jalview/ws/sifts/MappingOutputPojo.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/HiddenSequencesTest.java [new file with mode: 0644]
test/jalview/datamodel/PDBEntryTest.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/EnsemblCdnaTest.java
test/jalview/ext/ensembl/EnsemblCdsTest.java
test/jalview/ext/ensembl/EnsemblGeneTest.java
test/jalview/ext/ensembl/EnsemblGenomeTest.java
test/jalview/ext/ensembl/EnsemblRestClientTest.java
test/jalview/ext/ensembl/EnsemblSeqProxyTest.java
test/jalview/ext/jmol/JmolViewerTest.java
test/jalview/ext/paradise/TestAnnotate3D.java
test/jalview/ext/rbvi/chimera/JalviewChimeraView.java
test/jalview/ext/so/SequenceOntologyTest.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/JAL1353bugdemo.java
test/jalview/gui/PaintRefresherTest.java
test/jalview/gui/StructureChooserTest.java
test/jalview/io/1a70.pdb [new file with mode: 0644]
test/jalview/io/AnnotatedPDBFileInputTest.java
test/jalview/io/FeaturesFileTest.java
test/jalview/io/FileIOTester.java
test/jalview/io/IdentifyFileTest.java
test/jalview/io/JSONFileTest.java
test/jalview/io/Jalview2xmlTests.java
test/jalview/io/JalviewExportPropertiesTests.java
test/jalview/io/NewickFileTests.java
test/jalview/io/RNAMLfileTest.java
test/jalview/schemes/FeatureColourTest.java [new file with mode: 0644]
test/jalview/schemes/UserColourSchemeTest.java [new file with mode: 0644]
test/jalview/util/DnaUtilsTest.java [new file with mode: 0644]
test/jalview/util/StringUtilsTest.java
test/jalview/ws/PDBSequenceFetcherTest.java
test/jalview/ws/ebi/EBIFetchClientTest.java [new file with mode: 0644]
test/jalview/ws/jabaws/JalviewJabawsTestUtils.java
test/jalview/ws/jabaws/JpredJabaStructExportImport.java
test/jalview/ws/jabaws/RNAStructExportImport.java
test/jalview/ws/seqfetcher/DbRefFetcherTest.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 57cd9d2..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>
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..7fcca00 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>
+<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>
-        <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. 
-            The applet archive tag can take multiple entries separated by commas, 
-            eg<br>
-            <pre>&lt;applet code=&quot;jalview.bin.JalviewLite&quot;<em><strong> 
-            archive=&quot;jalviewApplet.jar, mydata.zip&quot;</strong></em>&gt;
-            </pre></li>
-          <li> Use Jalview for input to a HTML form. For an example of how to 
-            code this using Javascript, click <a href="javascript:doSubmit('formComplete')">here</a>. 
-            <br>
-          </li>
-          <li>Embed Jalview into the web page, without the &quot;Start Jalview&quot; 
-            button by setting the embed parameter to true;<br>
-            &lt;param name=&quot;embedded&quot;
-          value=&quot;true&quot;&gt; </li>
-       <li><a href="javascript:doSubmit('appletParameters')">View full list of supported parameters here.</a> </li>
-        </ul>
-        
-        <p><strong>**NEW FEATURES** in Jalview 2.9</strong></p> 
+<h2 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/jalviewApplet.jar">JalviewApplet.jar</a> </td>
+    <td>Main Jalview Applet Jar</td>
+  </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>
+
+<p>To run Jalview applet in your web page download the Jars listed above. The snippet below shows a minimal code for embedding Jalview applet into a web page.    
+<pre><code>
+&lt;applet code="jalview.bin.JalviewLite" width="756" height="560" archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar"&gt;
+       &lt;param name="permissions" value="sandbox" /&gt;
+       &lt;param name="file" value="plantfdx.fa" /&gt;
+       &lt;param name="features" value="plantfdx.features" /&gt;
+       &lt;param name="userDefinedColour" value="C=yellow; R,K,H=FF5555; D,E=5555FF" /&gt;
+       &lt;param name="showFullId" value="false" /&gt;
+       &lt;param name="embedded" value="true" /&gt;
+       &lt;param name="linkLabel_1" value="Uniprot" /&gt;
+       &lt;param name="linkUrl_1"      value="http://www.uniprot.org/uniprot/$SEQUENCE_ID$" /&gt;
+       &lt;param name="linkLabel_2" value="EMBL-EBI Search" /&gt;
+       &lt;param name="linkUrl_2"      value="http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$" /&gt;
+       &lt;param name="APPLICATION_URL" value="http://www.jalview.org/services/launchApp" /&gt;
+&lt;/applet&gt;
+</code></pre> 
+
+
+
+
+<ul>
+       <li>View full list of <a href="javascript:doSubmit('appletParameters')"> supported applet parameters here.</a></li>
+       <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. The applet archive tag can take multiple entries separated by
+               commas, eg<br> <pre>&lt;applet code=&quot;jalview.bin.JalviewLite&quot;<em><strong> archive=&quot;jalviewApplet.jar, mydata.zip&quot;</strong></em>&gt;
+            </pre>
+       </li>
+       <li>Use Jalview for input to a HTML form. For an example of how to
+               code this using Javascript, click <a
+               href="javascript:doSubmit('formComplete')">here</a>. <br>
+       </li>
+       <li>Embed Jalview into the web page, without the &quot;Start
+               Jalview&quot; button by setting the embed parameter to true;<br>
+               &lt;param name=&quot;embedded&quot; value=&quot;true&quot;&gt;
+       </li>
+       <li>For more examples, see the links to the left.</li>
+</ul>
+
+<table border="1" width=80%>
+       <tr><th colspan="2">Applet Release History</th>
+       <tr>
+               <th>Release</th>
+
+               <th>New Features / required changes</th>
+       </tr>
+       <tr>
+               <td><strong>2.9<br>(Latest)</strong></td>
+               <td>
         <ul>
         <li>Split Views for cDNA and Protein alignments<br/>Specify second alignment with 'file2' parameter, and set cDNA/Protein column scaling with scaleProteinAsCdna
         </li>
             <pre>archive=&quot;jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,<font color="red">java-json.jar,json_simple-1.1.jar</font>&quot;</pre>              
        </li>
         </ul>
-        </p>
-        <p><strong>**NEW FEATURES** in Jalview 2.8</strong></p> 
-        <ul>
+               </td>
+       </tr>
+       <tr>
+               <td><strong>2.8</strong></td>
+               <td><ul>
         <li>Normalised sequence logo display
         </li>
         <li>RNA secondary structure annotation row
             original Jalview structure viewer will still be available. <br>
           </li>
           
-        </ul>
-        <p><strong>**NEW FEATURES** in Jalview 2.7</strong></p>
-        <ul>
+        </ul></td>
+       </tr>
+       <tr>
+               <td><strong>2.7</strong></td>
+               <td><ul>
         <li>Javascript callbacks capabilities<ul><li>oninit parameter and methods for registering javascript handlers for selections, mouseovers and linking to Jmol applets on the page.</li>
         <li>To use javascript callbacks, ensure the applet tag includes the '<a href="http://download.oracle.com/javase/6/docs/technotes/guides/plugin/developer_guide/java_js.html">mayscript</a>' attribute - either as a parameter (&lt;param name="mayscript" value="true"/;gt;) or as a bare attribute in the applet html tag).</li></ul>
         </li>
           the Jmol binary distribution available at the Jmol Sourceforge site, 
           or <a href="JmolApplet-12.1.13.jar">download the Jmol applet from here</a></li>
           <li>Minimum recommended version of Java runtime for the applet is now 1.5 (JalviewLite v2.6 without the Jmol viewer may work ok on earlier Java environments but compatibility can no-longer be guaranteed).</li>
-  </ul>
-        <br><strong>**NEW FEATURES** in Jalview 2.5</strong></p>
-        <ul>
-        <li>New parameters to control display of tree annotation, width of alignment columns, and to disable the jalview button and check for Jmol on startup.</li>
-  </ul>        
-        <br><strong>**NEW FEATURES** in Jalview 2.4</strong></p>
-        <ul>
+  </ul></td>
+       </tr>
+       <tr>
+               <td><strong>2.5</strong></td>
+               <td><ul>
+        <li>New parameters to control display of tree annotation, width of alignment columns, and to disable the jalview button and check for Jmol on startup.</li>  </ul>
+    </td>
+       </tr>
+       <tr>
+               <td><strong>2.4</strong></td>
+               <td><ul>
         <li>New applet API methods for feature display control, views, and obtaining current selection via javascript.</li>
           <li>Group show and hide parameters:
         &quot;showfeaturegroups&quot; and
         <li>&quot;debug&quot; parameter to control verbosity of the applet's console output.</li>
         <li>&quot;showbutton&quot; parameter to disable launch button and open JalviewLite immediatly.</li>
         <li>&quot;nojmol&quot; parameter to disable check for Jmol classes.</li>
-        </ul><br>
-        <strong>**NEW FEATURES** in Jalview 2.3</strong></p>
-        <ul>
+        </ul></td>
+       </tr>
+       <tr>
+               <td><strong>2.3</strong></td>
+               <td><ul>
           <li>Note that Parameter &quot;PDBFile&quot; now takes 
             the PDB file followed by a space separated list of alignment sequence 
             ids to associate the structure to. It is also possible to associate 
           <li>Note parameter &quot;PDBSeq&quot; is no longer required.<br>
           </li>
           <li>Jalview 2.3 was updated to work with Jmol 11. See the <a href="/development">versions archive if you want to download the old Jmol applet</a>.</li> 
-            <p>&nbsp;</p>
-          </li>
-        </ul>
-        <strong>**NEW FEATURES** in Jalview 2.1</strong> 
-        <ul>
+          
+        </ul></td>
+       </tr>
+       <tr>
+               <td><strong>2.1</strong></td>
+               <td><ul>
           <li>Jalview Applet can read and display JNet secondary structure annotation 
             directly via the <strong>jnetfile</strong> parameter. <br>
           </li>
             &lt;param name=&quot;sequence2&quot; value=&quot;FER1_PEA/14-29 TSFLRTQPMPMSVTTT&quot;&gt;<br>
             </pre>(All the usual Jalview File formats are valid, however each 
             new line in an alignment file must be entered as a parameter)</li>
-        </ul>
+        </ul></td>
+       </tr>
+</table>
+
+        
 <!-- content end -->
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 34118b8..1f65565 100644 (file)
 
 <!-- boiler plate link to alternate demopage -->
 <div style="width: 100%">
-<div style="width:35%; align:left; float:right;">
-<div style="margin:8px; padding:10px; border: 2px solid black; align: left;">
-<p>Quick Links to jars for example:<br/><a href="jalviewApplet.jar">jalviewApplet.jar</a> and <a href="JmolApplet-14.2.14_2015.06.11.jar">JmolApplet.jar</a>
-</p></div>
 </div>
-</div>
-
 <!-- content template start -->
 
 <p align="left">
 <h2>JalviewLite Button Examples</h2>
-Try out JalviewLite by pressing one of the buttons below.<br/>
- For more information on how to use the applet in your website, see the <a href="javascript:doSubmit('appletParameters')"><strong>applet parameters</strong></a> and other documentation in the links to the left.</p>
+Try out JalviewLite by pressing one of the buttons below. 
+  <a href="view-source:http://www.jalview.org/builds/develop/examples/applets.html" target="_blank">View the source for the examples below here</a> (If the link doesn't work on your browser try going to <a href="http://www.jalview.org/builds/develop/examples/applets.html">this page</a> and viewing the page source manually).<br/>
+ For more information on how to use the applet in your website, see the <a href="javascript:doSubmit('appletDeployment')"><strong>applet deployment,</strong></a> <a href="javascript:doSubmit('appletParameters')"><strong>applet parameters,</strong></a> and other documentation in the links to the left.</p>
 <p>&nbsp;</p><div align="center">
   <p align="center">
     <h2>Ferredoxins, chloroplast precursor related UniRef50
index aa67325..0d5ddf3 100644 (file)
@@ -23,9 +23,6 @@
 <!-- boiler plate link to alternate demopage -->
 <div style="width: 100%">
 <div style="width:35%; align:left; float:right;">
-<div style="margin:8px; padding:10px; border: 2px solid black; align: left;">
-<p>Quick Links to jars for example:<br/><a href="jalviewApplet.jar">jalviewApplet.jar</a> and <a href="JmolApplet-14.2.14_2015.06.11.jar">JmolApplet.jar</a>
-</p></div>
 </div>
 </div>
 
@@ -40,6 +37,7 @@
     <li><a href="plantfdx.annotations">plantfdx.annotations</a> -
       Jalview Alignment Annotations File</li>
   </ul>
+  <a href="view-source:http://www.jalview.org/builds/develop/examples/embedded.html" target="_blank">View the source code for this example here</a> (If the link doesn't work on your browser try going to <a href="http://www.jalview.org/builds/develop/examples/embedded.html">this page</a> and viewing the page source manually).<p>
   <applet
    code="jalview.bin.JalviewLite" width="756" height="560"
    archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar">
index f629312..1ecff58 100644 (file)
@@ -260,11 +260,7 @@ jmolInitialize("","JmolApplet-14.2.14_2015.06.11.jar");
   modeltofiles+="1gaq.txt";
 </script> 
 <div style="width: 100%">
-<div style="width:35%; align:left; float:right;">
-<div style="margin:8px; padding:10px; border: 2px solid black; align: left;">
-<p>Quick Links to jars for example:<br/><a href="jalviewApplet.jar">jalviewApplet.jar</a> and <a href="JmolApplet-14.2.14_2015.06.11.jar">JmolApplet.jar</a>
-</p></div>
-</div>
+
 </div>
 
 <!-- content template start -->
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 91d94f8..9e89990 100644 (file)
@@ -24,9 +24,7 @@
 <!-- boiler plate link to alternate demopage -->
 <div style="width: 100%">
 <div style="width:35%; align:left; float:right;">
-<div style="margin:8px; padding:10px; border: 2px solid black; align: left;">
-<p>Quick Links to jars for example:<br/><a href="jalviewApplet.jar">jalviewApplet.jar</a> and <a href="JmolApplet-14.2.14_2015.06.11.jar">JmolApplet.jar</a>
-</p></div>
+
 </div>
 </div>
 
@@ -35,7 +33,7 @@
 <p>Using the Javascript API to fill out forms using data from JalviewLite
 <br/>Click the Javascript buttons below to interact with the Applet
 instance on the page.</p>
-View the source in your browser to see how it has been done. <br/>
+  <a href="view-source:http://www.jalview.org/builds/develop/examples/formComplete.html" target="_blank">View the source here to see how it has been done</a>  (If the link doesn't work on your browser try going to <a href="http://www.jalview.org/builds/develop/examples/formComplete.html">this page</a> and viewing the page source manually).<br/>
 <a name="api">View the full <a href="javascript:doSubmit('jalviewLiteJs')">JalviewLite API documentation</a>.</a>
 <applet code="jalview.bin.JalviewLite" width="0" height="0"
        archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar" name="Jalview">
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 e161ad6..35b1d81 100644 (file)
 
 <!-- boiler plate link to alternate demopage -->
 <div style="width: 100%">
-<div style="width:35%; align:left; float:right;">
 
-<div style="margin:8px; padding:10px; border: 2px solid black; align: left;">
-<p>Quick Links to jars for example:<br/><a href="jalviewApplet.jar">jalviewApplet.jar</a> and <a href="JmolApplet-14.2.14_2015.06.11.jar">JmolApplet.jar</a>
-</p></div>
-</div>
 </div>
 
 <!-- content template start -->
@@ -120,7 +115,7 @@ archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_
 <param name="showbutton" value="false"/>
 </applet>
 
-<h2>Javascript Launch Button</h2><p>The button below demonstrates how JalviewLite can be launched via a javascript action.</p>
+<h2>Javascript Launch Button</h2><p>The button below demonstrates how JalviewLite can be launched via a javascript action.  <a href="view-source:http://www.jalview.org/builds/develop/examples/javascriptLaunch.html" target="_blank">View the source here to see how it has been done</a> (If the link doesn't work on your browser try going to <a href="http://www.jalview.org/builds/develop/examples/javascriptLaunch.html">this page</a> and viewing the page source manually). </p>
 
   <input type="button" name="Button1" value="Start"
 onClick="startJalview('plantfdx.fa','Button1.alignment','alwvar')"/>
index 0449c0b..5890515 100644 (file)
@@ -22,9 +22,7 @@
 <!-- boiler plate link to alternate demopage -->
 <div style="width: 100%">
 <div style="width:35%; align:left; float:right;">
-<div style="margin:8px; padding:10px; border: 2px solid black; align: left;">
-<p>Quick Links to jars for example:<br/><a href="jalviewApplet.jar">jalviewApplet.jar</a> and <a href="JmolApplet-14.2.14_2015.06.11.jar">JmolApplet.jar</a>
-</p></div>
+
 </div>
 </div>
 
@@ -36,7 +34,7 @@
 
     <h2>JalviewLite Linked Applets Demo</h2>
     <p>The two applets below use <a href="javascript:doSubmit('jalviewLiteJs')">JalviewLite's javascript API</a> to exchange events about the currently selected region and mouse position in the alignment.
-    </p>
+    <a href="view-source:http://www.jalview.org/builds/develop/examples/linkedapplets_ng.html" target="_blank">View the source here to see how it has been done</a>  (If the link doesn't work on your browser try going to <a href="http://www.jalview.org/builds/develop/examples/linkedapplets_ng.html">this page</a> and viewing the page source manually).</p>
 
 
 <applet
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 34b64ee..614b440 100644 (file)
@@ -24,4 +24,3 @@ seq1  exonerate:protein2genome:local  similarity      9       11      3652    -       .       alignment_id 0 ; Qu
 ACTACGACACGACGACGACGACG
 >seq2
 CDEQEATGTQDAQEQAQC
-
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 0bb5fb7..0e7d02d 100755 (executable)
     <tr>
       <td width="60" nowrap>
         <div align="center">
-          <strong><a name="Jalview.2.9.1">2.9.1</a><br /> <em>1/6/2016</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></li>
+            <li><!-- JAL---></li>
+            <li><!-- JAL-192 --->Alignment ruler shows positions relative to reference sequence</li>
         </ul> <em>Application</em>
         <ul>
-          <li></li>
+            <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>
+            <li><!-- JAL-1369 --->Store/restore reference sequence in Jalview projects</li>
+             
         </ul> <em>Applet</em>
         <ul>
-          <li></li>
+            <li><!-- JAL---></li>
         </ul></td>
       <td>
         <div align="left">
           <em>General</em>
           <ul>
-            <li></li>
+            <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>
+            <li><!-- JAL-2065  -->Alignment view stops updating when show unconserved enabled for group on alignment</li>
+            <li><!--  JAL-2086  -->Cannot insert gaps into sequence when set as reference</li>
+            
           </ul>
           <em>Application</em>
           <ul>
-            <li></li>
+            <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>
+            <li><!--  JAL-2085  -->Cannot save project when view has a reference sequence defined</li>
+            <li><!--  JAL-1011  -->Columns are suddenly selected in other alignments and views when revealing hidden columns</li>
+            <li><!--  JAL-1989  -->Hide columns not mirrored in complement view in a cDNA/Protein splitframe</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>
+            <li><!--  --></li>
           </ul>
         </div>
       </td>
             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
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 19be76f..d7a93c6 100755 (executable)
     <strong>What's new ?</strong>
   </p>
   <p>
-    Jalview 2.9.0b2 is a bug fix release for Jalview 2.9.
-    The release of Jalview 2.9 in September 2015 included
-    a multitude of bug fixes and minor improvements (both small, and
-    rather big!), it also brings major new capabilities for codon-level
-    analysis of protein alignments and the retrieval and manipulation of
-    structural data.</p><p>For the patches since version 2.9 was released, see the
-    <a href="releases.html#Jalview.2.9.0b2">Jalview 2.9.0b2 Release Notes</a>.
+    Jalview 2.9.1 is the next major release in the Jalview 2.9 series. Full details are in the
+    <a href="releases.html#Jalview.2.9.1">Jalview 2.9.1 Release Notes</a>.
   </p>
   <p>
-    <strong>Highlights in Jalview 2.9</strong>
+    <strong>Highlights in Jalview 2.9.1</strong>
   <ul>
-    <li><strong>Visualisation, editing and analysis of
-        cDNA and Protein alignments</strong><br />A new <a
-      href="features/splitView.html">Split View</a> window allows linked
-      protein and nucleotide sequence alignments to be viewed, edited,
-      and analysed as one. <br />cDNA alignments can also be
-      reconstructed from protein alignments calculated by Jalview's web
-      services, and update in response to edits in the amino acid view.<br />To
-      start experimenting with cDNA/Protein analysis, jut drop a file
-      containing cDNA sequences which code for proteins in an existing
-      alignment, and Jalview will do the rest.</li>
-    <li><strong>Enhanced Integration of UCSF Chimera</strong> <br>Jalview
-      2.9 provides full support for the use of Chimera to view 3D
-      structures linked to alignment views in the Jalview Desktop. We've
-      also included support for saving Chimera sessions in Jalview
-      project files.<br />Jalview and Chimera communicate using local
-      web server connections, which may cause firewall alerts on some
-      systems, but has the advantage of allowing bidirectional
-      communication. Communication between Jalview and Chimera is now
-      much more responsive, and selected regions in Chimera are now
-      shown as highlighted regions in the Jalview desktop.</li>
-    <li><strong>Interactive querying of the PDBe</strong><br />Jalview
-      users can now <a href="features/pdbsequencefetcher.html">browse</a> and <a href="features/viewingpdbs.html">retrieve 3D structure</a> data from the PDB
-      via the <a href="http://www.ebi.ac.uk/pdbe/api/doc/search.html">PDBe
-        Search API</a> (<a href="http://dx.doi.org/10.1093%2Fnar%2Fgkt1180">Gutmanas
-        et al 2014</a>). Developed in collaboration with the PDBe group at
-      EMBL-EBI, the interface allows both structured and free-text
-      queries to be performed, and allows automatic selection of the
-      most relevant structures for an alignment acording to a variety of
-      criteria.</li>
-    <li><strong>Improved support for RNA visualisation</strong><br />Jalview
-      2.9 integrates the latest version of the <a
-      href="features/varna.html">VARNA RNA Viewer</a>, and VARNA views
-      can also now be stored in Jalview projects. We've also dealt with
-      a number of lingering bugs in the VARNA/Jalview interface,
-      including the loss of pseudoknots when RNA secondary structure is
-      shown VARNA.</li>
-    <li><strong>Protein Secondary Structure predictions
-        with JPred4</strong><br />Jalview includes a number of new features for
-      working with secondary structure predictions from the JPred4
-      server. These include new <a href="menus/popupMenu.html#hideinserts">popup menu actions</a> to automatically hide insertions and highlight
-      mutations in an alignment with respect to a <a href="calculations/referenceseq.html">Reference
-        Sequence</a>. Jalview 2.9's new <a href="io/export.html#htmlexport">scrollable
-        SVG HTML export</a> was also developed specifically for the JPred4
-      server.</li>
   </ul>
 
 </body>
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
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
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>
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
 #
index 6c78c16..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
@@ -35,16 +56,16 @@ _data_column.preferred_col_width
 _data_column.is_shown_by_default
 _data_column.is_searchable
 Uniprot Id;id;String;g3;80;150;85;true;true
-Entry Name;entry name|name;String;g3;100;150;105;true;true
-Protein names;protein names|protein name;String;g3;300;1500;500;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;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
+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
@@ -55,9 +76,9 @@ 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
 Status;reviewed;String;g6;50;100;95;true;true
-Length;length;int;g7;50;100;65;true;true
-Mass;mass;String;g7;50;100;80;false;true
-Sequence;sequence;String;g7;50;1000;95;false;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
@@ -83,15 +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
-ALL;Search All;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
@@ -131,7 +152,7 @@ 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;comment(DOMAIN)|domain;String;g18;80;1000;95;false;true
+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|family;String;g18;50;1000;95;false;true
 Coiled coil;feature(COILED COIL);String;g18;50;1000;95;false;false
index 62c813a..40c311f 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 (or pdbid:chaincode)
 label.discover_pdb_ids = Discover PDB IDs
 label.text_colour = Text Colour
 action.set_text_colour = Text Colour...
@@ -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
@@ -1286,19 +1287,24 @@ exception.fts_server_unreachable = Jalview is unable to reach the {0} server. \n
 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
 action.next_page= >> 
 action.prev_page= << 
-label.next_page_tooltop=Next Page
-label.prev_page_tooltop=Previous 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 850b223..f0bd638 100755 (executable)
                                                <xs:attribute name="end" type="xs:int" use="required" />
                                                <xs:attribute name="id" type="xs:string" use="required" />
                                                <xs:attribute name="hidden" type="xs:boolean" />
+                                               <xs:attribute name="viewreference" type="xs:boolean" use="optional"/>
                                        </xs:complexType>
                                </xs:element>
                                <xs:element name="JGroup" minOccurs="0" maxOccurs="unbounded">
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..33a54e8 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;
@@ -1331,15 +1332,19 @@ public class AlignmentUtils
           Collection<String> types, List<SequenceI> forSequences,
           boolean anyType, boolean doShow)
   {
-    for (AlignmentAnnotation aa : al.getAlignmentAnnotation())
+    AlignmentAnnotation[] anns = al.getAlignmentAnnotation();
+    if (anns != null)
     {
-      if (anyType || types.contains(aa.label))
+      for (AlignmentAnnotation aa : anns)
       {
-        if ((aa.sequenceRef != null)
-                && (forSequences == null || forSequences
-                        .contains(aa.sequenceRef)))
+        if (anyType || types.contains(aa.label))
         {
-          aa.visible = doShow;
+          if ((aa.sequenceRef != null)
+                  && (forSequences == null || forSequences
+                          .contains(aa.sequenceRef)))
+          {
+            aa.visible = doShow;
+          }
         }
       }
     }
@@ -1927,11 +1932,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 +2118,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 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 d8363f4..1fcbfd0 100644 (file)
@@ -1,13 +1,14 @@
 package jalview.api;
 
+import jalview.datamodel.SequenceFeature;
+
 import java.awt.Color;
 
 public interface FeatureColourI
 {
 
   /**
-   * Answers true when either isColourByLabel, isAboveThreshold or
-   * isBelowThreshold answers true
+   * Answers true when the feature colour varies across the score range
    * 
    * @return
    */
@@ -35,13 +36,22 @@ public interface FeatureColourI
   Color getMaxColour();
 
   /**
-   * Answers true if the feature is coloured by label (description); only
-   * applicable when isGraduatedColour answers true
+   * Answers true if the feature has a single colour, i.e. if isColourByLabel()
+   * and isGraduatedColour() both answer false
+   * 
+   * @return
+   */
+  boolean isSimpleColour();
+
+  /**
+   * Answers true if the feature is coloured by label (description)
    * 
    * @return
    */
   boolean isColourByLabel();
 
+  void setColourByLabel(boolean b);
+
   /**
    * Answers true if the feature is coloured below a threshold value; only
    * applicable when isGraduatedColour answers true
@@ -50,6 +60,8 @@ public interface FeatureColourI
    */
   boolean isBelowThreshold();
 
+  void setBelowThreshold(boolean b);
+
   /**
    * Answers true if the feature is coloured above a threshold value; only
    * applicable when isGraduatedColour answers true
@@ -58,14 +70,20 @@ public interface FeatureColourI
    */
   boolean isAboveThreshold();
 
+  void setAboveThreshold(boolean b);
+
   /**
-   * Answers true if the threshold is the min (or max) of the colour range; only
-   * applicable when isGraduatedColour answers true
+   * Answers true if the threshold is the minimum value (when
+   * isAboveThreshold()) or maximum value (when isBelowThreshold()) of the
+   * colour range; only applicable when isGraduatedColour and either
+   * isAboveThreshold() or isBelowThreshold() answers true
    * 
    * @return
    */
   boolean isThresholdMinMax();
 
+  void setThresholdMinMax(boolean b);
+
   /**
    * Returns the threshold value (if any), else zero
    * 
@@ -73,10 +91,71 @@ public interface FeatureColourI
    */
   float getThreshold();
 
+  void setThreshold(float f);
+
+  /**
+   * Answers true if the colour varies between the actual minimum and maximum
+   * score values of the feature, or false if between absolute minimum and
+   * maximum values (or if not a graduated colour).
+   * 
+   * @return
+   */
+  boolean isAutoScaled();
+
+  void setAutoScaled(boolean b);
+
+  /**
+   * Returns the maximum score of the graduated colour range
+   * 
+   * @return
+   */
+  float getMax();
+
+  /**
+   * Returns the minimum score of the graduated colour range
+   * 
+   * @return
+   */
+  float getMin();
+
+  /**
+   * Answers true if either isAboveThreshold or isBelowThreshold answers true
+   * 
+   * @return
+   */
+  boolean hasThreshold();
+
+  /**
+   * Returns the computed colour for the given sequence feature
+   * 
+   * @param feature
+   * @return
+   */
+  Color getColor(SequenceFeature feature);
+
+  /**
+   * Answers true if the feature has a simple colour, or is coloured by label,
+   * or has a graduated colour and the score of this feature instance is within
+   * the range to render (if any), i.e. does not lie below or above any
+   * threshold set.
+   * 
+   * @param feature
+   * @return
+   */
+  boolean isColored(SequenceFeature feature);
+
+  /**
+   * Update the min-max range for a graduated colour scheme
+   * 
+   * @param min
+   * @param max
+   */
+  void updateBounds(float min, float max);
+
   /**
-   * Answers true if ?
+   * Returns the colour in Jalview features file format
    * 
    * @return
    */
-  boolean isLowToHigh();
+  String toJalviewFormat(String featureType);
 }
index 5b15cad..dbc9880 100644 (file)
@@ -60,17 +60,15 @@ public interface FeatureRenderer
    * @param ft
    * @return display style for a feature
    */
-  Object getFeatureStyle(String ft);
+  FeatureColourI getFeatureStyle(String ft);
 
   /**
    * update the feature style for a particular feature
    * 
    * @param ft
    * @param ggc
-   *          - currently allows java.awt.Color and
-   *          jalview.schemes.GraduatedColor
    */
-  void setColour(String ft, Object ggc);
+  void setColour(String ft, FeatureColourI ggc);
 
   AlignViewportI getViewport();
 
@@ -85,7 +83,7 @@ public interface FeatureRenderer
    * 
    * @return
    */
-  Map<String, Object> getFeatureColours();
+  Map<String, FeatureColourI> getFeatureColours();
 
   /**
    * query the alignment view to find all features
@@ -100,7 +98,7 @@ public interface FeatureRenderer
    * 
    * @return
    */
-  Map<String, Object> getDisplayedFeatureCols();
+  Map<String, FeatureColourI> getDisplayedFeatureCols();
 
   /**
    * get all registered groups
@@ -143,12 +141,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..dad434a 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
 {
   /**
@@ -45,12 +47,6 @@ public interface SiftsClientI
    */
   public String getDbCoordSys();
 
-  /**
-   * Get DB Evidence for the SIFTs Entry
-   * 
-   * @return
-   */
-  public String getDbEvidence();
 
   /**
    * Get DB Source for the SIFTs Entry
@@ -99,13 +95,6 @@ public interface SiftsClientI
   public boolean isAccessionMatched(String accessionId);
 
   /**
-   * Get the standard DB referenced by the SIFTs Entry
-   * 
-   * @return
-   */
-  public String[] getEntryDBs();
-
-  /**
    * 
    * @param mop
    *          MappingOutputPojo
index 748954a..948c8e5 100644 (file)
@@ -537,6 +537,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
     MenuItem item = new MenuItem(label);
     item.addActionListener(new java.awt.event.ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         ap.alignFrame.showURL(url, target);
@@ -545,6 +546,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
     linkMenu.add(item);
   }
 
+  @Override
   public void itemStateChanged(ItemEvent evt)
   {
     if (evt.getSource() == abovePIDColour)
@@ -569,6 +571,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
     }
   }
 
+  @Override
   public void actionPerformed(ActionEvent evt)
   {
     Object source = evt.getSource();
@@ -1299,35 +1302,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
 
   void hideSequences(boolean representGroup)
   {
-    SequenceGroup sg = ap.av.getSelectionGroup();
-    if (sg == null || sg.getSize() < 1)
-    {
-      ap.av.hideSequence(new SequenceI[] { seq });
-      return;
-    }
-
-    ap.av.setSelectionGroup(null);
-
-    if (representGroup)
-    {
-      ap.av.hideRepSequences(seq, sg);
-
-      return;
-    }
-
-    int gsize = sg.getSize();
-    SequenceI[] hseqs;
-
-    hseqs = new SequenceI[gsize];
-
-    int index = 0;
-    for (int i = 0; i < gsize; i++)
-    {
-      hseqs[index++] = sg.getSequenceAt(i);
-    }
-
-    ap.av.hideSequence(hseqs);
-    ap.av.sendSelection();
+    ap.av.hideSequences(seq, representGroup);
   }
 
   /**
index e5f0053..8f1f2fd 100644 (file)
@@ -25,6 +25,7 @@ import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.api.AlignViewControllerGuiI;
 import jalview.api.AlignViewControllerI;
 import jalview.api.AlignViewportI;
+import jalview.api.FeatureColourI;
 import jalview.api.FeatureRenderer;
 import jalview.api.FeatureSettingsControllerI;
 import jalview.api.SequenceStructureBinding;
@@ -367,7 +368,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     boolean featuresFile = false;
     try
     {
-      Map<String, Object> colours = alignPanel.seqPanel.seqCanvas
+      Map<String, FeatureColourI> colours = alignPanel.seqPanel.seqCanvas
               .getFeatureRenderer().getFeatureColours();
       boolean relaxedIdMatching = viewport.applet.getDefaultParameter(
               "relaxedidmatch", false);
@@ -1399,7 +1400,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     return annotation;
   }
 
-  private Map<String, Object> getDisplayedFeatureCols()
+  private Map<String, FeatureColourI> getDisplayedFeatureCols()
   {
     if (alignPanel.getFeatureRenderer() != null
             && viewport.getFeaturesDisplayed() != null)
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 46a67c4..3c04ccd 100644 (file)
  */
 package jalview.appletgui;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.GraphLine;
 import jalview.schemes.AnnotationColourGradient;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
 import jalview.util.MessageManager;
 
 import java.awt.Checkbox;
@@ -60,9 +61,9 @@ public class FeatureColourChooser extends Panel implements ActionListener,
 
   // AlignmentPanel ap;
 
-  GraduatedColor cs;
+  FeatureColourI cs;
 
-  Object oldcs;
+  FeatureColourI oldcs;
 
   Hashtable oldgroupColours;
 
@@ -91,29 +92,29 @@ public class FeatureColourChooser extends Panel implements ActionListener,
   {
     this.type = type;
     fr = frenderer;
-    float mm[] = ((float[][]) fr.getMinMax().get(type))[0];
+    float mm[] = fr.getMinMax().get(type)[0];
     min = mm[0];
     max = mm[1];
     oldcs = fr.getFeatureColours().get(type);
-    if (oldcs instanceof GraduatedColor)
+    if (oldcs.isGraduatedColour())
     {
-      cs = new GraduatedColor((GraduatedColor) oldcs, min, max);
+      cs = new FeatureColour((FeatureColour) oldcs, min, max);
     }
     else
     {
       // promote original color to a graduated color
       Color bl = Color.black;
-      if (oldcs instanceof Color)
+      if (oldcs.isSimpleColour())
       {
-        bl = (Color) oldcs;
+        bl = oldcs.getColour();
       }
       // original colour becomes the maximum colour
-      cs = new GraduatedColor(Color.white, bl, mm[0], mm[1]);
+      cs = new FeatureColour(Color.white, bl, mm[0], mm[1]);
     }
-    minColour.setBackground(cs.getMinColor());
-    maxColour.setBackground(cs.getMaxColor());
-    minColour.setForeground(cs.getMinColor());
-    maxColour.setForeground(cs.getMaxColor());
+    minColour.setBackground(cs.getMinColour());
+    maxColour.setBackground(cs.getMaxColour());
+    minColour.setForeground(cs.getMinColour());
+    maxColour.setForeground(cs.getMaxColour());
     colourFromLabel.setState(cs.isColourByLabel());
     adjusting = true;
 
@@ -123,10 +124,8 @@ public class FeatureColourChooser extends Panel implements ActionListener,
     } catch (Exception ex)
     {
     }
-    threshold
-            .select(cs.getThreshType() == AnnotationColourGradient.NO_THRESHOLD ? 0
-                    : cs.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD ? 1
-                            : 2);
+    threshold.select(cs.isAboveThreshold() ? 1 : (cs.isBelowThreshold() ? 2
+            : 0));
 
     adjusting = false;
     changeColour();
@@ -259,6 +258,7 @@ public class FeatureColourChooser extends Panel implements ActionListener,
 
   private GraphLine threshline;
 
+  @Override
   public void actionPerformed(ActionEvent evt)
   {
     if (evt.getSource() == thresholdValue)
@@ -286,6 +286,7 @@ public class FeatureColourChooser extends Panel implements ActionListener,
     }
   }
 
+  @Override
   public void itemStateChanged(ItemEvent evt)
   {
     maxColour.setEnabled(!colourFromLabel.getState());
@@ -293,19 +294,20 @@ public class FeatureColourChooser extends Panel implements ActionListener,
     changeColour();
   }
 
+  @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
     if (!adjusting)
     {
-      thresholdValue.setText(((float) slider.getValue() / 1000f) + "");
+      thresholdValue.setText((slider.getValue() / 1000f) + "");
       valueChanged();
     }
   }
 
   protected void valueChanged()
   {
-    threshline.value = (float) slider.getValue() / 1000f;
-    cs.setThresh(threshline.value);
+    threshline.value = slider.getValue() / 1000f;
+    cs.setThreshold(threshline.value);
     changeColour();
     PaintRefresher.Refresh(this, fr.getViewport().getSequenceSetId());
     // ap.paintAlignment(false);
@@ -369,7 +371,7 @@ public class FeatureColourChooser extends Panel implements ActionListener,
 
     slider.setEnabled(true);
     thresholdValue.setEnabled(true);
-    GraduatedColor acg = new GraduatedColor(minColour.getBackground(),
+    FeatureColour acg = new FeatureColour(minColour.getBackground(),
             maxColour.getBackground(), min, max);
 
     acg.setColourByLabel(colourFromLabel.getState());
@@ -393,7 +395,7 @@ public class FeatureColourChooser extends Panel implements ActionListener,
     if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
     {
       adjusting = true;
-      acg.setThresh(threshline.value);
+      acg.setThreshold(threshline.value);
 
       float range = max * 1000f - min * 1000f;
 
@@ -406,17 +408,17 @@ public class FeatureColourChooser extends Panel implements ActionListener,
       adjusting = false;
     }
 
-    acg.setThreshType(aboveThreshold);
+    acg.setAboveThreshold(true);
     if (thresholdIsMin.getState()
             && aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
     {
       if (aboveThreshold == AnnotationColourGradient.ABOVE_THRESHOLD)
       {
-        acg = new GraduatedColor(acg, threshline.value, max);
+        acg = new FeatureColour(acg, threshline.value, max);
       }
       else
       {
-        acg = new GraduatedColor(acg, min, threshline.value);
+        acg = new FeatureColour(acg, min, threshline.value);
       }
     }
 
@@ -434,14 +436,17 @@ public class FeatureColourChooser extends Panel implements ActionListener,
 
   }
 
+  @Override
   public void mouseClicked(MouseEvent evt)
   {
   }
 
+  @Override
   public void mousePressed(MouseEvent evt)
   {
   }
 
+  @Override
   public void mouseReleased(MouseEvent evt)
   {
     if (evt.getSource() == minColour || evt.getSource() == maxColour)
@@ -456,10 +461,12 @@ public class FeatureColourChooser extends Panel implements ActionListener,
     // ap.paintAlignment(true);
   }
 
+  @Override
   public void mouseEntered(MouseEvent evt)
   {
   }
 
+  @Override
   public void mouseExited(MouseEvent evt)
   {
   }
index 4391fa2..3f87549 100644 (file)
  */
 package jalview.appletgui;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
-import jalview.schemes.AnnotationColourGradient;
-import jalview.schemes.GraduatedColor;
+import jalview.io.FeaturesFile;
+import jalview.schemes.FeatureColour;
+import jalview.schemes.UserColourScheme;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 
@@ -43,6 +45,9 @@ import java.awt.TextArea;
 import java.awt.TextField;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Hashtable;
 
 /**
  * DOCUMENT ME!
@@ -53,19 +58,20 @@ import java.awt.event.ActionListener;
 public class FeatureRenderer extends
         jalview.renderer.seqfeatures.FeatureRenderer
 {
+
+  // Holds web links for feature groups and feature types
+  // in the form label|link
+  Hashtable featureLinks = null;
+
   /**
    * Creates a new FeatureRenderer object.
    * 
    * @param av
-   *          DOCUMENT ME!
    */
   public FeatureRenderer(AlignmentViewport av)
   {
     super();
     this.av = av;
-
-    setTransparencyAvailable(!System.getProperty("java.version")
-            .startsWith("1.1"));
   }
 
   static String lastFeatureAdded;
@@ -91,51 +97,35 @@ public class FeatureRenderer extends
     /**
      * render a feature style in the amend feature dialog box
      */
-    public void updateColor(Object newcol)
+    public void updateColor(FeatureColourI newcol)
     {
-
-      Color bg, col = null;
-      GraduatedColor gcol = null;
+      Color bg = null;
       String vlabel = "";
-      if (newcol instanceof Color)
-      {
-        isGcol = false;
-        col = (Color) newcol;
-        gcol = null;
-      }
-      else if (newcol instanceof GraduatedColor)
-      {
-        isGcol = true;
-        gcol = (GraduatedColor) newcol;
-        col = null;
-      }
-      else
-      {
-        throw new Error(
-                MessageManager
-                        .getString("error.invalid_colour_for_mycheckbox"));
-      }
-      if (col != null)
+      if (newcol.isSimpleColour())
       {
-        setBackground(bg = col);
+        bg = newcol.getColour();
+        setBackground(bg);
       }
       else
       {
-        if (gcol.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
+        if (newcol.isAboveThreshold())
+        {
+          vlabel += " (>)";
+        }
+        else if (newcol.isBelowThreshold())
         {
-          vlabel += " "
-                  + ((gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD) ? "(>)"
-                          : "(<)");
+          vlabel += " (<)";
         }
-        if (isColourByLabel = gcol.isColourByLabel())
+
+        if (isColourByLabel = newcol.isColourByLabel())
         {
           setBackground(bg = Color.white);
           vlabel += " (by Label)";
         }
         else
         {
-          setBackground(bg = gcol.getMinColor());
-          maxCol = gcol.getMaxColor();
+          setBackground(bg = newcol.getMinColour());
+          maxCol = newcol.getMaxColour();
         }
       }
       label = vlabel;
@@ -242,11 +232,12 @@ public class FeatureRenderer extends
             ap.seqPanel.seqCanvas.highlightSearchResults(highlight);
 
           }
-          Object col = getFeatureStyle(name.getText());
+          FeatureColourI col = getFeatureStyle(name.getText());
           if (col == null)
           {
-            col = new jalview.schemes.UserColourScheme()
+            Color generatedColour = UserColourScheme
                     .createColourFromName(name.getText());
+            col = new FeatureColour(generatedColour);
           }
 
           colourPanel.updateColor(col);
@@ -354,21 +345,16 @@ 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());
+    // lookup (or generate) the feature colour
+    FeatureColourI fcol = getFeatureStyle(name.getText());
     // simply display the feature color in a box
     colourPanel.updateColor(fcol);
     dialog.setResizable(true);
     // TODO: render the graduated color in the box.
-    colourPanel.addMouseListener(new java.awt.event.MouseAdapter()
+    colourPanel.addMouseListener(new MouseAdapter()
     {
       @Override
-      public void mousePressed(java.awt.event.MouseEvent evt)
+      public void mousePressed(MouseEvent evt)
       {
         if (!colourPanel.isGcol)
         {
@@ -376,15 +362,14 @@ public class FeatureRenderer extends
         }
         else
         {
-          FeatureColourChooser fcc = new FeatureColourChooser(
-                  ap.alignFrame, name.getText());
+          new FeatureColourChooser(ap.alignFrame, name.getText());
           dialog.transferFocus();
         }
       }
     });
     dialog.setVisible(true);
 
-    jalview.io.FeaturesFile ffile = new jalview.io.FeaturesFile();
+    FeaturesFile ffile = new FeaturesFile();
 
     if (dialog.accept)
     {
@@ -413,7 +398,7 @@ public class FeatureRenderer extends
         if (!colourPanel.isGcol)
         {
           // update colour - otherwise its already done.
-          setColour(sf.type, colourPanel.getBackground());
+          setColour(sf.type, new FeatureColour(colourPanel.getBackground()));
         }
         try
         {
@@ -453,7 +438,7 @@ public class FeatureRenderer extends
         {
           setGroupVisibility(lastFeatureGroupAdded, true);
         }
-        setColour(lastFeatureAdded, newColour); // was fcol
+        setColour(lastFeatureAdded, new FeatureColour(newColour)); // was fcol
         setVisible(lastFeatureAdded);
         findAllFeatures(false); // different to original applet behaviour ?
         // findAllFeatures();
index 40a2ce5..bfac241 100755 (executable)
  */
 package jalview.appletgui;
 
+import jalview.api.FeatureColourI;
 import jalview.api.FeatureSettingsControllerI;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceFeature;
-import jalview.schemes.AnnotationColourGradient;
-import jalview.schemes.GraduatedColor;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
@@ -95,14 +94,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 +126,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);
 
@@ -206,8 +189,8 @@ public class FeatureSettings extends Panel implements ItemListener,
           int x, int y)
   {
     final String type = check.type;
-    final Object typeCol = fr.getFeatureStyle(type);
-    java.awt.PopupMenu men = new PopupMenu(MessageManager.formatMessage(
+    final FeatureColourI typeCol = fr.getFeatureStyle(type);
+    PopupMenu men = new PopupMenu(MessageManager.formatMessage(
             "label.settings_for_type", new String[] { type }));
     java.awt.MenuItem scr = new MenuItem(
             MessageManager.getString("label.sort_by_score"));
@@ -238,6 +221,7 @@ public class FeatureSettings extends Panel implements ItemListener,
 
     });
     men.add(dens);
+
     if (minmax != null)
     {
       final float[][] typeMinMax = minmax.get(type);
@@ -258,7 +242,7 @@ public class FeatureSettings extends Panel implements ItemListener,
         // graduated colourschemes for those where minmax exists for the
         // positional features
         MenuItem mxcol = new MenuItem(
-                (typeCol instanceof Color) ? "Graduated Colour"
+                (typeCol.isSimpleColour()) ? "Graduated Colour"
                         : "Single Colour");
         men.add(mxcol);
         mxcol.addActionListener(new ActionListener()
@@ -267,7 +251,7 @@ public class FeatureSettings extends Panel implements ItemListener,
           @Override
           public void actionPerformed(ActionEvent e)
           {
-            if (typeCol instanceof Color)
+            if (typeCol.isSimpleColour())
             {
               new FeatureColourChooser(me, type);
               // write back the current colour object to update the table
@@ -275,14 +259,64 @@ public class FeatureSettings extends Panel implements ItemListener,
             }
             else
             {
-              new UserDefinedColours(me, check.type,
-                      ((GraduatedColor) typeCol));
+              new UserDefinedColours(me, check.type, typeCol);
             }
           }
 
         });
       }
     }
+
+    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);
   }
@@ -601,19 +635,9 @@ public class FeatureSettings extends Panel implements ItemListener,
     }
   }
 
-  public void setUserColour(String feature, Object originalColour)
+  public void setUserColour(String feature, FeatureColourI originalColour)
   {
-    if (originalColour instanceof Color
-            || originalColour instanceof GraduatedColor)
-    {
-      fr.setColour(feature, originalColour);
-    }
-    else
-    {
-      throw new Error(
-              MessageManager
-                      .getString("error.implementation_error_unsupported_feature_colour_object"));
-    }
+    fr.setColour(feature, originalColour);
     refreshTable();
   }
 
@@ -650,10 +674,10 @@ public class FeatureSettings extends Panel implements ItemListener,
 
     if (evt.getClickCount() > 1)
     {
-      Object fcol = fr.getFeatureStyle(check.type);
-      if (fcol instanceof Color)
+      FeatureColourI fcol = fr.getFeatureStyle(check.type);
+      if (fcol.isSimpleColour())
       {
-        new UserDefinedColours(this, check.type, (Color) fcol);
+        new UserDefinedColours(this, check.type, fcol.getColour());
       }
       else
       {
@@ -685,49 +709,34 @@ public class FeatureSettings extends Panel implements ItemListener,
 
     boolean hasLink;
 
-    GraduatedColor gcol;
+    FeatureColourI col;
 
-    Color col;
-
-    public void updateColor(Object newcol)
+    public void updateColor(FeatureColourI newcol)
     {
-      if (newcol instanceof Color)
+      col = newcol;
+      if (col.isSimpleColour())
       {
-        col = (Color) newcol;
-        gcol = null;
-      }
-      else if (newcol instanceof GraduatedColor)
-      {
-        gcol = (GraduatedColor) newcol;
-        col = null;
-      }
-      else
-      {
-        throw new Error(
-                MessageManager
-                        .getString("error.invalid_colour_for_mycheckbox"));
-      }
-      if (col != null)
-      {
-        setBackground(col);
+        setBackground(col.getColour());
       }
       else
       {
         String vlabel = type;
-        if (gcol.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
+        if (col.isAboveThreshold())
+        {
+          vlabel += " (>)";
+        }
+        else if (col.isBelowThreshold())
         {
-          vlabel += " "
-                  + ((gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD) ? "(>)"
-                          : "(<)");
+          vlabel += " (<)";
         }
-        if (gcol.isColourByLabel())
+        if (col.isColourByLabel())
         {
           setBackground(Color.white);
           vlabel += " (by Label)";
         }
         else
         {
-          setBackground(gcol.getMinColor());
+          setBackground(col.getMinColour());
         }
         this.setLabel(vlabel);
       }
@@ -744,7 +753,7 @@ public class FeatureSettings extends Panel implements ItemListener,
     }
 
     public MyCheckbox(String type, boolean selected, boolean b,
-            Object featureStyle)
+            FeatureColourI featureStyle)
     {
       this(type, selected, b);
       updateColor(featureStyle);
@@ -754,31 +763,28 @@ public class FeatureSettings extends Panel implements ItemListener,
     public void paint(Graphics g)
     {
       Dimension d = getSize();
-      if (gcol != null)
+      if (col.isColourByLabel())
       {
-        if (gcol.isColourByLabel())
-        {
-          g.setColor(Color.white);
-          g.fillRect(d.width / 2, 0, d.width / 2, d.height);
-          /*
-           * g.setColor(Color.black); Font f=g.getFont().deriveFont(9);
-           * g.setFont(f);
-           * 
-           * // g.setFont(g.getFont().deriveFont( //
-           * AffineTransform.getScaleInstance( //
-           * width/g.getFontMetrics().stringWidth("Label"), //
-           * height/g.getFontMetrics().getHeight()))); g.drawString("Label",
-           * width/2, 0);
-           */
+        g.setColor(Color.white);
+        g.fillRect(d.width / 2, 0, d.width / 2, d.height);
+        /*
+         * g.setColor(Color.black); Font f=g.getFont().deriveFont(9);
+         * g.setFont(f);
+         * 
+         * // g.setFont(g.getFont().deriveFont( //
+         * AffineTransform.getScaleInstance( //
+         * width/g.getFontMetrics().stringWidth("Label"), //
+         * height/g.getFontMetrics().getHeight()))); g.drawString("Label",
+         * width/2, 0);
+         */
 
-        }
-        else
-        {
-          Color maxCol = gcol.getMaxColor();
-          g.setColor(maxCol);
-          g.fillRect(d.width / 2, 0, d.width / 2, d.height);
+      }
+      else if (col.isGraduatedColour())
+      {
+        Color maxCol = col.getMaxColour();
+        g.setColor(maxCol);
+        g.fillRect(d.width / 2, 0, d.width / 2, d.height);
 
-        }
       }
 
       if (hasLink)
@@ -789,9 +795,31 @@ 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();
+      }
+    }
+  }
+
   @Override
   public void mousePressed(MouseEvent e)
   {
+    // TODO Auto-generated method stub
+
   }
 
 }
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();
index 09b50c4..970d20e 100755 (executable)
@@ -32,6 +32,8 @@ import java.awt.Graphics;
 
 public class SequenceRenderer implements jalview.api.SequenceRenderer
 {
+  final static int CHAR_TO_UPPER = 'A' - 'a';
+
   AlignViewport av;
 
   FontMetrics fm;
@@ -67,6 +69,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
     this.renderGaps = renderGaps;
   }
 
+  @Override
   public Color getResidueBoxColour(SequenceI seq, int i)
   {
     allGroups = av.getAlignment().findAllGroups(seq);
@@ -256,7 +259,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
         }
         if (currentSequenceGroup.getShowNonconserved())
         {
-          s = getDisplayChar(srep, i, s, '.');
+          s = getDisplayChar(srep, i, s, '.', currentSequenceGroup);
         }
       }
       else
@@ -280,7 +283,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
         }
         if (av.getShowUnconserved())
         {
-          s = getDisplayChar(srep, i, s, '.');
+          s = getDisplayChar(srep, i, s, '.', null);
 
         }
       }
@@ -312,20 +315,43 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
 
   }
 
-  private char getDisplayChar(final boolean usesrep, int position, char s,
-          char c)
+  /**
+   * Returns 'conservedChar' to represent the given position if the sequence
+   * character at that position is equal to the consensus (ignoring case), else
+   * returns the sequence character
+   * 
+   * @param usesrep
+   * @param position
+   * @param sequenceChar
+   * @param conservedChar
+   * @return
+   */
+  private char getDisplayChar(final boolean usesrep, int position,
+          char sequenceChar, char conservedChar, SequenceGroup currentGroup)
   {
     // TODO - use currentSequenceGroup rather than alignment
     // currentSequenceGroup.getConsensus()
-    char conschar = (usesrep) ? av.getAlignment().getSeqrep()
-            .getCharAt(position)
-            : av.getAlignmentConsensusAnnotation().annotations[position].displayCharacter
-                    .charAt(0);
-    if (!jalview.util.Comparison.isGap(conschar) && s == conschar)
+    char conschar = (usesrep) ? (currentGroup == null
+            || position < currentGroup.getStartRes()
+            || position > currentGroup.getEndRes() ? av.getAlignment()
+            .getSeqrep().getCharAt(position)
+            : (currentGroup.getSeqrep() != null ? currentGroup.getSeqrep()
+                    .getCharAt(position) : av.getAlignment().getSeqrep()
+                    .getCharAt(position)))
+            : (currentGroup != null && currentGroup.getConsensus() != null
+                    && position >= currentGroup.getStartRes()
+                    && position <= currentGroup.getEndRes() && currentGroup
+                    .getConsensus().annotations.length > position) ? currentGroup
+                    .getConsensus().annotations[position].displayCharacter
+                    .charAt(0)
+                    : av.getAlignmentConsensusAnnotation().annotations[position].displayCharacter
+                            .charAt(0);
+    if (!jalview.util.Comparison.isGap(conschar)
+            && (sequenceChar == conschar || sequenceChar + CHAR_TO_UPPER == conschar))
     {
-      s = c;
+      sequenceChar = conservedChar;
     }
-    return s;
+    return sequenceChar;
   }
 
   boolean inCurrentSequenceGroup(int res)
index 57cf669..88098a9 100644 (file)
  */
 package jalview.appletgui;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.SequenceGroup;
 import jalview.schemes.ColourSchemeI;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
 import jalview.schemes.ResidueProperties;
 import jalview.schemes.UserColourScheme;
 import jalview.util.MessageManager;
@@ -59,7 +60,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
 
   Button selectedButton;
 
-  Vector oldColours = new Vector();
+  Vector<Color> oldColours = new Vector<Color>();
 
   ColourSchemeI oldColourScheme;
 
@@ -75,7 +76,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
 
   String originalLabel;
 
-  Object originalColour;
+  FeatureColourI originalColour;
 
   int R = 0, G = 0, B = 0;
 
@@ -117,7 +118,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
   public UserDefinedColours(FeatureRenderer fr, Frame alignframe)
   {
     caller = fr;
-    originalColour = fr.colourPanel.getBackground();
+    originalColour = new FeatureColour(fr.colourPanel.getBackground());
     originalLabel = "Feature Colour";
     setForDialog("Select Feature Colour", alignframe);
     setTargetColour(fr.colourPanel.getBackground());
@@ -134,21 +135,21 @@ public class UserDefinedColours extends Panel implements ActionListener,
    * 
    * @param caller
    *          - handles events
-   * @param col1
+   * @param col
    *          - original colour
    * @param alignframe
    *          - the parent Frame for the dialog
    * @param title
    *          - window title
    */
-  public UserDefinedColours(Component caller, Color col1, Frame alignframe,
+  public UserDefinedColours(Component caller, Color col, Frame alignframe,
           String title)
   {
     this.caller = caller;
-    originalColour = col1;
+    originalColour = new FeatureColour(col);
     originalLabel = title;
     setForDialog(title, alignframe);
-    setTargetColour(col1);
+    setTargetColour(col);
     dialog.setVisible(true);
   }
 
@@ -161,7 +162,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
    */
   public UserDefinedColours(Object caller, String label, Color colour)
   {
-    this(caller, label, colour, colour);
+    this(caller, label, new FeatureColour(colour), colour);
   }
 
   /**
@@ -172,13 +173,13 @@ public class UserDefinedColours extends Panel implements ActionListener,
    * @param graduatedColor
    */
   public UserDefinedColours(FeatureSettings me, String type,
-          GraduatedColor graduatedColor)
+          FeatureColourI graduatedColor)
   {
-    this(me, type, graduatedColor, graduatedColor.getMaxColor());
+    this(me, type, graduatedColor, graduatedColor.getMaxColour());
   }
 
-  private UserDefinedColours(Object caller, String label, Object ocolour,
-          Color colour)
+  private UserDefinedColours(Object caller, String label,
+          FeatureColourI ocolour, Color colour)
   {
     this.caller = caller;
     originalColour = ocolour;
@@ -228,6 +229,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
 
   }
 
+  @Override
   public void actionPerformed(ActionEvent evt)
   {
     final Object source = evt.getSource();
@@ -257,6 +259,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
     }
   }
 
+  @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
     if (evt.getSource() == rScroller)
@@ -420,6 +423,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
     button.setFont(new java.awt.Font("Verdana", 1, 10));
     button.addMouseListener(new java.awt.event.MouseAdapter()
     {
+      @Override
       public void mousePressed(MouseEvent e)
       {
         colourButtonPressed(e);
@@ -451,7 +455,8 @@ public class UserDefinedColours extends Panel implements ActionListener,
     {
       if (caller instanceof FeatureSettings)
       {
-        ((FeatureSettings) caller).setUserColour(originalLabel, getColor());
+        ((FeatureSettings) caller).setUserColour(originalLabel,
+                new FeatureColour(getColor()));
       }
       else if (caller instanceof AnnotationColourChooser)
       {
@@ -468,7 +473,8 @@ public class UserDefinedColours extends Panel implements ActionListener,
       }
       else if (caller instanceof FeatureRenderer)
       {
-        ((FeatureRenderer) caller).colourPanel.updateColor(getColor());
+        ((FeatureRenderer) caller).colourPanel
+                .updateColor(new FeatureColour(getColor()));
       }
       else if (caller instanceof FeatureColourChooser)
       {
@@ -537,12 +543,12 @@ public class UserDefinedColours extends Panel implements ActionListener,
         if (originalLabel.equals("Min Colour"))
         {
           ((AnnotationColourChooser) caller)
-                  .minColour_actionPerformed((Color) originalColour);
+                  .minColour_actionPerformed(originalColour.getColour());
         }
         else
         {
           ((AnnotationColourChooser) caller)
-                  .maxColour_actionPerformed((Color) originalColour);
+                  .maxColour_actionPerformed(originalColour.getColour());
         }
       }
       else if (caller instanceof FeatureRenderer)
@@ -556,12 +562,12 @@ public class UserDefinedColours extends Panel implements ActionListener,
         if (originalLabel.indexOf("inimum") > -1)
         {
           ((FeatureColourChooser) caller)
-                  .minColour_actionPerformed((Color) originalColour);
+                  .minColour_actionPerformed(originalColour.getColour());
         }
         else
         {
           ((FeatureColourChooser) caller)
-                  .maxColour_actionPerformed((Color) originalColour);
+                  .maxColour_actionPerformed(originalColour.getColour());
         }
       }
       if (dialog != null)
@@ -576,7 +582,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
     Color[] newColours = new Color[24];
     for (int i = 0; i < 24; i++)
     {
-      newColours[i] = (Color) oldColours.elementAt(i);
+      newColours[i] = oldColours.elementAt(i);
       buttonPanel.getComponent(i).setBackground(newColours[i]);
     }
 
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 6c8750f..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;
@@ -62,6 +71,15 @@ import javax.swing.UIManager;
  */
 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
@@ -83,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
@@ -90,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") + " "
@@ -162,7 +255,7 @@ public class Jalview
     try
     {
       Cache.initLogger();
-    } catch (java.lang.NoClassDefFoundError error)
+    } catch (NoClassDefFoundError error)
     {
       error.printStackTrace();
       System.out
@@ -171,7 +264,7 @@ public class Jalview
       System.exit(0);
     }
 
-    Desktop desktop = null;
+    desktop = null;
 
     try
     {
@@ -252,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
@@ -267,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)
@@ -283,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));
           }
@@ -366,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)
@@ -376,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);
@@ -388,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;
           }
@@ -417,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!");
@@ -426,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!");
@@ -474,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(
@@ -516,7 +609,7 @@ public class Jalview
           // Execute the groovy script after we've done all the rendering stuff
           // and before any images or figures are generated.
           System.out.println("Executing script " + groovyscript);
-          executeGroovyScript(groovyscript, new Object[] { desktop, af });
+          executeGroovyScript(groovyscript, af);
           System.out.println("CMD groovy[" + groovyscript
                   + "] executed successfully!");
           groovyscript = null;
@@ -529,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);
@@ -544,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);
@@ -618,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,
@@ -640,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
       {
@@ -711,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 "
@@ -748,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
      */
@@ -772,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)
         {
@@ -837,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
@@ -913,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();
-    }
   }
 
   /**
@@ -926,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)
@@ -965,7 +992,7 @@ public class Jalview
                         + nickname + "|" + url);
         if (source == null)
         {
-          source = new Vector();
+          source = new Vector<String>();
         }
         source.addElement(nickname);
       }
@@ -983,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);
     }
@@ -995,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();
@@ -1019,176 +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
-{
-  @Override
-  public void actionPerformed(ActionEvent arg0)
-  {
-    System.out.println("Good idea ! ");
-
-  }
-}
-
-class pbuttonlistener implements ActionListener
-{
-  @Override
-  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)
+  public AlignFrame[] getAlignFrames()
   {
-    return getValue(arg, false);
-  }
+    return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
+            : Desktop.getAlignFrames();
 
-  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()
-    {
-
-      @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;
-  }
-
 }
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 e3a8472..aaf70b8 100644 (file)
@@ -32,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
   {
     /*
@@ -205,9 +209,26 @@ 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
@@ -223,7 +244,7 @@ public class ColumnSelection
    */
   public void addElement(int col)
   {
-    selected.add(col);
+    selection.add(col);
   }
 
   /**
@@ -231,7 +252,7 @@ public class ColumnSelection
    */
   public void clear()
   {
-    selected.clear();
+    selection.clear();
   }
 
   /**
@@ -242,7 +263,7 @@ public class ColumnSelection
    */
   public void removeElement(int col)
   {
-    selected.remove(col);
+    selection.remove(col);
   }
 
   /**
@@ -259,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);
       }
     }
   }
@@ -273,7 +294,7 @@ public class ColumnSelection
    */
   public List<Integer> getSelected()
   {
-    return selected.getList();
+    return selection.getList();
   }
 
   /**
@@ -282,7 +303,7 @@ public class ColumnSelection
    */
   public List<int[]> getSelectedRanges()
   {
-    return selected.getRanges();
+    return selection.getRanges();
   }
 
   /**
@@ -294,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;
   }
 
   /**
@@ -302,7 +323,7 @@ public class ColumnSelection
    */
   public boolean isEmpty()
   {
-    return selected == null || selected.isEmpty();
+    return selection == null || selection.isEmpty();
   }
 
   /**
@@ -312,11 +333,11 @@ public class ColumnSelection
    */
   public int getMax()
   {
-    if (selected.isEmpty())
+    if (selection.isEmpty())
     {
       return -1;
     }
-    return selected.getMaxColumn();
+    return selection.getMaxColumn();
   }
 
   /**
@@ -326,11 +347,11 @@ public class ColumnSelection
    */
   public int getMin()
   {
-    if (selected.isEmpty())
+    if (selection.isEmpty())
     {
       return 1000000000;
     }
-    return selected.getMinColumn();
+    return selection.getMinColumn();
   }
 
   /**
@@ -344,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)
     {
@@ -394,7 +415,7 @@ public class ColumnSelection
   private void compensateForDelEdits(int start, int change)
   {
 
-    selected.compensateForEdits(start, change);
+    selection.compensateForEdits(start, change);
 
     if (hiddenColumns != null)
     {
@@ -571,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.
@@ -600,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)
@@ -743,13 +764,13 @@ public class ColumnSelection
 
   public void hideSelectedColumns()
   {
-    synchronized (selected)
+    synchronized (selection)
     {
-      for (int[] selregions : selected.getRanges())
+      for (int[] selregions : selection.getRanges())
       {
         hideColumns(selregions[0], selregions[1]);
       }
-      selected.clear();
+      selection.clear();
     }
 
   }
@@ -927,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)
@@ -1307,7 +1328,7 @@ public class ColumnSelection
       {
         if (hiddenColumns != null && isVisible(col.intValue()))
         {
-          selected.add(col);
+          selection.add(col);
         }
       }
     }
@@ -1321,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)
       {
@@ -1489,7 +1510,7 @@ public class ColumnSelection
    */
   public boolean hasSelectedColumns()
   {
-    return (selected != null && selected.size() > 0);
+    return (selection != null && selection.size() > 0);
   }
 
   /**
@@ -1612,4 +1633,74 @@ public class ColumnSelection
     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 dcc5f26..8ca3c5a 100755 (executable)
@@ -33,11 +33,21 @@ public class HiddenSequences
 
   AlignmentI alignment;
 
+  /**
+   * Constructor given a reference to an alignment (with no hidden sequences)
+   * 
+   * @param al
+   */
   public HiddenSequences(AlignmentI al)
   {
     alignment = al;
   }
 
+  /**
+   * Answers the number of hidden sequences
+   * 
+   * @return
+   */
   public int getSize()
   {
     if (hiddenSequences == null)
@@ -45,9 +55,9 @@ public class HiddenSequences
       return 0;
     }
     int count = 0;
-    for (int i = 0; i < hiddenSequences.length; i++)
+    for (SequenceI seq : hiddenSequences)
     {
-      if (hiddenSequences[i] != null)
+      if (seq != null)
       {
         count++;
       }
@@ -56,15 +66,23 @@ public class HiddenSequences
     return count;
   }
 
+  /**
+   * Answers the length of the longest hidden sequence
+   * 
+   * @return
+   */
   public int getWidth()
   {
+    if (hiddenSequences == null)
+    {
+      return 0;
+    }
     int width = 0;
-    for (int i = 0; i < hiddenSequences.length; i++)
+    for (SequenceI seq : hiddenSequences)
     {
-      if (hiddenSequences[i] != null
-              && hiddenSequences[i].getLength() > width)
+      if (seq != null && seq.getLength() > width)
       {
-        width = hiddenSequences[i].getLength();
+        width = seq.getLength();
       }
     }
 
@@ -72,7 +90,7 @@ public class HiddenSequences
   }
 
   /**
-   * Call this method if sequences are removed from the main alignment
+   * Call this method after a sequence is removed from the main alignment
    */
   public void adjustHeightSequenceDeleted(int seqIndex)
   {
@@ -108,8 +126,7 @@ public class HiddenSequences
   }
 
   /**
-   * Call this method if sequences are added to or removed from the main
-   * alignment
+   * Call this method after a sequence is added to the main alignment
    */
   public void adjustHeightSequenceAdded()
   {
@@ -125,6 +142,11 @@ public class HiddenSequences
     hiddenSequences = tmp;
   }
 
+  /**
+   * Mark the specified sequence as hidden
+   * 
+   * @param sequence
+   */
   public void hideSequence(SequenceI sequence)
   {
     if (hiddenSequences == null)
@@ -163,6 +185,17 @@ public class HiddenSequences
     return revealedSeqs;
   }
 
+  /**
+   * Reveals (unhides) consecutive hidden sequences just above the given
+   * alignment index. The revealed sequences are selected (including their
+   * visible representative sequence if there was one and 'reveal' is being
+   * performed on it).
+   * 
+   * @param alignmentIndex
+   * @param hiddenRepSequences
+   *          a map of representative sequences to the sequences they represent
+   * @return
+   */
   public List<SequenceI> showSequence(int alignmentIndex,
           Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
   {
@@ -203,20 +236,22 @@ public class HiddenSequences
                     + " has been deleted whilst hidden");
           }
         }
-
       }
     }
-
     return revealedSeqs;
   }
 
   public SequenceI getHiddenSequence(int alignmentIndex)
   {
-    return hiddenSequences[alignmentIndex];
+    return hiddenSequences == null ? null : hiddenSequences[alignmentIndex];
   }
 
   public int findIndexWithoutHiddenSeqs(int alignmentIndex)
   {
+    if (hiddenSequences == null)
+    {
+      return alignmentIndex;
+    }
     int index = 0;
     int hiddenSeqs = 0;
     if (hiddenSequences.length <= alignmentIndex)
@@ -232,13 +267,16 @@ public class HiddenSequences
       }
       index++;
     }
-    ;
 
     return (alignmentIndex - hiddenSeqs);
   }
 
   public int adjustForHiddenSeqs(int alignmentIndex)
   {
+    if (hiddenSequences == null)
+    {
+      return alignmentIndex;
+    }
     int index = 0;
     int hSize = hiddenSequences.length;
     while (index <= alignmentIndex && index < hSize)
@@ -254,22 +292,36 @@ public class HiddenSequences
     return alignmentIndex;
   }
 
+  /**
+   * makes a copy of the alignment with hidden sequences included. Using the
+   * copy for anything other than simple output is not recommended. Note - this
+   * method DOES NOT USE THE AlignmentI COPY CONSTRUCTOR!
+   * @return
+   */
   public AlignmentI getFullAlignment()
   {
-    int isize = hiddenSequences.length;
-    SequenceI[] seq = new Sequence[isize];
-
-    int index = 0;
-    for (int i = 0; i < hiddenSequences.length; i++)
+    SequenceI[] seq;
+    if (hiddenSequences == null)
     {
-      if (hiddenSequences[i] != null)
-      {
-        seq[i] = hiddenSequences[i];
-      }
-      else
+      seq = alignment.getSequencesArray();
+    }
+    else
+    {
+      int isize = hiddenSequences.length;
+      seq = new Sequence[isize];
+
+      int index = 0;
+      for (int i = 0; i < hiddenSequences.length; i++)
       {
-        seq[i] = alignment.getSequenceAt(index);
-        index++;
+        if (hiddenSequences[i] != null)
+        {
+          seq[i] = hiddenSequences[i];
+        }
+        else
+        {
+          seq[i] = alignment.getSequenceAt(index);
+          index++;
+        }
       }
     }
     Alignment fAlignmt = new Alignment(seq);
@@ -277,6 +329,7 @@ public class HiddenSequences
     fAlignmt.alignmentProperties = alignment.getProperties();
     fAlignmt.groups = alignment.getGroups();
     fAlignmt.hasRNAStructure = alignment.hasRNAStructure();
+    fAlignmt.setSeqrep(alignment.getSeqrep());
 
     return fAlignmt;
   }
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 0e8fa17..d403d6e 100755 (executable)
@@ -894,6 +894,7 @@ public class SequenceGroup implements AnnotatedCollectionI
   /**
    * @return the representative sequence for this group
    */
+  @Override
   public SequenceI getSeqrep()
   {
     return seqrep;
@@ -906,6 +907,7 @@ public class SequenceGroup implements AnnotatedCollectionI
    * @param seqrep
    *          the seqrep to set (null means no sequence representative)
    */
+  @Override
   public void setSeqrep(SequenceI seqrep)
   {
     this.seqrep = seqrep;
@@ -915,6 +917,7 @@ public class SequenceGroup implements AnnotatedCollectionI
    * 
    * @return true if group has a sequence representative
    */
+  @Override
   public boolean hasSeqrep()
   {
     return seqrep != null;
@@ -1036,7 +1039,8 @@ public class SequenceGroup implements AnnotatedCollectionI
 
   /**
    * 
-   * @return automatically calculated consensus row
+   * @return automatically calculated consensus row note: the row is a stub if a
+   *         consensus calculation has not yet been performed on the group
    */
   public AlignmentAnnotation getConsensus()
   {
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 4dd1bba..b4d2783 100644 (file)
@@ -8,7 +8,7 @@ import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.io.gff.SequenceOntologyFactory;
 import jalview.io.gff.SequenceOntologyI;
-import jalview.schemes.FeatureColourAdapter;
+import jalview.schemes.FeatureColour;
 import jalview.schemes.FeatureSettingsAdapter;
 import jalview.util.MapList;
 
@@ -536,7 +536,7 @@ public class EnsemblGene extends EnsemblSeqProxy
       {
         if (so.isA(type, SequenceOntologyI.EXON))
         {
-          return new FeatureColourAdapter()
+          return new FeatureColour()
           {
             @Override
             public boolean isColourByLabel()
@@ -547,7 +547,7 @@ public class EnsemblGene extends EnsemblSeqProxy
         }
         if (so.isA(type, SequenceOntologyI.SEQUENCE_VARIANT))
         {
-          return new FeatureColourAdapter()
+          return new FeatureColour()
           {
 
             @Override
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 6a564f1..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,23 +80,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
    */
   public EnsemblRestClient(String d)
   {
-    domain = d;
-  }
-
-  /**
-   * Returns the domain name to query e.g. http://rest.ensembl.org or
-   * http://rest.ensemblgenomes.org
-   * 
-   * @return
-   */
-  String getDomain()
-  {
-    return domain;
-  }
-
-  void setDomain(String d)
-  {
-    domain = d;
+    setDomain(d);
   }
 
   /**
@@ -222,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",
@@ -284,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)
       {
@@ -300,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;
   }
 
   /**
@@ -378,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..2ccf118 100644 (file)
@@ -57,7 +57,6 @@ import org.jmol.api.JmolStatusListener;
 import org.jmol.api.JmolViewer;
 import org.jmol.c.CBK;
 import org.jmol.script.T;
-import org.jmol.viewer.JC;
 import org.jmol.viewer.Viewer;
 
 public abstract class JalviewJmolBinding extends AAStructureBindingModel
@@ -170,12 +169,9 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
   public void closeViewer()
   {
-    viewer.acm.setModeMouse(JC.MOUSE_NONE);
     // remove listeners for all structures in viewer
     getSsm().removeStructureViewerListener(this, this.getPdbFile());
-    // 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 7741d73..80990b4 100644 (file)
@@ -93,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
@@ -133,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
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 2f24a01..00a081b 100644 (file)
@@ -143,21 +143,62 @@ public abstract class FTSRestClient implements FTSRestClientI
               }
 
               @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
@@ -228,6 +269,7 @@ public abstract class FTSRestClient implements FTSRestClientI
                         && this.getGroup().equals(that.getGroup());
               }
 
+
             };
             dataColumns.add(dataCol);
 
@@ -325,7 +367,7 @@ public abstract class FTSRestClient implements FTSRestClientI
   }
 
   @Override
-  public Collection<FTSDataColumnI> getAllDefaulDisplayedDataColumns()
+  public Collection<FTSDataColumnI> getAllDefaultDisplayedFTSDataColumns()
   {
     if (defaulDisplayedDataColumns == null
             || defaulDisplayedDataColumns.isEmpty())
index 6cce2c4..8078d43 100644 (file)
@@ -107,7 +107,8 @@ public class FTSRestResponse
         {
           return String.class;
         }
-        return cols[columnIndex - colOffset].getDataColumnClass();
+        return cols[columnIndex - colOffset].getDataType()
+                .getDataTypeClass();
       }
 
     };
@@ -149,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 bc68667..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;
@@ -140,6 +142,11 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
 
   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;
@@ -341,7 +348,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     });
     btn_next_page.setEnabled(false);
     btn_next_page.setToolTipText(MessageManager
-            .getString("label.next_page_tooltop"));
+            .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()
@@ -366,7 +373,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
 
     btn_prev_page.setEnabled(false);
     btn_prev_page.setToolTipText(MessageManager
-            .getString("label.prev_page_tooltop"));
+            .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()
@@ -491,6 +498,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
                 if (!getTypedText().equalsIgnoreCase(lastSearchTerm))
                 {
                   searchAction(true);
+                  paginatorCart.clear();
                   lastSearchTerm = getTypedText();
                 }
               }
@@ -540,7 +548,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
           txt_search.setEnabled(false);
           cmb_searchTarget.setEnabled(false);
           previousWantedFields = getFTSRestClient()
-                  .getAllDefaulDisplayedDataColumns()
+                  .getAllDefaultDisplayedFTSDataColumns()
                   .toArray(new Object[0]);
         }
         if (sourceTabbedPane.getTitleAt(index).equals(searchTabTitle))
@@ -553,6 +561,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
           if (wantedFieldsUpdated())
           {
             searchAction(true);
+            paginatorCart.clear();
           }
           else
           {
@@ -639,7 +648,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     }
 
     return Arrays.equals(getFTSRestClient()
-            .getAllDefaulDisplayedDataColumns()
+            .getAllDefaultDisplayedFTSDataColumns()
             .toArray(new Object[0]), previousWantedFields) ? false
             : true;
 
@@ -647,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);
     }
@@ -824,6 +834,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
   @Override
   public void prevPageAction()
   {
+    updatePaginatorCart();
     if (offSet >= pageLimit)
     {
       offSet = offSet - pageLimit;
@@ -838,11 +849,73 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
   @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);
index 4f308e3..32c171e 100644 (file)
@@ -71,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);
 
@@ -107,7 +107,8 @@ public class PDBFTSPanel extends GFTSPanel
 
           long endTime = System.currentTimeMillis();
           totalResultSetCount = resultList.getNumberOfItemsFound();
-          resultSetCount = resultList.getSearchSummary().size();
+          resultSetCount = resultList.getSearchSummary() == null ? 0
+                  : resultList.getSearchSummary().size();
           String result = (resultSetCount > 0) ? MessageManager
                   .getString("label.results") : MessageManager
                   .getString("label.result");
@@ -115,9 +116,14 @@ public class PDBFTSPanel extends GFTSPanel
           if (isPaginationEnabled() && resultSetCount > 0)
           {
             updateSearchFrameTitle(defaultFTSFrameTitle + " - " + result
-                    + " " + (offSet + 1) + " to "
-                    + (offSet + resultSetCount) + " of "
-                    + totalResultSetCount
+                    + " "
+                    + totalNumberformatter.format((Number) (offSet + 1))
+                    + " to "
+                    + totalNumberformatter
+                            .format((Number) (offSet + resultSetCount))
+                    + " of "
+                    + totalNumberformatter
+                            .format((Number) totalResultSetCount)
                     + " " + " (" + (endTime - startTime) + " milli secs)");
           }
           else
@@ -129,6 +135,7 @@ public class PDBFTSPanel extends GFTSPanel
           
           setSearchInProgress(false);
           refreshPaginatorState();
+          updateSummaryTableSelections();
         }
       }
     }.start();
@@ -188,12 +195,17 @@ public class PDBFTSPanel extends GFTSPanel
       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));
     }
 
index 29450e8..219d6d6 100644 (file)
@@ -326,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();
@@ -389,6 +391,14 @@ public class PDBFTSRestClient extends FTSRestClient
     };
   }
 
+  private static String sanitiseData(String data)
+  {
+    String cleanData = data.replaceAll("\\[\"", "").replaceAll("\\]\"", "")
+            .replaceAll("\\[", "").replaceAll("\\]", "")
+            .replaceAll("\",\"", ", ").replaceAll("\"", "");
+    return cleanData;
+  }
+
   @Override
   public String getColumnDataConfigFileName()
   {
@@ -404,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 8a21ffb..5ee518b 100644 (file)
@@ -63,19 +63,20 @@ public class UniProtFTSRestClient extends FTSRestClient
               : 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();
+      }
 
-      String query = uniportRestRequest.getFieldToSearchBy()
-              .equalsIgnoreCase("Search All") ? uniportRestRequest
-              .getSearchTerm() : uniportRestRequest.getFieldToSearchBy()
-              + ":" + uniportRestRequest.getSearchTerm();
-
-      // + (uniportRestRequest.isAllowUnpublishedEntries() ? ""
-      // : " AND status:REL");
-      // System.out.println(">>>>> Query : " + query);
-      // System.out.println(">>>>> Columns : " + wantedFields);
-      // System.out.println(">>>>> Response size: " + responseSize
-      // + " offset : "
-      // + offSet);
       WebResource webResource = null;
       webResource = client.resource(UNIPROT_SEARCH_ENDPOINT)
               .queryParam("format", "tab")
@@ -99,10 +100,12 @@ public class UniProtFTSRestClient extends FTSRestClient
         throw new Exception(errorMessage);
 
       }
+      int xTotalResults = Integer.valueOf(clientResponse.getHeaders()
+              .get("X-Total-Results").get(0));
       clientResponse = null;
       client = null;
       return parseUniprotResponse(uniProtTabDelimittedResponseString,
-              uniportRestRequest);
+              uniportRestRequest, xTotalResults);
     } catch (Exception e)
     {
       String exceptionMsg = e.getMessage();
@@ -126,10 +129,21 @@ public class UniProtFTSRestClient extends FTSRestClient
     }
   }
 
+  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;
@@ -156,7 +170,7 @@ 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;
@@ -224,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)
           {
index acf2fb0..b1aa5f1 100644 (file)
@@ -74,7 +74,7 @@ public class UniprotFTSPanel extends GFTSPanel
                   .getSelectedItem()).getAltCode();
 
           wantedFields = UniProtFTSRestClient.getInstance()
-                  .getAllDefaulDisplayedDataColumns();
+                  .getAllDefaultDisplayedFTSDataColumns();
           String searchTerm = decodeSearchTerm(txt_search.getText(),
                   searchTarget);
 
@@ -109,15 +109,23 @@ public class UniprotFTSPanel extends GFTSPanel
           }
 
           long endTime = System.currentTimeMillis();
-          resultSetCount = resultList.getNumberOfItemsFound();
+          totalResultSetCount = resultList.getNumberOfItemsFound();
+          resultSetCount = resultList.getSearchSummary() == null ? 0
+                  : resultList.getSearchSummary().size();
           String result = (resultSetCount > 0) ? MessageManager
                   .getString("label.results") : MessageManager
                   .getString("label.result");
           if (isPaginationEnabled() && resultSetCount > 0)
           {
             updateSearchFrameTitle(defaultFTSFrameTitle + " - " + result
-                    + " " + (offSet + 1) + " to "
-                    + (offSet + resultSetCount)
+                    + " "
+                    + totalNumberformatter.format((Number) (offSet + 1))
+                    + " to "
+                    + totalNumberformatter
+                            .format((Number) (offSet + resultSetCount))
+                    + " of "
+                    + totalNumberformatter
+                            .format((Number) totalResultSetCount)
                     + " " + " (" + (endTime - startTime) + " milli secs)");
           }
           else
@@ -128,6 +136,7 @@ public class UniprotFTSPanel extends GFTSPanel
           }
           setSearchInProgress(false);
           refreshPaginatorState();
+          updateSummaryTableSelections();
         }
       }
     }.start();
@@ -190,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 8ec5366..133aab4 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;
@@ -473,7 +473,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       @Override
       public void focusGained(FocusEvent e)
       {
-        Desktop.setCurrentAlignFrame(AlignFrame.this);
+        Jalview.setCurrentAlignFrame(AlignFrame.this);
       }
     });
 
@@ -1313,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];
@@ -1324,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!
    * 
@@ -4681,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)
   {
@@ -4713,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
@@ -4747,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', 
@@ -4765,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());
@@ -4840,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(
@@ -4926,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;
@@ -5025,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();
@@ -5542,8 +5519,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 AlignFrame.this.setMenusForViewport();
               }
             });
-            dbRefFetcher
-                    .fetchDBRefs(false);
+            dbRefFetcher.fetchDBRefs(false);
           }
         }).start();
 
@@ -5984,8 +5960,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void setAnnotationsVisibility(boolean visible,
           boolean forSequences, boolean forAlignment)
   {
-    for (AlignmentAnnotation aa : alignPanel.getAlignment()
-            .getAlignmentAnnotation())
+    AlignmentAnnotation[] anns = alignPanel.getAlignment()
+            .getAlignmentAnnotation();
+    if (anns == null)
+    {
+      return;
+    }
+    for (AlignmentAnnotation aa : anns)
     {
       /*
        * don't display non-positional annotations on an alignment
@@ -6101,9 +6082,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());
@@ -6119,7 +6103,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   protected void runGroovy_actionPerformed()
   {
-    Desktop.setCurrentAlignFrame(this);
+    Jalview.setCurrentAlignFrame(this);
     groovy.ui.Console console = Desktop.getGroovyConsole();
     if (console != null)
     {
@@ -6142,6 +6126,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 26f0d95..814bfc3 100644 (file)
@@ -685,27 +685,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()][]);
   }
@@ -1105,6 +1120,7 @@ public class AlignViewport extends AlignmentViewport implements
    * 
    * @param featureSettings
    */
+  @Override
   public void applyFeaturesStyle(FeatureSettingsModelI featureSettings)
   {
     if (featureSettings == null)
index d688ddd..469e495 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.SequenceI;
 import jalview.io.AnnotationFile;
@@ -155,18 +156,25 @@ public class AnnotationExporter extends JPanel
             .getString("label.no_features_on_alignment");
     if (features)
     {
+      Map<String, FeatureColourI> displayedFeatureColours = ap
+              .getFeatureRenderer().getDisplayedFeatureCols();
       FeaturesFile formatter = new FeaturesFile();
       SequenceI[] sequences = ap.av.getAlignment().getSequencesArray();
-      Map<String, Object> featureColours = ap.getFeatureRenderer()
+      Map<String, FeatureColourI> featureColours = ap.getFeatureRenderer()
               .getDisplayedFeatureCols();
       boolean includeNonPositional = ap.av.isShowNPFeats();
       if (GFFFormat.isSelected())
       {
+        text = new FeaturesFile().printGffFormat(ap.av.getAlignment()
+                .getDataset().getSequencesArray(), displayedFeatureColours,
+                true, ap.av.isShowNPFeats());
         text = formatter.printGffFormat(sequences, featureColours, true,
                 includeNonPositional);
       }
       else
       {
+        text = new FeaturesFile().printJalviewFormat(ap.av.getAlignment()
+                .getDataset().getSequencesArray(), displayedFeatureColours, true, ap.av.isShowNPFeats()); // ap.av.featuresDisplayed);
         text = formatter.printJalviewFormat(sequences, featureColours,
                 true, includeNonPositional);
       }
index 68df498..e27b919 100755 (executable)
@@ -802,8 +802,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();
@@ -833,7 +870,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();
@@ -841,7 +879,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
               }
               else
               {
-                if (evt.isControlDown())
+                if (jalview.util.Platform.isControlDown(evt))
                 {
                   sg.addOrRemove(aa[selectedRow].sequenceRef, true);
                 }
@@ -861,9 +899,9 @@ 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();
           }
 
         }
index 7f36f7f..d54e553 100644 (file)
@@ -61,6 +61,7 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.FocusEvent;
 import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
@@ -82,6 +83,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Semaphore;
 
+import javax.swing.AbstractAction;
 import javax.swing.DefaultDesktopManager;
 import javax.swing.DesktopManager;
 import javax.swing.JButton;
@@ -96,6 +98,7 @@ import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.JProgressBar;
+import javax.swing.KeyStroke;
 import javax.swing.SwingUtilities;
 import javax.swing.event.HyperlinkEvent;
 import javax.swing.event.HyperlinkEvent.EventType;
@@ -169,8 +172,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;
@@ -952,53 +953,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;
     }
 
@@ -1218,6 +1181,13 @@ public class Desktop extends jalview.jbgui.GDesktop implements
       dialogExecutor.shutdownNow();
     }
     closeAll_actionPerformed(null);
+
+    if (groovyConsole != null)
+    {
+      // suppress a possible repeat prompt to save script
+      groovyConsole.setDirty(false);
+      groovyConsole.exit();
+    }
     System.exit(0);
   }
 
@@ -2409,7 +2379,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();
@@ -2505,50 +2475,79 @@ public class Desktop extends jalview.jbgui.GDesktop implements
    */
   void openGroovyConsole()
   {
-    groovyConsole = new groovy.ui.Console();
+    if (groovyConsole == null)
+    {
+      groovyConsole = new groovy.ui.Console();
+      groovyConsole.setVariable("Jalview", this);
+      groovyConsole.run();
 
-    /*
-     * bind groovy variable 'Jalview' to the Desktop object
-     */
-    groovyConsole.setVariable("Jalview", this);
+      /*
+       * We allow only one console at a time, so that AlignFrame menu option
+       * 'Calculate | Run Groovy script' is unambiguous.
+       * Disable 'Groovy Console', and enable 'Run script', when the console is 
+       * opened, and the reverse when it is closed
+       */
+      Window window = (Window) groovyConsole.getFrame();
+      window.addWindowListener(new WindowAdapter()
+      {
+        @Override
+        public void windowClosed(WindowEvent e)
+        {
+          /*
+           * rebind CMD-Q from Groovy Console to Jalview Quit
+           */
+          addQuitHandler();
+          enableExecuteGroovy(false);
+        }
+      });
+    }
 
     /*
-     * start the console
+     * show Groovy console window (after close and reopen)
      */
-    groovyConsole.run();
+    ((Window) groovyConsole.getFrame()).setVisible(true);
 
     /*
-     * Allow only one console at a time, so that the AlignFrame menu option
-     * 'Calculate | Run Groovy script' is unambiguous.
-     * Disable 'new console', and enable 'Run script', when the console is 
-     * opened, and the reverse when it is closed
+     * if we got this far, enable 'Run Groovy' in AlignFrame menus
+     * and disable opening a second console
      */
-    Window window = (Window) groovyConsole.getFrame();
-    window.addWindowListener(new WindowAdapter()
+    enableExecuteGroovy(true);
+  }
+
+  /**
+   * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
+   * binding when opened
+   */
+  protected void addQuitHandler()
+  {
+    getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+            KeyStroke.getKeyStroke(KeyEvent.VK_Q, Toolkit
+                    .getDefaultToolkit().getMenuShortcutKeyMask()),
+            "Quit");
+    getRootPane().getActionMap().put("Quit", new AbstractAction()
     {
       @Override
-      public void windowClosed(WindowEvent e)
+      public void actionPerformed(ActionEvent e)
       {
-        groovyShell.setEnabled(true);
-        enableExecuteGroovy(false);
+        quit();
       }
     });
-
-    /*
-     * if we got this far, enable 'Run Groovy' in AlignFrame menus
-     * and disable opening a second console
-     */
-    groovyShell.setEnabled(false);
-    enableExecuteGroovy(true);
   }
 
   /**
    * 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)
     {
@@ -3172,22 +3171,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 groovy.ui.Console 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 064d58b..79217ea 100644 (file)
@@ -20,9 +20,9 @@
  */
 package jalview.gui;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.GraphLine;
-import jalview.schemes.AnnotationColourGradient;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
@@ -33,7 +33,6 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
-import java.util.Hashtable;
 
 import javax.swing.BorderFactory;
 import javax.swing.JCheckBox;
@@ -52,16 +51,16 @@ public class FeatureColourChooser extends JalviewDialog
   // FeatureSettings fs;
   FeatureRenderer fr;
 
-  private GraduatedColor cs;
+  private FeatureColourI cs;
 
-  private Object oldcs;
+  private FeatureColourI oldcs;
 
   /**
    * 
    * @return the last colour setting selected by user - either oldcs (which may
    *         be a java.awt.Color) or the new GraduatedColor
    */
-  public Object getLastColour()
+  public FeatureColourI getLastColour()
   {
     if (cs == null)
     {
@@ -70,8 +69,6 @@ public class FeatureColourChooser extends JalviewDialog
     return cs;
   }
 
-  Hashtable oldgroupColours;
-
   AlignmentPanel ap;
 
   boolean adjusting = false;
@@ -127,7 +124,7 @@ public class FeatureColourChooser extends JalviewDialog
       }
     });
 
-    float mm[] = ((float[][]) fr.getMinMax().get(type))[0];
+    float mm[] = fr.getMinMax().get(type)[0];
     min = mm[0];
     max = mm[1];
 
@@ -139,32 +136,32 @@ public class FeatureColourChooser extends JalviewDialog
     scaleFactor = (max == min) ? 1f : 100f / (max - min);
 
     oldcs = fr.getFeatureColours().get(type);
-    if (oldcs instanceof GraduatedColor)
+    if (!oldcs.isSimpleColour())
     {
-      if (((GraduatedColor) oldcs).isAutoScale())
+      if (oldcs.isAutoScaled())
       {
         // update the scale
-        cs = new GraduatedColor((GraduatedColor) oldcs, min, max);
+        cs = new FeatureColour((FeatureColour) oldcs, min, max);
       }
       else
       {
-        cs = new GraduatedColor((GraduatedColor) oldcs);
+        cs = new FeatureColour((FeatureColour) oldcs);
       }
     }
     else
     {
       // promote original color to a graduated color
-      Color bl = Color.black;
-      if (oldcs instanceof Color)
+      Color bl = oldcs.getColour();
+      if (bl == null)
       {
-        bl = (Color) oldcs;
+        bl = Color.BLACK;
       }
       // original colour becomes the maximum colour
-      cs = new GraduatedColor(Color.white, bl, mm[0], mm[1]);
+      cs = new FeatureColour(Color.white, bl, mm[0], mm[1]);
       cs.setColourByLabel(false);
     }
-    minColour.setBackground(oldminColour = cs.getMinColor());
-    maxColour.setBackground(oldmaxColour = cs.getMaxColor());
+    minColour.setBackground(oldminColour = cs.getMinColour());
+    maxColour.setBackground(oldmaxColour = cs.getMaxColour());
     adjusting = true;
 
     try
@@ -174,18 +171,15 @@ public class FeatureColourChooser extends JalviewDialog
     {
     }
     // update the gui from threshold state
-    thresholdIsMin.setSelected(!cs.isAutoScale());
+    thresholdIsMin.setSelected(!cs.isAutoScaled());
     colourByLabel.setSelected(cs.isColourByLabel());
-    if (cs.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
+    if (cs.hasThreshold())
     {
       // initialise threshold slider and selector
-      threshold
-              .setSelectedIndex(cs.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD ? 1
-                      : 2);
+      threshold.setSelectedIndex(cs.isAboveThreshold() ? 1 : 2);
       slider.setEnabled(true);
       thresholdValue.setEnabled(true);
-      threshline = new jalview.datamodel.GraphLine((max - min) / 2f,
-              "Threshold", Color.black);
+      threshline = new GraphLine((max - min) / 2f, "Threshold", Color.black);
 
     }
 
@@ -395,50 +389,50 @@ public class FeatureColourChooser extends JalviewDialog
       return;
     }
 
-    int aboveThreshold = AnnotationColourGradient.NO_THRESHOLD;
+    boolean aboveThreshold = false;
+    boolean belowThreshold = false;
     if (threshold.getSelectedIndex() == 1)
     {
-      aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD;
+      aboveThreshold = true;
     }
     else if (threshold.getSelectedIndex() == 2)
     {
-      aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD;
+      belowThreshold = true;
     }
+    boolean hasThreshold = aboveThreshold || belowThreshold;
 
     slider.setEnabled(true);
     thresholdValue.setEnabled(true);
 
-    GraduatedColor acg;
+    FeatureColourI acg;
     if (cs.isColourByLabel())
     {
-      acg = new GraduatedColor(oldminColour, oldmaxColour, min, max);
+      acg = new FeatureColour(oldminColour, oldmaxColour, min, max);
     }
     else
     {
-      acg = new GraduatedColor(oldminColour = minColour.getBackground(),
+      acg = new FeatureColour(oldminColour = minColour.getBackground(),
               oldmaxColour = maxColour.getBackground(), min, max);
 
     }
 
-    if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
+    if (!hasThreshold)
     {
       slider.setEnabled(false);
       thresholdValue.setEnabled(false);
       thresholdValue.setText("");
       thresholdIsMin.setEnabled(false);
     }
-    else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD
-            && threshline == null)
+    else if (threshline == null)
     {
       // todo visual indication of feature threshold
-      threshline = new jalview.datamodel.GraphLine((max - min) / 2f,
-              "Threshold", Color.black);
+      threshline = new GraphLine((max - min) / 2f, "Threshold", Color.black);
     }
 
-    if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
+    if (hasThreshold)
     {
       adjusting = true;
-      acg.setThresh(threshline.value);
+      acg.setThreshold(threshline.value);
 
       float range = (max - min) * scaleFactor;
 
@@ -453,18 +447,18 @@ public class FeatureColourChooser extends JalviewDialog
       adjusting = false;
     }
 
-    acg.setThreshType(aboveThreshold);
-    if (thresholdIsMin.isSelected()
-            && aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
+    acg.setAboveThreshold(aboveThreshold);
+    acg.setBelowThreshold(belowThreshold);
+    if (thresholdIsMin.isSelected() && hasThreshold)
     {
       acg.setAutoScaled(false);
-      if (aboveThreshold == AnnotationColourGradient.ABOVE_THRESHOLD)
+      if (aboveThreshold)
       {
-        acg = new GraduatedColor(acg, threshline.value, max);
+        acg = new FeatureColour((FeatureColour) acg, threshline.value, max);
       }
       else
       {
-        acg = new GraduatedColor(acg, min, threshline.value);
+        acg = new FeatureColour((FeatureColour) acg, min, threshline.value);
       }
     }
     else
@@ -554,7 +548,7 @@ public class FeatureColourChooser extends JalviewDialog
   public void valueChanged()
   {
     threshline.value = slider.getValue() / scaleFactor;
-    cs.setThresh(threshline.value);
+    cs.setThreshold(threshline.value);
     changeColour();
     ap.paintAlignment(false);
   }
index 1cf15ac..1bf7453 100644 (file)
  */
 package jalview.gui;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
+import jalview.schemes.UserColourScheme;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
@@ -94,7 +96,7 @@ public class FeatureRenderer extends
 
   static String lastDescriptionAdded;
 
-  Object oldcol, fcol;
+  FeatureColourI oldcol, fcol;
 
   int featureIndex = 0;
 
@@ -126,20 +128,19 @@ public class FeatureRenderer extends
       @Override
       public void mousePressed(MouseEvent evt)
       {
-        if (fcol instanceof Color)
+        if (fcol.isSimpleColour())
         {
           Color col = JColorChooser.showDialog(Desktop.desktop,
                   MessageManager.getString("label.select_feature_colour"),
-                  ((Color) fcol));
+                  fcol.getColour());
           if (col != null)
           {
-            fcol = col;
-            updateColourButton(bigPanel, colour, col);
+            fcol = new FeatureColour(col);
+            updateColourButton(bigPanel, colour, new FeatureColour(col));
           }
         }
         else
         {
-
           if (fcc == null)
           {
             final String type = features[featureIndex].getType();
@@ -206,11 +207,11 @@ public class FeatureRenderer extends
             ap.getSeqPanel().seqCanvas.highlightSearchResults(highlight);
 
           }
-          Object col = getFeatureStyle(name.getText());
+          FeatureColourI col = getFeatureStyle(name.getText());
           if (col == null)
           {
-            col = new jalview.schemes.UserColourScheme()
-                    .createColourFromName(name.getText());
+            col = new FeatureColour(UserColourScheme
+                    .createColourFromName(name.getText()));
           }
           oldcol = fcol = col;
           updateColourButton(bigPanel, colour, col);
@@ -421,26 +422,25 @@ public class FeatureRenderer extends
    * 
    * @param bigPanel
    * @param col
-   * @param col2
+   * @param col
    */
   protected void updateColourButton(JPanel bigPanel, JLabel colour,
-          Object col2)
+          FeatureColourI col)
   {
     colour.removeAll();
     colour.setIcon(null);
     colour.setToolTipText(null);
     colour.setText("");
 
-    if (col2 instanceof Color)
+    if (col.isSimpleColour())
     {
-      colour.setBackground((Color) col2);
+      colour.setBackground(col.getColour());
     }
     else
     {
       colour.setBackground(bigPanel.getBackground());
       colour.setForeground(Color.black);
-      FeatureSettings.renderGraduatedColor(colour, (GraduatedColor) col2);
-      // colour.setForeground(colour.getBackground());
+      FeatureSettings.renderGraduatedColor(colour, col);
     }
   }
 
index 6633156..bfc14b5 100644 (file)
  */
 package jalview.gui;
 
+import jalview.api.FeatureColourI;
 import jalview.api.FeatureSettingsControllerI;
 import jalview.bin.Cache;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.Help.HelpId;
 import jalview.io.JalviewFileChooser;
-import jalview.schemes.AnnotationColourGradient;
-import jalview.schemes.GraduatedColor;
+import jalview.schemabinding.version2.JalviewUserColours;
+import jalview.schemes.FeatureColour;
+import jalview.util.Format;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.util.QuickSort;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.ws.dbsources.das.api.jalviewSourceI;
 
@@ -160,8 +164,8 @@ public class FeatureSettings extends JPanel implements
 
     table.setDefaultEditor(Color.class, new ColorEditor(this));
 
-    table.setDefaultEditor(GraduatedColor.class, new ColorEditor(this));
-    table.setDefaultRenderer(GraduatedColor.class, new ColorRenderer());
+    table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
+    table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
     table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 
     table.addMouseListener(new MouseAdapter()
@@ -170,7 +174,7 @@ public class FeatureSettings extends JPanel implements
       public void mousePressed(MouseEvent evt)
       {
         selectedRow = table.rowAtPoint(evt.getPoint());
-        if (evt.isPopupTrigger())
+        if (SwingUtilities.isRightMouseButton(evt))
         {
           popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
                   table.getValueAt(selectedRow, 1), fr.getMinMax(),
@@ -251,7 +255,7 @@ public class FeatureSettings extends JPanel implements
 
     frame = new JInternalFrame();
     frame.setContentPane(this);
-    if (new jalview.util.Platform().isAMac())
+    if (Platform.isAMac())
     {
       Desktop.addInternalFrame(frame,
               MessageManager.getString("label.sequence_feature_settings"),
@@ -281,6 +285,8 @@ public class FeatureSettings extends JPanel implements
           final Object typeCol, final Map<String, float[][]> minmax, int x,
           int y)
   {
+    final FeatureColourI featureColour = (FeatureColourI) typeCol;
+
     JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
             "label.settings_for_param", new String[] { type }));
     JMenuItem scr = new JMenuItem(
@@ -336,7 +342,7 @@ public class FeatureSettings extends JPanel implements
         // positional features
         final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
                 "Graduated Colour");
-        mxcol.setSelected(!(typeCol instanceof Color));
+        mxcol.setSelected(!featureColour.isSimpleColour());
         men.add(mxcol);
         mxcol.addActionListener(new ActionListener()
         {
@@ -347,7 +353,7 @@ public class FeatureSettings extends JPanel implements
           {
             if (e.getSource() == mxcol)
             {
-              if (typeCol instanceof Color)
+              if (featureColour.isSimpleColour())
               {
                 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
                         type);
@@ -361,8 +367,7 @@ public class FeatureSettings extends JPanel implements
                         "Select new Colour", true, // modal
                         colorChooser, this, // OK button handler
                         null); // no CANCEL button handler
-                colorChooser.setColor(((GraduatedColor) typeCol)
-                        .getMaxColor());
+                colorChooser.setColor(featureColour.getMaxColour());
                 dialog.setVisible(true);
               }
             }
@@ -394,7 +399,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 +410,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 +417,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);
   }
 
@@ -427,13 +452,13 @@ public class FeatureSettings extends JPanel implements
   /**
    * contains a float[3] for each feature type string. created by setTableData
    */
-  Hashtable typeWidth = null;
+  Map<String, float[]> typeWidth = null;
 
   @Override
   synchronized public void discoverAllFeatureData()
   {
-    Vector allFeatures = new Vector();
-    Vector allGroups = new Vector();
+    Vector<String> allFeatures = new Vector<String>();
+    Vector<String> allGroups = new Vector<String>();
     SequenceFeature[] tmpfeatures;
     String group;
     for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
@@ -539,13 +564,13 @@ public class FeatureSettings extends JPanel implements
       return;
     }
     resettingTable = true;
-    typeWidth = new Hashtable();
+    typeWidth = new Hashtable<String, float[]>();
     // TODO: change avWidth calculation to 'per-sequence' average and use long
     // rather than float
     float[] avWidth = null;
     SequenceFeature[] tmpfeatures;
     String group = null, type;
-    Vector visibleChecks = new Vector();
+    Vector<String> visibleChecks = new Vector<String>();
 
     // Find out which features should be visible depending on which groups
     // are selected / deselected
@@ -586,7 +611,7 @@ public class FeatureSettings extends JPanel implements
         }
         else
         {
-          avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
+          avWidth = typeWidth.get(tmpfeatures[index].getType());
         }
         avWidth[0]++;
         if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
@@ -731,8 +756,7 @@ public class FeatureSettings extends JPanel implements
         InputStreamReader in = new InputStreamReader(new FileInputStream(
                 file), "UTF-8");
 
-        jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
-        jucs = jucs.unmarshal(in);
+        JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
 
         for (int i = jucs.getColourCount() - 1; i >= 0; i--)
         {
@@ -751,7 +775,7 @@ public class FeatureSettings extends JPanel implements
               Cache.log.warn("Couldn't parse out graduated feature color.",
                       e);
             }
-            GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
+            FeatureColourI gcol = new FeatureColour(mincol, maxcol,
                     newcol.getMin(), newcol.getMax());
             if (newcol.hasAutoScale())
             {
@@ -763,31 +787,28 @@ public class FeatureSettings extends JPanel implements
             }
             if (newcol.hasThreshold())
             {
-              gcol.setThresh(newcol.getThreshold());
-              gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
+              gcol.setThreshold(newcol.getThreshold());
             }
             if (newcol.getThreshType().length() > 0)
             {
               String ttyp = newcol.getThreshType();
-              if (ttyp.equalsIgnoreCase("NONE"))
-              {
-                gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
-              }
               if (ttyp.equalsIgnoreCase("ABOVE"))
               {
-                gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
+                gcol.setAboveThreshold(true);
               }
               if (ttyp.equalsIgnoreCase("BELOW"))
               {
-                gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
+                gcol.setBelowThreshold(true);
               }
             }
             fr.setColour(name = newcol.getName(), gcol);
           }
           else
           {
-            fr.setColour(name = jucs.getColour(i).getName(), new Color(
-                    Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
+            Color color = new Color(
+                    Integer.parseInt(jucs.getColour(i).getRGB(), 16));
+            fr.setColour(name = jucs.getColour(i).getName(),
+                    new FeatureColour(color));
           }
           fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
         }
@@ -810,7 +831,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,50 +852,40 @@ 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++)
         {
           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]);
-          if (fcol instanceof GraduatedColor)
+          FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
+          if (fcol.isSimpleColour())
           {
-            gcol = (GraduatedColor) fcol;
-            col.setMin(gcol.getMin());
-            col.setMax(gcol.getMax());
-            col.setMinRGB(jalview.util.Format.getHexString(gcol
-                    .getMinColor()));
-            col.setAutoScale(gcol.isAutoScale());
-            col.setThreshold(gcol.getThresh());
-            col.setColourByLabel(gcol.isColourByLabel());
-            switch (gcol.getThreshType())
-            {
-            case AnnotationColourGradient.NO_THRESHOLD:
-              col.setThreshType("NONE");
-              break;
-            case AnnotationColourGradient.ABOVE_THRESHOLD:
-              col.setThreshType("ABOVE");
-              break;
-            case AnnotationColourGradient.BELOW_THRESHOLD:
-              col.setThreshType("BELOW");
-              break;
-            }
+            col.setRGB(Format.getHexString(fcol.getColour()));
+          }
+          else
+          {
+            col.setRGB(Format.getHexString(fcol.getMaxColour()));
+            col.setMin(fcol.getMin());
+            col.setMax(fcol.getMax());
+            col.setMinRGB(jalview.util.Format.getHexString(fcol
+                    .getMinColour()));
+            col.setAutoScale(fcol.isAutoScaled());
+            col.setThreshold(fcol.getThreshold());
+            col.setColourByLabel(fcol.isColourByLabel());
+            col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
+                    .isBelowThreshold() ? "BELOW" : "NONE"));
           }
           ucs.addColour(col);
         }
@@ -910,7 +921,7 @@ public class FeatureSettings extends JPanel implements
     int num = 0;
     for (int i = 0; i < data.length; i++)
     {
-      awidth = (float[]) typeWidth.get(data[i][0]);
+      awidth = typeWidth.get(data[i][0]);
       if (awidth[0] > 0)
       {
         width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
@@ -1233,7 +1244,8 @@ public class FeatureSettings extends JPanel implements
     fetchDAS.setEnabled(false);
     cancelDAS.setEnabled(true);
     dassourceBrowser.setGuiEnabled(false);
-    Vector selectedSources = dassourceBrowser.getSelectedSources();
+    Vector<jalviewSourceI> selectedSources = dassourceBrowser
+            .getSelectedSources();
     doDasFeatureFetch(selectedSources, true, true);
   }
 
@@ -1292,7 +1304,7 @@ public class FeatureSettings extends JPanel implements
    *          Vector of Strings to resolve to DAS source nicknames.
    * @return sources that are present in source list.
    */
-  public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
+  public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
   {
     return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
   }
@@ -1303,7 +1315,7 @@ public class FeatureSettings extends JPanel implements
    * 
    * @return vector of selected das source nicknames
    */
-  public Vector getSelectedSources()
+  public Vector<jalviewSourceI> getSelectedSources()
   {
     return dassourceBrowser.getSelectedSources();
   }
@@ -1317,7 +1329,7 @@ public class FeatureSettings extends JPanel implements
    *          if true then runs in same thread, otherwise passes to the Swing
    *          executor
    */
-  public void fetchDasFeatures(Vector sources, boolean block)
+  public void fetchDasFeatures(Vector<String> sources, boolean block)
   {
     initDasSources();
     List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
@@ -1483,10 +1495,11 @@ public class FeatureSettings extends JPanel implements
     }
 
     @Override
-    public Component getTableCellRendererComponent(JTable table,
+    public Component getTableCellRendererComponent(JTable tbl,
             Object color, boolean isSelected, boolean hasFocus, int row,
             int column)
     {
+      FeatureColourI cellColour = (FeatureColourI) color;
       // JLabel comp = new JLabel();
       // comp.
       setOpaque(true);
@@ -1494,11 +1507,11 @@ public class FeatureSettings extends JPanel implements
       // setBounds(getBounds());
       Color newColor;
       setToolTipText(baseTT);
-      setBackground(table.getBackground());
-      if (color instanceof GraduatedColor)
+      setBackground(tbl.getBackground());
+      if (!cellColour.isSimpleColour())
       {
-        Rectangle cr = table.getCellRect(row, column, false);
-        FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
+        Rectangle cr = tbl.getCellRect(row, column, false);
+        FeatureSettings.renderGraduatedColor(this, cellColour,
                 (int) cr.getWidth(), (int) cr.getHeight());
 
       }
@@ -1506,20 +1519,16 @@ public class FeatureSettings extends JPanel implements
       {
         this.setText("");
         this.setIcon(null);
-        newColor = (Color) color;
-        // comp.
+        newColor = cellColour.getColour();
         setBackground(newColor);
-        // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
-        // + newColor.getGreen() + ", " + newColor.getBlue());
       }
       if (isSelected)
       {
         if (selectedBorder == null)
         {
           selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
-                  table.getSelectionBackground());
+                  tbl.getSelectionBackground());
         }
-        // comp.
         setBorder(selectedBorder);
       }
       else
@@ -1527,9 +1536,8 @@ public class FeatureSettings extends JPanel implements
         if (unselectedBorder == null)
         {
           unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
-                  table.getBackground());
+                  tbl.getBackground());
         }
-        // comp.
         setBorder(unselectedBorder);
       }
 
@@ -1543,7 +1551,7 @@ public class FeatureSettings extends JPanel implements
    * @param comp
    * @param gcol
    */
-  public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
+  public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
   {
     int w = comp.getWidth(), h = comp.getHeight();
     if (w < 20)
@@ -1559,23 +1567,23 @@ public class FeatureSettings extends JPanel implements
     renderGraduatedColor(comp, gcol, w, h);
   }
 
-  public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
+  public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
           int w, int h)
   {
     boolean thr = false;
     String tt = "";
     String tx = "";
-    if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
+    if (gcol.isAboveThreshold())
     {
       thr = true;
       tx += ">";
-      tt += "Thresholded (Above " + gcol.getThresh() + ") ";
+      tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
     }
-    if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
+    if (gcol.isBelowThreshold())
     {
       thr = true;
       tx += "<";
-      tt += "Thresholded (Below " + gcol.getThresh() + ") ";
+      tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
     }
     if (gcol.isColourByLabel())
     {
@@ -1589,7 +1597,7 @@ public class FeatureSettings extends JPanel implements
     }
     else
     {
-      Color newColor = gcol.getMaxColor();
+      Color newColor = gcol.getMaxColour();
       comp.setBackground(newColor);
       // System.err.println("Width is " + w / 2);
       Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
@@ -1617,7 +1625,7 @@ public class FeatureSettings extends JPanel implements
 
 class FeatureIcon implements Icon
 {
-  GraduatedColor gcol;
+  FeatureColourI gcol;
 
   Color backg;
 
@@ -1629,7 +1637,7 @@ class FeatureIcon implements Icon
 
   Color mpcolour = Color.white;
 
-  FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
+  FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
   {
     gcol = gfc;
     backg = bg;
@@ -1669,7 +1677,7 @@ class FeatureIcon implements Icon
       g.setColor(backg);
       g.fillRect(0, 0, width, height);
       // need an icon here.
-      g.setColor(gcol.getMaxColor());
+      g.setColor(gcol.getMaxColour());
 
       g.setFont(new Font("Verdana", Font.PLAIN, 9));
 
@@ -1683,7 +1691,7 @@ class FeatureIcon implements Icon
     }
     else
     {
-      Color minCol = gcol.getMinColor();
+      Color minCol = gcol.getMinColour();
       g.setColor(minCol);
       g.fillRect(0, 0, s1, height);
       if (midspace)
@@ -1691,7 +1699,7 @@ class FeatureIcon implements Icon
         g.setColor(Color.white);
         g.fillRect(s1, 0, e1 - s1, height);
       }
-      g.setColor(gcol.getMaxColor());
+      g.setColor(gcol.getMaxColour());
       g.fillRect(0, e1, width - e1, height);
     }
   }
@@ -1702,14 +1710,12 @@ class ColorEditor extends AbstractCellEditor implements TableCellEditor,
 {
   FeatureSettings me;
 
-  GraduatedColor currentGColor;
+  FeatureColourI currentColor;
 
   FeatureColourChooser chooser;
 
   String type;
 
-  Color currentColor;
-
   JButton button;
 
   JColorChooser colorChooser;
@@ -1749,11 +1755,11 @@ class ColorEditor extends AbstractCellEditor implements TableCellEditor,
     {
       // The user has clicked the cell, so
       // bring up the dialog.
-      if (currentColor != null)
+      if (currentColor.isSimpleColour())
       {
         // bring up simple color chooser
-        button.setBackground(currentColor);
-        colorChooser.setColor(currentColor);
+        button.setBackground(currentColor.getColour());
+        colorChooser.setColor(currentColor.getColour());
         dialog.setVisible(true);
       }
       else
@@ -1770,15 +1776,13 @@ class ColorEditor extends AbstractCellEditor implements TableCellEditor,
     }
     else
     { // User pressed dialog's "OK" button.
-      if (currentColor != null)
+      if (currentColor.isSimpleColour())
       {
-        currentColor = colorChooser.getColor();
+        currentColor = new FeatureColour(colorChooser.getColor());
       }
       else
       {
-        // class cast exceptions may be raised if the chooser created on a
-        // non-graduated color
-        currentGColor = (GraduatedColor) chooser.getLastColour();
+        currentColor = chooser.getLastColour();
       }
       me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
       fireEditingStopped();
@@ -1790,10 +1794,6 @@ class ColorEditor extends AbstractCellEditor implements TableCellEditor,
   @Override
   public Object getCellEditorValue()
   {
-    if (currentColor == null)
-    {
-      return currentGColor;
-    }
     return currentColor;
   }
 
@@ -1802,18 +1802,16 @@ class ColorEditor extends AbstractCellEditor implements TableCellEditor,
   public Component getTableCellEditorComponent(JTable table, Object value,
           boolean isSelected, int row, int column)
   {
-    currentGColor = null;
-    currentColor = null;
+    currentColor = (FeatureColourI) value;
     this.selectedRow = row;
     type = me.table.getValueAt(row, 0).toString();
     button.setOpaque(true);
     button.setBackground(me.getBackground());
-    if (value instanceof GraduatedColor)
+    if (!currentColor.isSimpleColour())
     {
-      currentGColor = (GraduatedColor) value;
       JLabel btn = new JLabel();
       btn.setSize(button.getSize());
-      FeatureSettings.renderGraduatedColor(btn, currentGColor);
+      FeatureSettings.renderGraduatedColor(btn, currentColor);
       button.setBackground(btn.getBackground());
       button.setIcon(btn.getIcon());
       button.setText(btn.getText());
@@ -1822,8 +1820,7 @@ class ColorEditor extends AbstractCellEditor implements TableCellEditor,
     {
       button.setText("");
       button.setIcon(null);
-      currentColor = (Color) value;
-      button.setBackground(currentColor);
+      button.setBackground(currentColor.getColour());
     }
     return button;
   }
index c84505b..61ddafb 100755 (executable)
@@ -349,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..01e60d4 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import jalview.api.FeatureColourI;
 import jalview.api.ViewStyleI;
 import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.Cache;
@@ -71,7 +72,7 @@ import jalview.schemabinding.version2.Viewport;
 import jalview.schemes.AnnotationColourGradient;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
 import jalview.schemes.ResidueColourScheme;
 import jalview.schemes.ResidueProperties;
 import jalview.schemes.UserColourScheme;
@@ -79,6 +80,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 +92,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 +119,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;
@@ -633,11 +635,15 @@ public class Jalview2XML
     object.setVersion(jalview.bin.Cache.getDefault("VERSION",
             "Development Build"));
 
-    jalview.datamodel.AlignmentI jal = av.getAlignment();
+    /**
+     * rjal is full height alignment, jal is actual alignment with full metadata
+     * but excludes hidden sequences.
+     */
+    jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
 
     if (av.hasHiddenRows())
     {
-      jal = jal.getHiddenSequences().getFullAlignment();
+      rjal = jal.getHiddenSequences().getFullAlignment();
     }
 
     SequenceSet vamsasSet = new SequenceSet();
@@ -654,6 +660,7 @@ public class Jalview2XML
       {
         // switch jal and the dataset
         jal = jal.getDataset();
+        rjal = jal;
       }
     }
     if (jal.getProperties() != null)
@@ -673,9 +680,8 @@ public class Jalview2XML
     Set<String> calcIdSet = new HashSet<String>();
 
     // SAVE SEQUENCES
-    for (int i = 0; i < jal.getHeight(); i++)
+    for (final SequenceI jds : rjal.getSequences())
     {
-      final SequenceI jds = jal.getSequenceAt(i);
       final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
               : jds.getDatasetSequence();
       String id = seqHash(jds);
@@ -714,26 +720,34 @@ public class Jalview2XML
         // Store any sequences this sequence represents
         if (av.hasHiddenRows())
         {
+          // use rjal, contains the full height alignment
           jseq.setHidden(av.getAlignment().getHiddenSequences()
                   .isHidden(jds));
 
-          if (av.isHiddenRepSequence(jal.getSequenceAt(i)))
+          if (av.isHiddenRepSequence(jds))
           {
             jalview.datamodel.SequenceI[] reps = av
-                    .getRepresentedSequences(jal.getSequenceAt(i))
-                    .getSequencesInOrder(jal);
+                    .getRepresentedSequences(jds)
+                    .getSequencesInOrder(rjal);
 
             for (int h = 0; h < reps.length; h++)
             {
-              if (reps[h] != jal.getSequenceAt(i))
+              if (reps[h] != jds)
               {
-                jseq.addHiddenSequences(jal.findIndex(reps[h]));
+                jseq.addHiddenSequences(rjal.findIndex(reps[h]));
               }
             }
           }
         }
+        // mark sequence as reference - if it is the reference for this view
+        if (jal.hasSeqrep())
+        {
+          jseq.setViewreference(jds == jal.getSeqrep());
+        }
       }
 
+      // TODO: omit sequence features from each alignment view's XML dump if we
+      // are storing dataset
       if (jds.getSequenceFeatures() != null)
       {
         jalview.datamodel.SequenceFeature[] sf = jds.getSequenceFeatures();
@@ -899,7 +913,7 @@ public class Jalview2XML
             alc.addAlcodMap(alcmap);
           }
         }
-
+        // TODO: delete this ? dead code from 2.8.3->2.9 ?
         // {
         // AlcodonFrame alc = new AlcodonFrame();
         // vamsasSet.addAlcodonFrame(alc);
@@ -1194,82 +1208,55 @@ public class Jalview2XML
                 .getFeatureRenderer().getRenderOrder()
                 .toArray(new String[0]);
 
-        Vector settingsAdded = new Vector();
-        Object gstyle = null;
-        GraduatedColor gcol = null;
+        Vector<String> settingsAdded = new Vector<String>();
         if (renderOrder != null)
         {
-          for (int ro = 0; ro < renderOrder.length; ro++)
+          for (String featureType : renderOrder)
           {
-            gstyle = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
-                    .getFeatureStyle(renderOrder[ro]);
+            FeatureColourI fcol = ap.getSeqPanel().seqCanvas
+                    .getFeatureRenderer()
+                    .getFeatureStyle(featureType);
             Setting setting = new Setting();
-            setting.setType(renderOrder[ro]);
-            if (gstyle instanceof GraduatedColor)
+            setting.setType(featureType);
+            if (!fcol.isSimpleColour())
             {
-              gcol = (GraduatedColor) gstyle;
-              setting.setColour(gcol.getMaxColor().getRGB());
-              setting.setMincolour(gcol.getMinColor().getRGB());
-              setting.setMin(gcol.getMin());
-              setting.setMax(gcol.getMax());
-              setting.setColourByLabel(gcol.isColourByLabel());
-              setting.setAutoScale(gcol.isAutoScale());
-              setting.setThreshold(gcol.getThresh());
-              setting.setThreshstate(gcol.getThreshType());
+              setting.setColour(fcol.getMaxColour().getRGB());
+              setting.setMincolour(fcol.getMinColour().getRGB());
+              setting.setMin(fcol.getMin());
+              setting.setMax(fcol.getMax());
+              setting.setColourByLabel(fcol.isColourByLabel());
+              setting.setAutoScale(fcol.isAutoScaled());
+              setting.setThreshold(fcol.getThreshold());
+              // -1 = No threshold, 0 = Below, 1 = Above
+              setting.setThreshstate(fcol.isAboveThreshold() ? 1
+                      : (fcol.isBelowThreshold() ? 0 : -1));
             }
             else
             {
-              setting.setColour(ap.getSeqPanel().seqCanvas
-                      .getFeatureRenderer().getColour(renderOrder[ro])
-                      .getRGB());
+              setting.setColour(fcol.getColour().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;
@@ -1283,7 +1270,6 @@ public class Jalview2XML
           groupsAdded.addElement(grp);
         }
         jms.setFeatureSettings(fs);
-
       }
 
       if (av.hasHiddenColumns())
@@ -2680,7 +2666,7 @@ public class Jalview2XML
     List<SequenceI> tmpseqs = new ArrayList<SequenceI>();
 
     boolean multipleView = false;
-
+    SequenceI referenceseqForView = null;
     JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
     int vi = 0; // counter in vamsasSeq array
     for (int i = 0; i < jseqs.length; i++)
@@ -2705,6 +2691,11 @@ public class Jalview2XML
         vi++;
       }
 
+      if (jseqs[i].hasViewreference() && jseqs[i].getViewreference())
+      {
+        referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
+      }
+
       if (jseqs[i].getHidden())
       {
         if (hiddenSeqs == null)
@@ -2714,7 +2705,6 @@ public class Jalview2XML
 
         hiddenSeqs.add(seqRefIds.get(seqId));
       }
-
     }
 
     // /
@@ -2725,6 +2715,10 @@ public class Jalview2XML
 
     Alignment al = new Alignment(orderedSeqs);
 
+    if (referenceseqForView != null)
+    {
+      al.setSeqrep(referenceseqForView);
+    }
     // / Add the alignment properties
     for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
     {
@@ -4047,18 +4041,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 +4067,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;
@@ -4151,6 +4112,12 @@ public class Jalview2XML
               .getSequenceAt(i), new java.awt.Color(JSEQ[i].getColour()));
     }
 
+    if (al.hasSeqrep())
+    {
+      af.getViewport().setColourByReferenceSeq(true);
+      af.getViewport().setDisplayReferenceSeq(true);
+    }
+
     af.viewport.setGatherViewsHere(view.getGatheredViews());
 
     if (view.getSequenceSetId() != null)
@@ -4354,25 +4321,33 @@ public class Jalview2XML
       af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
       String[] renderOrder = new String[jms.getFeatureSettings()
               .getSettingCount()];
-      Hashtable featureGroups = new Hashtable();
-      Hashtable featureColours = new Hashtable();
-      Hashtable featureOrder = new Hashtable();
+      Map<String, FeatureColourI> featureColours = new Hashtable<String, FeatureColourI>();
+      Map<String, Float> featureOrder = new Hashtable<String, Float>();
 
       for (int fs = 0; fs < jms.getFeatureSettings().getSettingCount(); fs++)
       {
         Setting setting = jms.getFeatureSettings().getSetting(fs);
         if (setting.hasMincolour())
         {
-          GraduatedColor gc = setting.hasMin() ? new GraduatedColor(
-                  new java.awt.Color(setting.getMincolour()),
-                  new java.awt.Color(setting.getColour()),
-                  setting.getMin(), setting.getMax()) : new GraduatedColor(
-                  new java.awt.Color(setting.getMincolour()),
-                  new java.awt.Color(setting.getColour()), 0, 1);
+          FeatureColourI gc = setting.hasMin() ? new FeatureColour(
+                  new Color(setting.getMincolour()), new Color(
+                          setting.getColour()), setting.getMin(),
+                  setting.getMax()) : new FeatureColour(new Color(
+                  setting.getMincolour()), new Color(setting.getColour()),
+                  0, 1);
           if (setting.hasThreshold())
           {
-            gc.setThresh(setting.getThreshold());
-            gc.setThreshType(setting.getThreshstate());
+            gc.setThreshold(setting.getThreshold());
+            int threshstate = setting.getThreshstate();
+            // -1 = None, 0 = Below, 1 = Above threshold
+            if (threshstate == 0)
+            {
+              gc.setBelowThreshold(true);
+            }
+            else if (threshstate == 1)
+            {
+              gc.setAboveThreshold(true);
+            }
           }
           gc.setAutoScaled(true); // default
           if (setting.hasAutoScale())
@@ -4388,8 +4363,8 @@ public class Jalview2XML
         }
         else
         {
-          featureColours.put(setting.getType(),
-                  new java.awt.Color(setting.getColour()));
+          featureColours.put(setting.getType(), new FeatureColour(
+                  new Color(setting.getColour())));
         }
         renderOrder[fs] = setting.getType();
         if (setting.hasOrder())
@@ -4406,7 +4381,7 @@ public class Jalview2XML
           fdi.setVisible(setting.getType());
         }
       }
-      Hashtable fgtable = new Hashtable();
+      Map<String, Boolean> fgtable = new Hashtable<String, Boolean>();
       for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
       {
         Group grp = jms.getFeatureSettings().getGroup(gs);
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..497f3ba 100644 (file)
@@ -2270,28 +2270,7 @@ public class PopupMenu extends JPopupMenu
 
   void hideSequences(boolean representGroup)
   {
-    SequenceGroup sg = ap.av.getSelectionGroup();
-    if (sg == null || sg.getSize() < 1)
-    {
-      ap.av.hideSequence(new SequenceI[] { sequence });
-      return;
-    }
-
-    ap.av.setSelectionGroup(null);
-
-    if (representGroup)
-    {
-      ap.av.hideRepSequences(sequence, sg);
-
-      return;
-    }
-
-    int gsize = sg.getSize();
-    SequenceI[] hseqs = sg.getSequences().toArray(new SequenceI[gsize]);
-
-    ap.av.hideSequence(hseqs);
-    // refresh(); TODO: ? needed ?
-    ap.av.sendSelection();
+    ap.av.hideSequences(sequence, representGroup);
   }
 
   public void copy_actionPerformed()
@@ -2363,45 +2342,6 @@ public class PopupMenu extends JPopupMenu
             ap, true));
   }
 
-  public void enterPDB_actionPerformed()
-  {
-    String id = JOptionPane.showInternalInputDialog(Desktop.desktop,
-            MessageManager.getString("label.enter_pdb_id"),
-            MessageManager.getString("label.enter_pdb_id"),
-            JOptionPane.QUESTION_MESSAGE);
-
-    if (id != null && id.length() > 0)
-    {
-      PDBEntry entry = new PDBEntry();
-      entry.setId(id.toUpperCase());
-      sequence.getDatasetSequence().addPDBId(entry);
-    }
-  }
-
-  public void discoverPDB_actionPerformed()
-  {
-
-    final SequenceI[] sequences = ((ap.av.getSelectionGroup() == null) ? new SequenceI[]
-    { sequence }
-            : ap.av.getSequenceSelection());
-    Thread discpdb = new Thread(new Runnable()
-    {
-      @Override
-      public void run()
-      {
-        boolean isNuclueotide = ap.alignFrame.getViewport().getAlignment()
-                .isNucleotide();
-
-        new jalview.ws.DBRefFetcher(sequences, ap.alignFrame, null,
-                ap.alignFrame.featureSettings, isNuclueotide)
-                .fetchDBRefs(false);
-
-      }
-
-    });
-    discpdb.start();
-  }
-
   public void sequenceFeature_actionPerformed()
   {
     SequenceGroup sg = ap.av.getSelectionGroup();
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 aedb157..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,92 +493,15 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
         }
       }
     }
-    // Draw the scale numbers
-    gg.setColor(Color.black);
-
-    int scalestartx = (startx / 10) * 10;
-
-    SequenceI refSeq = av.getAlignment().getSeqrep();
-    int refSp = 0, refEp = -1, refStart = 0, refEnd = -1, 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];
-      refEp = refbounds[1];
-      refStart = refbounds[2];
-      refEnd = refbounds[3];
-      refStartI = refbounds[4];
-      refEndI = refbounds[5];
-      scalestartx = refSp + ((scalestartx - refSp) / 10) * 10;
-    }
-
 
     int widthx = 1 + endx - startx;
 
     FontMetrics fm = gg.getFontMetrics(av.getFont());
-    int y = avCharHeight - fm.getDescent();
-
-    if (refSeq == null && scalestartx % 10 == 0)
-    {
-      scalestartx += 5;
-    }
-
-    String string;
-    int maxX = 0, refN, iadj;
-    // todo: add a 'reference origin column' to set column number relative to
-    for (int i = scalestartx; i < endx; i += 5)
-    {
-      if (((i - refSp) % 10) == 0)
-      {
-        iadj = av.getColumnSelection().adjustForHiddenColumns(i) - 1;
-        if (refSeq == null)
-        {
-          string = String.valueOf(iadj + 1);
-        }
-        else
-        {
-          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);
-          }
-        }
-        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()
@@ -590,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"),
@@ -606,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 d5a04a9..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()
@@ -919,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,
@@ -944,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();
@@ -987,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 258a229..427eb08 100755 (executable)
@@ -29,12 +29,6 @@ import java.awt.Color;
 import java.awt.FontMetrics;
 import java.awt.Graphics;
 
-/**
- * DOCUMENT ME!
- * 
- * @author $author$
- * @version $Revision$
- */
 public class SequenceRenderer implements jalview.api.SequenceRenderer
 {
   final static int CHAR_TO_UPPER = 'A' - 'a';
@@ -417,7 +411,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
           }
           if (!isarep && av.getShowUnconserved())
           {
-            s = getDisplayChar(srep, i, s, '.', currentSequenceGroup);
+            s = getDisplayChar(srep, i, s, '.', null);
 
           }
 
@@ -447,12 +441,17 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
   {
     // TODO - use currentSequenceGroup rather than alignment
     // currentSequenceGroup.getConsensus()
-    char conschar = (usesrep) ? (currentGroup == null ? av.getAlignment()
+    char conschar = (usesrep) ? (currentGroup == null
+            || position < currentGroup.getStartRes()
+            || position > currentGroup.getEndRes() ? av.getAlignment()
             .getSeqrep().getCharAt(position)
             : (currentGroup.getSeqrep() != null ? currentGroup.getSeqrep()
                     .getCharAt(position) : av.getAlignment().getSeqrep()
                     .getCharAt(position)))
-            : (currentGroup != null && currentGroup.getConsensus() != null) ? currentGroup
+            : (currentGroup != null && currentGroup.getConsensus() != null
+                    && position >= currentGroup.getStartRes()
+                    && position <= currentGroup.getEndRes() && currentGroup
+                    .getConsensus().annotations.length > position) ? currentGroup
                     .getConsensus().annotations[position].displayCharacter
                     .charAt(0)
                     : av.getAlignmentConsensusAnnotation().annotations[position].displayCharacter
index d924e73..8bccc6b 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;
@@ -44,6 +45,7 @@ import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 import java.util.Vector;
 
 import javax.swing.JCheckBox;
@@ -147,8 +149,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 +187,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();
@@ -247,7 +250,7 @@ public class StructureChooser extends GStructureChooser implements
     boolean isPDBRefsFound = false;
     boolean isUniProtRefsFound = false;
     StringBuilder queryBuilder = new StringBuilder();
-    HashSet<String> seqRefs = new LinkedHashSet<String>();
+    Set<String> seqRefs = new LinkedHashSet<String>();
 
     if (seq.getAllPDBEntries() != null)
     {
@@ -255,9 +258,8 @@ public class StructureChooser extends GStructureChooser implements
       {
         if (isValidSeqName(entry.getId()))
         {
-          queryBuilder.append("pdb_id")
-                  .append(":")
-.append(entry.getId().toLowerCase())
+          queryBuilder.append("pdb_id:")
+                  .append(entry.getId().toLowerCase())
                   .append(" OR ");
           isPDBRefsFound = true;
           // seqRefs.add(entry.getId());
@@ -273,21 +275,18 @@ public class StructureChooser extends GStructureChooser implements
         {
           if (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT))
           {
-            queryBuilder
-.append("uniprot_accession").append(":")
+            queryBuilder.append("uniprot_accession:")
                     .append(getDBRefId(dbRef))
                     .append(" OR ");
-            queryBuilder
-.append("uniprot_id")
-                    .append(":")
-                    .append(getDBRefId(dbRef)).append(" OR ");
+            queryBuilder.append("uniprot_id:").append(getDBRefId(dbRef))
+                    .append(" OR ");
             isUniProtRefsFound = true;
           }
           else if (dbRef.getSource().equalsIgnoreCase(DBRefSource.PDB))
           {
 
-            queryBuilder.append("pdb_id")
-                    .append(":").append(getDBRefId(dbRef).toLowerCase())
+            queryBuilder.append("pdb_id:")
+                    .append(getDBRefId(dbRef).toLowerCase())
                     .append(" OR ");
             isPDBRefsFound = true;
           }
@@ -330,17 +329,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 +395,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 +405,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 +452,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 +530,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 +590,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 +728,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,7 +801,15 @@ public class StructureChooser extends GStructureChooser implements
       if (pdbEntry == null)
       {
         pdbEntry = new PDBEntry();
-        pdbEntry.setId(pdbIdStr);
+            if (pdbIdStr.split(":").length > 1)
+            {
+              pdbEntry.setId(pdbIdStr.split(":")[0]);
+              pdbEntry.setChainCode(pdbIdStr.split(":")[1].toUpperCase());
+            }
+            else
+            {
+              pdbEntry.setId(pdbIdStr);
+            }
         pdbEntry.setType(PDBEntry.Type.PDB);
         selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
       }
@@ -849,42 +858,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 +968,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 +978,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 8b3aa98..d738882 100755 (executable)
@@ -1760,6 +1760,10 @@ public class AnnotationFile
    */
   public String printCSVAnnotations(AlignmentAnnotation[] annotations)
   {
+    if (annotations == null)
+    {
+      return "";
+    }
     StringBuffer sp = new StringBuffer();
     for (int i = 0; i < annotations.length; i++)
     {
index 2dd5f26..aa38540 100755 (executable)
@@ -23,6 +23,7 @@ package jalview.io;
 import jalview.analysis.AlignmentUtils;
 import jalview.analysis.SequenceIdMatcher;
 import jalview.api.AlignViewportI;
+import jalview.api.FeatureColourI;
 import jalview.api.FeaturesSourceI;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
@@ -33,15 +34,12 @@ import jalview.datamodel.SequenceI;
 import jalview.io.gff.GffHelperBase;
 import jalview.io.gff.GffHelperFactory;
 import jalview.io.gff.GffHelperI;
-import jalview.schemes.AnnotationColourGradient;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
 import jalview.schemes.UserColourScheme;
-import jalview.util.Format;
 import jalview.util.MapList;
 import jalview.util.ParseHtmlBodyAndLinks;
 import jalview.util.StringUtils;
 
-import java.awt.Color;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -50,7 +48,6 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.StringTokenizer;
 
 /**
  * Parses and writes features files, which may be in Jalview, GFF2 or GFF3
@@ -140,7 +137,8 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    *          - process html strings into plain text
    * @return true if features were added
    */
-  public boolean parse(AlignmentI align, Map<String, Object> colours,
+  public boolean parse(AlignmentI align,
+          Map<String, FeatureColourI> colours,
           boolean removeHTML)
   {
     return parse(align, colours, removeHTML, false);
@@ -177,7 +175,8 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    *          - when true, ID matches to compound sequence IDs are allowed
    * @return true if features were added
    */
-  public boolean parse(AlignmentI align, Map<String, Object> colours,
+  public boolean parse(AlignmentI align,
+          Map<String, FeatureColourI> colours,
           boolean removeHTML, boolean relaxedIdmatching)
   {
     Map<String, String> gffProps = new HashMap<String, String>();
@@ -232,12 +231,18 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
           else if (ft.equalsIgnoreCase("endgroup"))
           {
             // We should check whether this is the current group,
-            // but at present theres no way of showing more than 1 group
+            // but at present there's no way of showing more than 1 group
             featureGroup = null;
           }
           else
           {
-            parseFeatureColour(line, ft, gffColumns, colours);
+            String colscheme = gffColumns[1];
+            FeatureColourI colour = FeatureColour
+                    .parseJalviewFeatureColour(colscheme);
+            if (colour != null)
+            {
+              colours.put(ft, colour);
+            }
           }
           continue;
         }
@@ -297,7 +302,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    * @param featureGroup
    */
   protected boolean parseJalviewFeature(String line, String[] gffColumns,
-          AlignmentI alignment, Map<String, Object> featureColours,
+          AlignmentI alignment, Map<String, FeatureColourI> featureColours,
           boolean removeHTML, boolean relaxedIdMatching, String featureGroup)
   {
     /*
@@ -350,7 +355,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
        * synthesize a colour from the feature type
        */
       UserColourScheme ucs = new UserColourScheme(ft);
-      featureColours.put(ft, ucs.findColour('A'));
+      featureColours.put(ft, new FeatureColour(ucs.findColour('A')));
     }
     SequenceFeature sf = new SequenceFeature(ft, desc, "", startPos,
             endPos, featureGroup);
@@ -381,225 +386,6 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
   }
 
   /**
-   * Process a feature type colour specification
-   * 
-   * @param line
-   *          the current input line (for error messages only)
-   * @param featureType
-   *          the first token on the line
-   * @param gffColumns
-   *          holds tokens on the line
-   * @param colours
-   *          map to which to add derived colour specification
-   */
-  protected void parseFeatureColour(String line, String featureType,
-          String[] gffColumns, Map<String, Object> colours)
-  {
-    Object colour = null;
-    String colscheme = gffColumns[1];
-    if (colscheme.indexOf("|") > -1
-            || colscheme.trim().equalsIgnoreCase("label"))
-    {
-      colour = parseGraduatedColourScheme(line, colscheme);
-    }
-    else
-    {
-      UserColourScheme ucs = new UserColourScheme(colscheme);
-      colour = ucs.findColour('A');
-    }
-    if (colour != null)
-    {
-      colours.put(featureType, colour);
-    }
-  }
-
-  /**
-   * Parse a Jalview graduated colour descriptor
-   * 
-   * @param line
-   * @param colourDescriptor
-   * @return
-   */
-  protected GraduatedColor parseGraduatedColourScheme(String line,
-          String colourDescriptor)
-  {
-    // Parse '|' separated graduated colourscheme fields:
-    // [label|][mincolour|maxcolour|[absolute|]minvalue|maxvalue|thresholdtype|thresholdvalue]
-    // can either provide 'label' only, first is optional, next two
-    // colors are required (but may be
-    // left blank), next is optional, nxt two min/max are required.
-    // first is either 'label'
-    // first/second and third are both hexadecimal or word equivalent
-    // colour.
-    // next two are values parsed as floats.
-    // fifth is either 'above','below', or 'none'.
-    // sixth is a float value and only required when fifth is either
-    // 'above' or 'below'.
-    StringTokenizer gcol = new StringTokenizer(colourDescriptor, "|", true);
-    // set defaults
-    float min = Float.MIN_VALUE, max = Float.MAX_VALUE;
-    boolean labelCol = false;
-    // Parse spec line
-    String mincol = gcol.nextToken();
-    if (mincol == "|")
-    {
-      System.err
-              .println("Expected either 'label' or a colour specification in the line: "
-                      + line);
-      return null;
-    }
-    String maxcol = null;
-    if (mincol.toLowerCase().indexOf("label") == 0)
-    {
-      labelCol = true;
-      mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null); // skip '|'
-      mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
-    }
-    String abso = null, minval, maxval;
-    if (mincol != null)
-    {
-      // at least four more tokens
-      if (mincol.equals("|"))
-      {
-        mincol = "";
-      }
-      else
-      {
-        gcol.nextToken(); // skip next '|'
-      }
-      // continue parsing rest of line
-      maxcol = gcol.nextToken();
-      if (maxcol.equals("|"))
-      {
-        maxcol = "";
-      }
-      else
-      {
-        gcol.nextToken(); // skip next '|'
-      }
-      abso = gcol.nextToken();
-      gcol.nextToken(); // skip next '|'
-      if (abso.toLowerCase().indexOf("abso") != 0)
-      {
-        minval = abso;
-        abso = null;
-      }
-      else
-      {
-        minval = gcol.nextToken();
-        gcol.nextToken(); // skip next '|'
-      }
-      maxval = gcol.nextToken();
-      if (gcol.hasMoreTokens())
-      {
-        gcol.nextToken(); // skip next '|'
-      }
-      try
-      {
-        if (minval.length() > 0)
-        {
-          min = Float.valueOf(minval);
-        }
-      } catch (Exception e)
-      {
-        System.err
-                .println("Couldn't parse the minimum value for graduated colour for type ("
-                        + colourDescriptor
-                        + ") - did you misspell 'auto' for the optional automatic colour switch ?");
-        e.printStackTrace();
-      }
-      try
-      {
-        if (maxval.length() > 0)
-        {
-          max = Float.valueOf(maxval);
-        }
-      } catch (Exception e)
-      {
-        System.err
-                .println("Couldn't parse the maximum value for graduated colour for type ("
-                        + colourDescriptor + ")");
-        e.printStackTrace();
-      }
-    }
-    else
-    {
-      // add in some dummy min/max colours for the label-only
-      // colourscheme.
-      mincol = "FFFFFF";
-      maxcol = "000000";
-    }
-
-    GraduatedColor colour = null;
-    try
-    {
-      colour = new GraduatedColor(
-              new UserColourScheme(mincol).findColour('A'),
-              new UserColourScheme(maxcol).findColour('A'), min, max);
-    } catch (Exception e)
-    {
-      System.err.println("Couldn't parse the graduated colour scheme ("
-              + colourDescriptor + ")");
-      e.printStackTrace();
-    }
-    if (colour != null)
-    {
-      colour.setColourByLabel(labelCol);
-      colour.setAutoScaled(abso == null);
-      // add in any additional parameters
-      String ttype = null, tval = null;
-      if (gcol.hasMoreTokens())
-      {
-        // threshold type and possibly a threshold value
-        ttype = gcol.nextToken();
-        if (ttype.toLowerCase().startsWith("below"))
-        {
-          colour.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
-        }
-        else if (ttype.toLowerCase().startsWith("above"))
-        {
-          colour.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
-        }
-        else
-        {
-          colour.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
-          if (!ttype.toLowerCase().startsWith("no"))
-          {
-            System.err.println("Ignoring unrecognised threshold type : "
-                    + ttype);
-          }
-        }
-      }
-      if (colour.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
-      {
-        try
-        {
-          gcol.nextToken();
-          tval = gcol.nextToken();
-          colour.setThresh(new Float(tval).floatValue());
-        } catch (Exception e)
-        {
-          System.err.println("Couldn't parse threshold value as a float: ("
-                  + tval + ")");
-          e.printStackTrace();
-        }
-      }
-      // parse the thresh-is-min token ?
-      if (gcol.hasMoreTokens())
-      {
-        System.err
-                .println("Ignoring additional tokens in parameters in graduated colour specification\n");
-        while (gcol.hasMoreTokens())
-        {
-          System.err.println("|" + gcol.nextToken());
-        }
-        System.err.println("\n");
-      }
-    }
-    return colour;
-  }
-
-  /**
    * clear any temporary handles used to speed up ID matching
    */
   protected void resetMatcher()
@@ -703,7 +489,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    * @return features file contents
    */
   public String printJalviewFormat(SequenceI[] sequences,
-          Map<String, Object> visible)
+          Map<String, FeatureColourI> visible)
   {
     return printJalviewFormat(sequences, visible, true, true);
   }
@@ -723,7 +509,8 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    * @return features file contents
    */
   public String printJalviewFormat(SequenceI[] sequences,
-          Map<String, Object> visible, boolean visOnly, boolean nonpos)
+          Map<String, FeatureColourI> visible, boolean visOnly,
+          boolean nonpos)
   {
     StringBuilder out = new StringBuilder(256);
     boolean featuresGen = false;
@@ -739,58 +526,14 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
       // viewed features
       // TODO: decide if feature links should also be written here ?
       Iterator<String> en = visible.keySet().iterator();
-      String featureType, color;
       while (en.hasNext())
       {
-        featureType = en.next().toString();
-
-        if (visible.get(featureType) instanceof GraduatedColor)
-        {
-          GraduatedColor gc = (GraduatedColor) visible.get(featureType);
-          color = (gc.isColourByLabel() ? "label|" : "")
-                  + Format.getHexString(gc.getMinColor()) + "|"
-                  + Format.getHexString(gc.getMaxColor())
-                  + (gc.isAutoScale() ? "|" : "|abso|") + gc.getMin() + "|"
-                  + gc.getMax() + "|";
-          if (gc.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
-          {
-            if (gc.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
-            {
-              color += "below";
-            }
-            else
-            {
-              if (gc.getThreshType() != AnnotationColourGradient.ABOVE_THRESHOLD)
-              {
-                System.err.println("WARNING: Unsupported threshold type ("
-                        + gc.getThreshType() + ") : Assuming 'above'");
-              }
-              color += "above";
-            }
-            // add the value
-            color += "|" + gc.getThresh();
-          }
-          else
-          {
-            color += "none";
-          }
-        }
-        else if (visible.get(featureType) instanceof Color)
-        {
-          color = Format.getHexString((Color) visible.get(featureType));
-        }
-        else
-        {
-          // legacy support for integer objects containing colour triplet values
-          color = Format.getHexString(new Color(Integer.parseInt(visible
-                  .get(featureType).toString())));
-        }
-        out.append(featureType);
-        out.append(TAB);
-        out.append(color);
-        out.append(newline);
+        String featureType = en.next().toString();
+        FeatureColourI colour = visible.get(featureType);
+        out.append(colour.toJalviewFormat(featureType)).append(newline);
       }
     }
+
     // Work out which groups are both present and visible
     List<String> groups = new ArrayList<String>();
     int groupIndex = 0;
@@ -842,12 +585,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 +598,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 +649,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);
           }
@@ -1003,7 +747,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    * @return
    */
   public String printGffFormat(SequenceI[] sequences,
-          Map<String, Object> visible)
+          Map<String, FeatureColourI> visible)
   {
     return printGffFormat(sequences, visible, true, true);
   }
@@ -1020,11 +764,12 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    * @return
    */
   public String printGffFormat(SequenceI[] sequences,
-          Map<String, Object> visible, boolean outputVisibleOnly,
+          Map<String, FeatureColourI> visible, boolean outputVisibleOnly,
           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 36980f8..3cda444 100644 (file)
@@ -744,11 +744,14 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
     fr = avpanel.cloneFeatureRenderer();
 
     // Add non auto calculated annotation to AlignFile
-    for (AlignmentAnnotation annot : annots)
+    if (annots != null)
     {
-      if (annot != null && !annot.autoCalculated)
+      for (AlignmentAnnotation annot : annots)
       {
-        annotations.add(annot);
+        if (annot != null && !annot.autoCalculated)
+        {
+          annotations.add(annot);
+        }
       }
     }
     globalColourScheme = ColourSchemeProperty.getColourName(viewport
index 83bb37e..ecce1a3 100644 (file)
@@ -1,7 +1,7 @@
 package jalview.io;
 
 import jalview.api.FeatureColourI;
-import jalview.schemes.FeatureColourAdapter;
+import jalview.schemes.FeatureColour;
 import jalview.schemes.FeatureSettingsAdapter;
 
 import java.awt.Color;
@@ -25,7 +25,7 @@ public class PDBFeatureSettings extends FeatureSettingsAdapter
   {
     if (type.equalsIgnoreCase(FEATURE_INSERTION))
     {
-      return new FeatureColourAdapter()
+      return new FeatureColour()
       {
 
         @Override
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 817ba9c..63263d2 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.io.packed;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
 import jalview.io.NewickFile;
@@ -57,7 +58,7 @@ public class JalviewDataset
   /**
    * @return the featureColours
    */
-  public Map<String, Object> getFeatureColours()
+  public Map<String, FeatureColourI> getFeatureColours()
   {
     return featureColours;
   }
@@ -66,7 +67,7 @@ public class JalviewDataset
    * @param featureColours
    *          the featureColours to set
    */
-  public void setFeatureColours(Map<String, Object> featureColours)
+  public void setFeatureColours(Map<String, FeatureColourI> featureColours)
   {
     this.featureColours = featureColours;
   }
@@ -187,7 +188,7 @@ public class JalviewDataset
   /**
    * current set of feature colours
    */
-  Map<String, Object> featureColours;
+  Map<String, FeatureColourI> featureColours;
 
   /**
    * original identity of each sequence in results
@@ -201,7 +202,7 @@ public class JalviewDataset
     seqDetails = new Hashtable();
     al = new ArrayList<AlignmentSet>();
     parentDataset = null;
-    featureColours = new HashMap<String, Object>();
+    featureColours = new HashMap<String, FeatureColourI>();
   }
 
   /**
@@ -209,7 +210,8 @@ public class JalviewDataset
    * 
    * @param parentAlignment
    */
-  public JalviewDataset(AlignmentI aldataset, Map<String, Object> fc,
+  public JalviewDataset(AlignmentI aldataset,
+          Map<String, FeatureColourI> fc,
           Hashtable seqDets)
   {
     // TODO not used - remove?
@@ -231,7 +233,8 @@ public class JalviewDataset
    *          (may be null) alignment to associate new annotation and trees
    *          with.
    */
-  public JalviewDataset(AlignmentI aldataset, Map<String, Object> fc,
+  public JalviewDataset(AlignmentI aldataset,
+          Map<String, FeatureColourI> fc,
           Hashtable seqDets, AlignmentI parentAlignment)
   {
     this();
index 01369b9..71999f0 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.io.packed;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.AlignmentI;
 import jalview.io.AppletFormatAdapter;
 import jalview.io.FileParse;
@@ -157,7 +158,7 @@ public class ParsePackedSet
         // if not, create one.
         if (context.featureColours == null)
         {
-          context.featureColours = new HashMap<String, Object>();
+          context.featureColours = new HashMap<String, FeatureColourI>();
         }
         try
         {
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 2276913..5d3aa2d 100644 (file)
@@ -50,6 +50,8 @@ public class FeatureRenderer extends FeatureRendererModel
 
   boolean av_validCharWidth, av_isShowSeqFeatureHeight;
 
+  private Integer currentColour;
+
   protected void updateAvConfig()
   {
     av_charHeight = av.getCharHeight();
@@ -175,8 +177,8 @@ public class FeatureRenderer extends FeatureRendererModel
   }
 
   /**
-   * This is used by the Molecule Viewer and Overview to get the accurate
-   * colourof the rendered sequence
+   * This is used by the Molecule Viewer and Overview to get the accurate colour
+   * of the rendered sequence
    */
   public synchronized int findFeatureColour(int initialCol,
           final SequenceI seq, int column)
@@ -246,7 +248,7 @@ public class FeatureRenderer extends FeatureRendererModel
       }
       else
       {
-        return ((Integer) currentColour).intValue();
+        return currentColour.intValue();
       }
     }
 
@@ -390,7 +392,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,
@@ -398,19 +400,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 361fb7c..0a01103 100644 (file)
@@ -1,4 +1,4 @@
-#Thu Sep 03 10:55:37 BST 2015
+#Mon Jun 20 15:44:52 BST 2016
 jalview.schemabinding.version2.ThresholdLine=jalview.schemabinding.version2.descriptors.ThresholdLineDescriptor
 jalview.schemabinding.version2.SequenceSetProperties=jalview.schemabinding.version2.descriptors.SequenceSetPropertiesDescriptor
 jalview.schemabinding.version2.StructureState=jalview.schemabinding.version2.descriptors.StructureStateDescriptor
index 9ca6708..7c6308e 100644 (file)
@@ -72,6 +72,16 @@ public class JSeq implements java.io.Serializable
   private boolean _has_hidden;
 
   /**
+   * Field _viewreference.
+   */
+  private boolean _viewreference;
+
+  /**
+   * keeps track of state for field: _viewreference
+   */
+  private boolean _has_viewreference;
+
+  /**
    * Field _featuresList.
    */
   private java.util.Vector _featuresList;
@@ -256,6 +266,13 @@ public class JSeq implements java.io.Serializable
   }
 
   /**
+     */
+  public void deleteViewreference()
+  {
+    this._has_viewreference = false;
+  }
+
+  /**
    * Method enumerateFeatures.
    * 
    * @return an Enumeration over all jalview.schemabinding.version2.Features
@@ -549,6 +566,16 @@ public class JSeq implements java.io.Serializable
   }
 
   /**
+   * Returns the value of field 'viewreference'.
+   * 
+   * @return the value of field 'Viewreference'.
+   */
+  public boolean getViewreference()
+  {
+    return this._viewreference;
+  }
+
+  /**
    * Method hasColour.
    * 
    * @return true if at least one Colour has been added
@@ -589,6 +616,16 @@ public class JSeq implements java.io.Serializable
   }
 
   /**
+   * Method hasViewreference.
+   * 
+   * @return true if at least one Viewreference has been added
+   */
+  public boolean hasViewreference()
+  {
+    return this._has_viewreference;
+  }
+
+  /**
    * Returns the value of field 'hidden'.
    * 
    * @return the value of field 'Hidden'.
@@ -616,6 +653,16 @@ public class JSeq implements java.io.Serializable
   }
 
   /**
+   * Returns the value of field 'viewreference'.
+   * 
+   * @return the value of field 'Viewreference'.
+   */
+  public boolean isViewreference()
+  {
+    return this._viewreference;
+  }
+
+  /**
    * 
    * 
    * @param out
@@ -1004,6 +1051,18 @@ public class JSeq implements java.io.Serializable
   }
 
   /**
+   * Sets the value of field 'viewreference'.
+   * 
+   * @param viewreference
+   *          the value of field 'viewreference'.
+   */
+  public void setViewreference(final boolean viewreference)
+  {
+    this._viewreference = viewreference;
+    this._has_viewreference = true;
+  }
+
+  /**
    * Method unmarshal.
    * 
    * @param reader
index 1d2aad3..5739d90 100644 (file)
@@ -11,6 +11,8 @@ package jalview.schemabinding.version2.descriptors;
 //- Imported classes and packages -/
 //---------------------------------/
 
+import jalview.schemabinding.version2.AnnotationColours;
+
 /**
  * Class AnnotationColoursDescriptor.
  * 
index a7ffaba..107c06d 100644 (file)
@@ -11,6 +11,8 @@ package jalview.schemabinding.version2.descriptors;
 //- Imported classes and packages -/
 //---------------------------------/
 
+import jalview.schemabinding.version2.Features;
+
 /**
  * Class FeaturesDescriptor.
  * 
index 0f000bb..28f23b2 100644 (file)
@@ -334,6 +334,61 @@ public class JSeqDescriptor extends
       fieldValidator.setValidator(typeValidator);
     }
     desc.setValidator(fieldValidator);
+    // -- _viewreference
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Boolean.TYPE, "_viewreference", "viewreference",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        JSeq target = (JSeq) object;
+        if (!target.hasViewreference())
+        {
+          return null;
+        }
+        return (target.getViewreference() ? java.lang.Boolean.TRUE
+                : java.lang.Boolean.FALSE);
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          JSeq target = (JSeq) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteViewreference();
+            return;
+          }
+          target.setViewreference(((java.lang.Boolean) value)
+                  .booleanValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _viewreference
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.BooleanValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.BooleanValidator();
+      fieldValidator.setValidator(typeValidator);
+    }
+    desc.setValidator(fieldValidator);
     // -- initialize element descriptors
 
     // -- _featuresList
index 77efa7e..d65de13 100644 (file)
@@ -72,6 +72,7 @@ public class JalviewUserColoursDescriptor extends
     desc.setImmutable(true);
     handler = new org.exolab.castor.xml.XMLFieldHandler()
     {
+      @Override
       public java.lang.Object getValue(java.lang.Object object)
               throws IllegalStateException
       {
@@ -79,6 +80,7 @@ public class JalviewUserColoursDescriptor extends
         return target.getSchemeName();
       }
 
+      @Override
       public void setValue(java.lang.Object object, java.lang.Object value)
               throws IllegalStateException, IllegalArgumentException
       {
@@ -92,6 +94,7 @@ public class JalviewUserColoursDescriptor extends
         }
       }
 
+      @Override
       public java.lang.Object newInstance(java.lang.Object parent)
       {
         return null;
@@ -119,6 +122,7 @@ public class JalviewUserColoursDescriptor extends
     desc.setImmutable(true);
     handler = new org.exolab.castor.xml.XMLFieldHandler()
     {
+      @Override
       public java.lang.Object getValue(java.lang.Object object)
               throws IllegalStateException
       {
@@ -126,6 +130,7 @@ public class JalviewUserColoursDescriptor extends
         return target.getVersion();
       }
 
+      @Override
       public void setValue(java.lang.Object object, java.lang.Object value)
               throws IllegalStateException, IllegalArgumentException
       {
@@ -139,6 +144,7 @@ public class JalviewUserColoursDescriptor extends
         }
       }
 
+      @Override
       public java.lang.Object newInstance(java.lang.Object parent)
       {
         return null;
@@ -163,6 +169,7 @@ public class JalviewUserColoursDescriptor extends
             org.exolab.castor.xml.NodeType.Element);
     handler = new org.exolab.castor.xml.XMLFieldHandler()
     {
+      @Override
       public java.lang.Object getValue(java.lang.Object object)
               throws IllegalStateException
       {
@@ -170,6 +177,7 @@ public class JalviewUserColoursDescriptor extends
         return target.getColour();
       }
 
+      @Override
       public void setValue(java.lang.Object object, java.lang.Object value)
               throws IllegalStateException, IllegalArgumentException
       {
@@ -183,6 +191,7 @@ public class JalviewUserColoursDescriptor extends
         }
       }
 
+      @Override
       public void resetValue(Object object) throws IllegalStateException,
               IllegalArgumentException
       {
@@ -196,6 +205,7 @@ public class JalviewUserColoursDescriptor extends
         }
       }
 
+      @Override
       public java.lang.Object newInstance(java.lang.Object parent)
       {
         return new Colour();
@@ -222,6 +232,7 @@ public class JalviewUserColoursDescriptor extends
    * 
    * @return the access mode specified for this class.
    */
+  @Override
   public org.exolab.castor.mapping.AccessMode getAccessMode()
   {
     return null;
@@ -232,6 +243,7 @@ public class JalviewUserColoursDescriptor extends
    * 
    * @return the identity field, null if this class has no identity.
    */
+  @Override
   public org.exolab.castor.mapping.FieldDescriptor getIdentity()
   {
     return super.getIdentity();
@@ -242,6 +254,7 @@ public class JalviewUserColoursDescriptor extends
    * 
    * @return the Java class represented by this descriptor.
    */
+  @Override
   public java.lang.Class getJavaClass()
   {
     return jalview.schemabinding.version2.JalviewUserColours.class;
@@ -252,6 +265,7 @@ public class JalviewUserColoursDescriptor extends
    * 
    * @return the namespace prefix to use when marshaling as XML.
    */
+  @Override
   public java.lang.String getNameSpacePrefix()
   {
     return _nsPrefix;
@@ -262,6 +276,7 @@ public class JalviewUserColoursDescriptor extends
    * 
    * @return the namespace URI used when marshaling and unmarshaling as XML.
    */
+  @Override
   public java.lang.String getNameSpaceURI()
   {
     return _nsURI;
@@ -273,6 +288,7 @@ public class JalviewUserColoursDescriptor extends
    * @return a specific validator for the class described by this
    *         ClassDescriptor.
    */
+  @Override
   public org.exolab.castor.xml.TypeValidator getValidator()
   {
     return this;
@@ -283,6 +299,7 @@ public class JalviewUserColoursDescriptor extends
    * 
    * @return the XML Name for the Class being described.
    */
+  @Override
   public java.lang.String getXMLName()
   {
     return _xmlName;
@@ -294,6 +311,7 @@ public class JalviewUserColoursDescriptor extends
    * @return true if XML schema definition of this Class is that of a global
    *         element or element with anonymous type definition.
    */
+  @Override
   public boolean isElementDefinition()
   {
     return _elementDefinition;
index ece728a..df9ab07 100644 (file)
@@ -11,6 +11,8 @@ package jalview.schemabinding.version2.descriptors;
 //- Imported classes and packages -/
 //---------------------------------/
 
+import jalview.schemabinding.version2.UserColourScheme;
+
 /**
  * Class UserColourSchemeDescriptor.
  * 
index 86e6992..3e26611 100644 (file)
@@ -11,6 +11,8 @@ package jalview.schemabinding.version2.descriptors;
 //- Imported classes and packages -/
 //---------------------------------/
 
+import jalview.schemabinding.version2.VamsasModel;
+
 /**
  * Class VamsasModelDescriptor.
  * 
diff --git a/src/jalview/schemes/FeatureColour.java b/src/jalview/schemes/FeatureColour.java
new file mode 100644 (file)
index 0000000..bdc70c9
--- /dev/null
@@ -0,0 +1,673 @@
+package jalview.schemes;
+
+import jalview.api.FeatureColourI;
+import jalview.datamodel.SequenceFeature;
+import jalview.util.Format;
+
+import java.awt.Color;
+import java.util.StringTokenizer;
+
+/**
+ * A class that wraps either a simple colour or a graduated colour
+ */
+public class FeatureColour implements FeatureColourI
+{
+  private static final String BAR = "|";
+
+  final private Color colour;
+
+  final private Color minColour;
+
+  final private Color maxColour;
+
+  private boolean graduatedColour;
+
+  private boolean colourByLabel;
+
+  private float threshold;
+
+  private float base;
+
+  private float range;
+
+  private boolean belowThreshold;
+
+  private boolean aboveThreshold;
+
+  private boolean thresholdIsMinOrMax;
+
+  private boolean isHighToLow;
+
+  private boolean autoScaled;
+
+  final private float minRed;
+
+  final private float minGreen;
+
+  final private float minBlue;
+
+  final private float deltaRed;
+
+  final private float deltaGreen;
+
+  final private float deltaBlue;
+
+  /**
+   * Parses a Jalview features file format colour descriptor
+   * [label|][mincolour|maxcolour
+   * |[absolute|]minvalue|maxvalue|thresholdtype|thresholdvalue] Examples:
+   * <ul>
+   * <li>red</li>
+   * <li>a28bbb</li>
+   * <li>25,125,213</li>
+   * <li>label</li>
+   * <li>label|||0.0|0.0|above|12.5</li>
+   * <li>label|||0.0|0.0|below|12.5</li>
+   * <li>red|green|12.0|26.0|none</li>
+   * <li>a28bbb|3eb555|12.0|26.0|above|12.5</li>
+   * <li>a28bbb|3eb555|abso|12.0|26.0|below|12.5</li>
+   * </ul>
+   * 
+   * @param descriptor
+   * @return
+   * @throws IllegalArgumentException
+   *           if not parseable
+   */
+  public static FeatureColour parseJalviewFeatureColour(String descriptor)
+  {
+    StringTokenizer gcol = new StringTokenizer(descriptor, "|", true);
+    float min = Float.MIN_VALUE;
+    float max = Float.MAX_VALUE;
+    boolean labelColour = false;
+
+    String mincol = gcol.nextToken();
+    if (mincol == "|")
+    {
+      throw new IllegalArgumentException(
+              "Expected either 'label' or a colour specification in the line: "
+                      + descriptor);
+    }
+    String maxcol = null;
+    if (mincol.toLowerCase().indexOf("label") == 0)
+    {
+      labelColour = true;
+      mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
+      // skip '|'
+      mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
+    }
+
+    if (!labelColour && !gcol.hasMoreTokens())
+    {
+      /*
+       * only a simple colour specification - parse it
+       */
+      Color colour = UserColourScheme.getColourFromString(descriptor);
+      if (colour == null)
+      {
+        throw new IllegalArgumentException("Invalid colour descriptor: "
+                + descriptor);
+      }
+      return new FeatureColour(colour);
+    }
+
+    /*
+     * autoScaled == true: colours range over actual score range
+     * autoScaled == false ('abso'): colours range over min/max range
+     */
+    boolean autoScaled = true;
+    String tok = null, minval, maxval;
+    if (mincol != null)
+    {
+      // at least four more tokens
+      if (mincol.equals("|"))
+      {
+        mincol = "";
+      }
+      else
+      {
+        gcol.nextToken(); // skip next '|'
+      }
+      maxcol = gcol.nextToken();
+      if (maxcol.equals("|"))
+      {
+        maxcol = "";
+      }
+      else
+      {
+        gcol.nextToken(); // skip next '|'
+      }
+      tok = gcol.nextToken();
+      gcol.nextToken(); // skip next '|'
+      if (tok.toLowerCase().startsWith("abso"))
+      {
+        minval = gcol.nextToken();
+        gcol.nextToken(); // skip next '|'
+        autoScaled = false;
+      }
+      else
+      {
+        minval = tok;
+      }
+      maxval = gcol.nextToken();
+      if (gcol.hasMoreTokens())
+      {
+        gcol.nextToken(); // skip next '|'
+      }
+      try
+      {
+        if (minval.length() > 0)
+        {
+          min = new Float(minval).floatValue();
+        }
+      } catch (Exception e)
+      {
+        throw new IllegalArgumentException(
+                "Couldn't parse the minimum value for graduated colour ("
+                        + descriptor + ")");
+      }
+      try
+      {
+        if (maxval.length() > 0)
+        {
+          max = new Float(maxval).floatValue();
+        }
+      } catch (Exception e)
+      {
+        throw new IllegalArgumentException(
+                "Couldn't parse the maximum value for graduated colour ("
+                        + descriptor + ")");
+      }
+    }
+    else
+    {
+      // add in some dummy min/max colours for the label-only
+      // colourscheme.
+      mincol = "FFFFFF";
+      maxcol = "000000";
+    }
+
+    /*
+     * construct the FeatureColour
+     */
+    FeatureColour featureColour;
+    try
+    {
+      featureColour = new FeatureColour(
+              new UserColourScheme(mincol).findColour('A'),
+              new UserColourScheme(maxcol).findColour('A'), min, max);
+      featureColour.setColourByLabel(labelColour);
+      featureColour.setAutoScaled(autoScaled);
+      // add in any additional parameters
+      String ttype = null, tval = null;
+      if (gcol.hasMoreTokens())
+      {
+        // threshold type and possibly a threshold value
+        ttype = gcol.nextToken();
+        if (ttype.toLowerCase().startsWith("below"))
+        {
+          featureColour.setBelowThreshold(true);
+        }
+        else if (ttype.toLowerCase().startsWith("above"))
+        {
+          featureColour.setAboveThreshold(true);
+        }
+        else
+        {
+          if (!ttype.toLowerCase().startsWith("no"))
+          {
+            System.err.println("Ignoring unrecognised threshold type : "
+                    + ttype);
+          }
+        }
+      }
+      if (featureColour.hasThreshold())
+      {
+        try
+        {
+          gcol.nextToken();
+          tval = gcol.nextToken();
+          featureColour.setThreshold(new Float(tval).floatValue());
+        } catch (Exception e)
+        {
+          System.err.println("Couldn't parse threshold value as a float: ("
+                  + tval + ")");
+        }
+      }
+      if (gcol.hasMoreTokens())
+      {
+        System.err
+                .println("Ignoring additional tokens in parameters in graduated colour specification\n");
+        while (gcol.hasMoreTokens())
+        {
+          System.err.println("|" + gcol.nextToken());
+        }
+        System.err.println("\n");
+      }
+      return featureColour;
+    } catch (Exception e)
+    {
+      throw new IllegalArgumentException(e.getMessage());
+    }
+  }
+
+  /**
+   * Default constructor
+   */
+  public FeatureColour()
+  {
+    this((Color) null);
+  }
+
+  /**
+   * Constructor given a simple colour
+   * 
+   * @param c
+   */
+  public FeatureColour(Color c)
+  {
+    minColour = Color.WHITE;
+    maxColour = Color.BLACK;
+    minRed = 0f;
+    minGreen = 0f;
+    minBlue = 0f;
+    deltaRed = 0f;
+    deltaGreen = 0f;
+    deltaBlue = 0f;
+    colour = c;
+  }
+
+  /**
+   * Constructor given a colour range and a score range
+   * 
+   * @param low
+   * @param high
+   * @param min
+   * @param max
+   */
+  public FeatureColour(Color low, Color high, float min, float max)
+  {
+    graduatedColour = true;
+    colour = null;
+    minColour = low;
+    maxColour = high;
+    threshold = Float.NaN;
+    isHighToLow = min >= max;
+    minRed = low.getRed() / 255f;
+    minGreen = low.getGreen() / 255f;
+    minBlue = low.getBlue() / 255f;
+    deltaRed = (high.getRed() / 255f) - minRed;
+    deltaGreen = (high.getGreen() / 255f) - minGreen;
+    deltaBlue = (high.getBlue() / 255f) - minBlue;
+    if (isHighToLow)
+    {
+      base = max;
+      range = min - max;
+    }
+    else
+    {
+      base = min;
+      range = max - min;
+    }
+  }
+
+  /**
+   * Copy constructor
+   * 
+   * @param fc
+   */
+  public FeatureColour(FeatureColour fc)
+  {
+    graduatedColour = fc.graduatedColour;
+    colour = fc.colour;
+    minColour = fc.minColour;
+    maxColour = fc.maxColour;
+    minRed = fc.minRed;
+    minGreen = fc.minGreen;
+    minBlue = fc.minBlue;
+    deltaRed = fc.deltaRed;
+    deltaGreen = fc.deltaGreen;
+    deltaBlue = fc.deltaBlue;
+    base = fc.base;
+    range = fc.range;
+    isHighToLow = fc.isHighToLow;
+    setAboveThreshold(fc.isAboveThreshold());
+    setBelowThreshold(fc.isBelowThreshold());
+    setThreshold(fc.getThreshold());
+    setAutoScaled(fc.isAutoScaled());
+    setColourByLabel(fc.isColourByLabel());
+  }
+  
+  /**
+   * Copy constructor with new min/max ranges
+   * @param fc
+   * @param min
+   * @param max
+   */
+  public FeatureColour(FeatureColour fc, float min, float max)
+  {
+    this(fc);
+    graduatedColour = true;
+    updateBounds(min, max);
+  }
+
+  @Override
+  public boolean isGraduatedColour()
+  {
+    return graduatedColour;
+  }
+
+  /**
+   * Sets the 'graduated colour' flag. If true, also sets 'colour by label' to
+   * false.
+   */
+  void setGraduatedColour(boolean b)
+  {
+    graduatedColour = b;
+    if (b)
+    {
+      setColourByLabel(false);
+    }
+  }
+
+  @Override
+  public Color getColour()
+  {
+    return colour;
+  }
+
+  @Override
+  public Color getMinColour()
+  {
+    return minColour;
+  }
+
+  @Override
+  public Color getMaxColour()
+  {
+    return maxColour;
+  }
+
+  @Override
+  public boolean isColourByLabel()
+  {
+    return colourByLabel;
+  }
+
+  /**
+   * Sets the 'colour by label' flag. If true, also sets 'graduated colour' to
+   * false.
+   */
+  @Override
+  public void setColourByLabel(boolean b)
+  {
+    colourByLabel = b;
+    if (b)
+    {
+      setGraduatedColour(false);
+    }
+  }
+  @Override
+  public boolean isBelowThreshold()
+  {
+    return belowThreshold;
+  }
+
+  @Override
+  public void setBelowThreshold(boolean b)
+  {
+    belowThreshold = b;
+    if (b)
+    {
+      setAboveThreshold(false);
+    }
+  }
+
+  @Override
+  public boolean isAboveThreshold()
+  {
+    return aboveThreshold;
+  }
+
+  @Override
+  public void setAboveThreshold(boolean b)
+  {
+    aboveThreshold = b;
+    if (b)
+    {
+      setBelowThreshold(false);
+    }
+  }
+
+  @Override
+  public boolean isThresholdMinMax()
+  {
+    return thresholdIsMinOrMax;
+  }
+
+  @Override
+  public void setThresholdMinMax(boolean b)
+  {
+    thresholdIsMinOrMax = b;
+  }
+
+  @Override
+  public float getThreshold()
+  {
+    return threshold;
+  }
+
+  @Override
+  public void setThreshold(float f)
+  {
+    threshold = f;
+  }
+
+  @Override
+  public boolean isAutoScaled()
+  {
+    return autoScaled;
+  }
+
+  @Override
+  public void setAutoScaled(boolean b)
+  {
+    this.autoScaled = b;
+  }
+
+  /**
+   * Updates the base and range appropriately for the given minmax range
+   * 
+   * @param min
+   * @param max
+   */
+  @Override
+  public void updateBounds(float min, float max)
+  {
+    if (max < min)
+    {
+      base = max;
+      range = min - max;
+      isHighToLow = true;
+    }
+    else
+    {
+      base = min;
+      range = max - min;
+      isHighToLow = false;
+    }
+  }
+
+  /**
+   * Returns the colour for the given instance of the feature. This may be a
+   * simple colour, a colour generated from the feature description (if
+   * isColourByLabel()), or a colour derived from the feature score (if
+   * isGraduatedColour()).
+   * 
+   * @param feature
+   * @return
+   */
+  @Override
+  public Color getColor(SequenceFeature feature)
+  {
+    if (isColourByLabel())
+    {
+      return UserColourScheme
+              .createColourFromName(feature.getDescription());
+    }
+
+    if (!isGraduatedColour())
+    {
+      return getColour();
+    }
+
+    // todo should we check for above/below threshold here?
+    if (range == 0.0)
+    {
+      return getMaxColour();
+    }
+    float scr = feature.getScore();
+    if (Float.isNaN(scr))
+    {
+      return getMinColour();
+    }
+    float scl = (scr - base) / range;
+    if (isHighToLow)
+    {
+      scl = -scl;
+    }
+    if (scl < 0f)
+    {
+      scl = 0f;
+    }
+    if (scl > 1f)
+    {
+      scl = 1f;
+    }
+    return new Color(minRed + scl * deltaRed, minGreen + scl * deltaGreen, minBlue + scl * deltaBlue);
+  }
+
+  /**
+   * Returns the maximum score of the graduated colour range
+   * 
+   * @return
+   */
+  @Override
+  public float getMax()
+  {
+    // regenerate the original values passed in to the constructor
+    return (isHighToLow) ? base : (base + range);
+  }
+
+  /**
+   * Returns the minimum score of the graduated colour range
+   * 
+   * @return
+   */
+  @Override
+  public float getMin()
+  {
+    // regenerate the original value passed in to the constructor
+    return (isHighToLow) ? (base + range) : base;
+  }
+
+  /**
+   * Answers true if the feature has a simple colour, or is coloured by label,
+   * or has a graduated colour and the score of this feature instance is within
+   * the range to render (if any), i.e. does not lie below or above any
+   * threshold set.
+   * 
+   * @param feature
+   * @return
+   */
+  @Override
+  public boolean isColored(SequenceFeature feature)
+  {
+    if (isColourByLabel() || !isGraduatedColour())
+    {
+      return true;
+    }
+
+    float val = feature.getScore();
+    if (Float.isNaN(val))
+    {
+      return true;
+    }
+    if (Float.isNaN(this.threshold))
+    {
+      return true;
+    }
+
+    if (isAboveThreshold() && val <= threshold)
+    {
+      return false;
+    }
+    if (isBelowThreshold() && val >= threshold)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  @Override
+  public boolean isSimpleColour()
+  {
+    return (!isColourByLabel() && !isGraduatedColour());
+  }
+
+  @Override
+  public boolean hasThreshold()
+  {
+    return isAboveThreshold() || isBelowThreshold();
+  }
+
+  @Override
+  public String toJalviewFormat(String featureType)
+  {
+    String colourString = null;
+    if (isSimpleColour())
+    {
+      colourString = Format.getHexString(getColour());
+    }
+    else
+    {
+      StringBuilder sb = new StringBuilder(32);
+      if (isColourByLabel())
+      {
+        sb.append("label");
+        if (hasThreshold())
+        {
+          sb.append(BAR).append(BAR).append(BAR);
+        }
+      }
+      if (isGraduatedColour())
+      {
+        sb.append(Format.getHexString(getMinColour())).append(BAR);
+        sb.append(Format.getHexString(getMaxColour())).append(BAR);
+        if (!isAutoScaled())
+        {
+          sb.append("abso").append(BAR);
+        }
+      }
+      if (hasThreshold() || isGraduatedColour())
+      {
+        sb.append(getMin()).append(BAR);
+        sb.append(getMax()).append(BAR);
+        if (isBelowThreshold())
+        {
+          sb.append("below").append(BAR).append(getThreshold());
+        }
+        else if (isAboveThreshold())
+        {
+          sb.append("above").append(BAR).append(getThreshold());
+        }
+        else
+        {
+          sb.append("none");
+        }
+      }
+      colourString = sb.toString();
+    }
+    return String.format("%s\t%s", featureType, colourString);
+  }
+
+}
diff --git a/src/jalview/schemes/FeatureColourAdapter.java b/src/jalview/schemes/FeatureColourAdapter.java
deleted file mode 100644 (file)
index a86bee4..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-package jalview.schemes;
-
-import jalview.api.FeatureColourI;
-
-import java.awt.Color;
-
-/**
- * A convenience class with implementations of FeatureColourI methods. Override
- * methods as required in subclasses.
- */
-public class FeatureColourAdapter implements FeatureColourI
-{
-  @Override
-  public boolean isGraduatedColour()
-  {
-    return isColourByLabel() || isAboveThreshold() || isBelowThreshold();
-  }
-
-  @Override
-  public Color getColour()
-  {
-    return Color.BLACK;
-  }
-
-  @Override
-  public Color getMinColour()
-  {
-    return Color.WHITE;
-  }
-
-  @Override
-  public Color getMaxColour()
-  {
-    return Color.BLACK;
-  }
-
-  @Override
-  public boolean isColourByLabel()
-  {
-    return false;
-  }
-
-  @Override
-  public boolean isBelowThreshold()
-  {
-    return false;
-  }
-
-  @Override
-  public boolean isAboveThreshold()
-  {
-    return false;
-  }
-
-  @Override
-  public boolean isThresholdMinMax()
-  {
-    return false;
-  }
-
-  @Override
-  public float getThreshold()
-  {
-    return 0f;
-  }
-
-  @Override
-  public boolean isLowToHigh()
-  {
-    return true;
-  }
-
-}
diff --git a/src/jalview/schemes/GraduatedColor.java b/src/jalview/schemes/GraduatedColor.java
deleted file mode 100644 (file)
index 2d1c572..0000000
+++ /dev/null
@@ -1,304 +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.schemes;
-
-import jalview.api.FeatureColourI;
-import jalview.datamodel.SequenceFeature;
-
-import java.awt.Color;
-
-/**
- * Value and/or thresholded colour scale used for colouring by annotation and
- * feature score
- * 
- * @author JimP
- * 
- */
-public class GraduatedColor
-{
-  int thresholdState = AnnotationColourGradient.NO_THRESHOLD; // or
-                                                              // ABOVE_THRESHOLD
-                                                              // or
-                                                              // BELOW_THRESHOLD
-
-  float lr, lg, lb, dr, dg, db;
-
-  /**
-   * linear scaling parameters, base, minimum colour threshold, range of linear
-   * scale from lower to upper
-   */
-  float base, range, thrsh;
-
-  /**
-   * when true, colour from u to u-d rather than u to u+d
-   */
-  boolean tolow = false;
-
-  /**
-   * when false, min/max range has been manually set so should not be
-   * dynamically adjusted.
-   */
-  boolean autoScale = true;
-
-  /**
-   * construct a graduatedColor object from simple parameters
-   * 
-   * @param low
-   * @param high
-   * @param min
-   * @param max
-   *          color low->high from min->max
-   */
-  public GraduatedColor(Color low, Color high, float min, float max)
-  {
-    thrsh = Float.NaN;
-    tolow = min >= max;
-    lr = low.getRed() / 255f;
-    lg = low.getGreen() / 255f;
-    lb = low.getBlue() / 255f;
-    dr = (high.getRed() / 255f) - lr;
-    dg = (high.getGreen() / 255f) - lg;
-    db = (high.getBlue() / 255f) - lb;
-    if (tolow)
-    {
-      base = max;
-      range = min - max;
-    }
-    else
-    {
-      base = min;
-      range = max - min;
-    }
-  }
-
-  public GraduatedColor(GraduatedColor oldcs)
-  {
-    lr = oldcs.lr;
-    lg = oldcs.lg;
-    lb = oldcs.lb;
-    dr = oldcs.dr;
-    dg = oldcs.dg;
-    db = oldcs.db;
-    base = oldcs.base;
-    range = oldcs.range;
-    tolow = oldcs.tolow;
-    thresholdState = oldcs.thresholdState;
-    thrsh = oldcs.thrsh;
-    autoScale = oldcs.autoScale;
-    colourByLabel = oldcs.colourByLabel;
-  }
-
-  /**
-   * make a new gradient from an old one with a different scale range
-   * 
-   * @param oldcs
-   * @param min
-   * @param max
-   */
-  public GraduatedColor(GraduatedColor oldcs, float min, float max)
-  {
-    this(oldcs);
-    updateBounds(min, max);
-  }
-
-  public GraduatedColor(FeatureColourI col)
-  {
-    setColourByLabel(col.isColourByLabel());
-  }
-
-  public Color getMinColor()
-  {
-    return new Color(lr, lg, lb);
-  }
-
-  public Color getMaxColor()
-  {
-    return new Color(lr + dr, lg + dg, lb + db);
-  }
-
-  /**
-   * 
-   * @return true if original min/max scale was from high to low
-   */
-  public boolean getTolow()
-  {
-    return tolow;
-  }
-
-  public void setTolow(boolean tolower)
-  {
-    tolow = tolower;
-  }
-
-  public boolean isColored(SequenceFeature feature)
-  {
-    float val = feature.getScore();
-    if (Float.isNaN(val))
-    {
-      return true;
-    }
-    if (this.thresholdState == AnnotationColourGradient.NO_THRESHOLD)
-    {
-      return true;
-    }
-    if (Float.isNaN(this.thrsh))
-    {
-      return true;
-    }
-    boolean rtn = thresholdState == AnnotationColourGradient.ABOVE_THRESHOLD;
-    if (val <= thrsh)
-    {
-      return !rtn; // ? !tolow : tolow;
-    }
-    else
-    {
-      return rtn; // ? tolow : !tolow;
-    }
-  }
-
-  /**
-   * default implementor of a getColourFromString method. TODO: abstract an
-   * interface enabling pluggable colour from string
-   */
-  private UserColourScheme ucs = null;
-
-  private boolean colourByLabel = false;
-
-  /**
-   * 
-   * @return true if colourByLabel style is set
-   */
-  public boolean isColourByLabel()
-  {
-    return colourByLabel;
-  }
-
-  /**
-   * @param colourByLabel
-   *          the colourByLabel to set
-   */
-  public void setColourByLabel(boolean colourByLabel)
-  {
-    this.colourByLabel = colourByLabel;
-  }
-
-  public Color findColor(SequenceFeature feature)
-  {
-    if (colourByLabel)
-    {
-      // TODO: allow user defined feature label colourschemes. Colour space is
-      // {type,regex,%anytype%}x{description string, regex, keyword}
-      if (ucs == null)
-      {
-        ucs = new UserColourScheme();
-      }
-      return ucs.createColourFromName(feature.getDescription());
-    }
-    if (range == 0.0)
-    {
-      return getMaxColor();
-    }
-    float scr = feature.getScore();
-    if (Float.isNaN(scr))
-    {
-      return getMinColor();
-    }
-    float scl = (scr - base) / range;
-    if (tolow)
-    {
-      scl = -scl;
-    }
-    if (scl < 0f)
-    {
-      scl = 0f;
-    }
-    if (scl > 1f)
-    {
-      scl = 1f;
-    }
-    return new Color(lr + scl * dr, lg + scl * dg, lb + scl * db);
-  }
-
-  public void setThresh(float value)
-  {
-    thrsh = value;
-  }
-
-  public float getThresh()
-  {
-    return thrsh;
-  }
-
-  public void setThreshType(int aboveThreshold)
-  {
-    thresholdState = aboveThreshold;
-  }
-
-  public int getThreshType()
-  {
-    return thresholdState;
-  }
-
-  public float getMax()
-  {
-    // regenerate the original values passed in to the constructor
-    return (tolow) ? base : (base + range);
-  }
-
-  public float getMin()
-  {
-    // regenerate the original value passed in to the constructor
-    return (tolow) ? (base + range) : base;
-  }
-
-  public boolean isAutoScale()
-  {
-    return autoScale;
-  }
-
-  public void setAutoScaled(boolean autoscale)
-  {
-    autoScale = autoscale;
-  }
-
-  /**
-   * update the base and range appropriatly for the given minmax range
-   * 
-   * @param a
-   *          float[] {min,max} array containing minmax range for the associated
-   *          score values
-   */
-  public void updateBounds(float min, float max)
-  {
-    if (max < min)
-    {
-      base = max;
-      range = min - max;
-      tolow = true;
-    }
-    else
-    {
-      base = min;
-      range = max - min;
-      tolow = false;
-    }
-  }
-}
index d17f510..9729a83 100644 (file)
@@ -91,6 +91,10 @@ public class RNAHelicesColour extends ResidueColourScheme
     // This loop will find the first rna structure annotation by which to colour
     // the sequences.
     AlignmentAnnotation[] annotations = alignment.getAlignmentAnnotation();
+    if (annotations == null)
+    {
+      return;
+    }
     for (int i = 0; i < annotations.length; i++)
     {
 
index 1a13bbe..b1b3c5a 100644 (file)
@@ -22,6 +22,7 @@ package jalview.schemes;
 
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
+import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.SequenceGroup;
 
 import java.awt.event.ActionEvent;
@@ -77,16 +78,20 @@ public class RNAHelicesColourChooser
     adjusting = true;
     Vector list = new Vector();
     int index = 1;
-    for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
+    AlignmentAnnotation[] anns = av.getAlignment().getAlignmentAnnotation();
+    if (anns != null)
     {
-      String label = av.getAlignment().getAlignmentAnnotation()[i].label;
-      if (!list.contains(label))
+      for (int i = 0; i < anns.length; i++)
       {
-        list.addElement(label);
-      }
-      else
-      {
-        list.addElement(label + "_" + (index++));
+        String label = anns[i].label;
+        if (!list.contains(label))
+        {
+          list.addElement(label);
+        }
+        else
+        {
+          list.addElement(label + "_" + (index++));
+        }
       }
     }
 
index b1e4d58..9ae14ca 100755 (executable)
@@ -101,6 +101,10 @@ public class UserColourScheme extends ResidueColourScheme
 
   public static Color getColourFromString(String colour)
   {
+    if (colour == null)
+    {
+      return null;
+    }
     colour = colour.trim();
 
     Color col = null;
@@ -136,7 +140,7 @@ public class UserColourScheme extends ResidueColourScheme
 
   }
 
-  public Color createColourFromName(String name)
+  public static Color createColourFromName(String name)
   {
     int r, g, b;
 
index 3fcb5e9..78634e0 100644 (file)
@@ -159,4 +159,14 @@ public class StructureMapping
     }
     return ala_copy;
   }
+
+  public String getMappingDetailsOutput()
+  {
+    return mappingDetails;
+  }
+
+  public HashMap<Integer, int[]> getMapping()
+  {
+    return mapping;
+  }
 }
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 fbd1622..eab4aa5 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
@@ -1411,6 +1413,39 @@ public abstract class AlignmentViewport implements AlignViewportI,
   }
 
   /**
+   * Hides the specified sequence, or the sequences it represents
+   * 
+   * @param sequence
+   *          the sequence to hide, or keep as representative
+   * @param representGroup
+   *          if true, hide the current selection group except for the
+   *          representative sequence
+   */
+  public void hideSequences(SequenceI sequence, boolean representGroup)
+  {
+    if (selectionGroup == null || selectionGroup.getSize() < 1)
+    {
+      hideSequence(new SequenceI[] { sequence });
+      return;
+    }
+
+    if (representGroup)
+    {
+      hideRepSequences(sequence, selectionGroup);
+      setSelectionGroup(null);
+      return;
+    }
+
+    int gsize = selectionGroup.getSize();
+    SequenceI[] hseqs = selectionGroup.getSequences().toArray(
+            new SequenceI[gsize]);
+
+    hideSequence(hseqs);
+    setSelectionGroup(null);
+    sendSelection();
+  }
+
+  /**
    * Set visibility for any annotations for the given sequence.
    * 
    * @param sequenceI
@@ -1418,11 +1453,15 @@ public abstract class AlignmentViewport implements AlignViewportI,
   protected void setSequenceAnnotationsVisible(SequenceI sequenceI,
           boolean visible)
   {
-    for (AlignmentAnnotation ann : alignment.getAlignmentAnnotation())
+    AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation();
+    if (anns != null)
     {
-      if (ann.sequenceRef == sequenceI)
+      for (AlignmentAnnotation ann : anns)
       {
-        ann.visible = visible;
+        if (ann.sequenceRef == sequenceI)
+        {
+          ann.visible = visible;
+        }
       }
     }
   }
@@ -1586,6 +1625,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;
@@ -1599,13 +1645,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
       {
@@ -2717,4 +2763,6 @@ public abstract class AlignmentViewport implements AlignViewportI,
       }
     }
   }
+
+
 }
index 848f565..a4e4348 100644 (file)
@@ -27,7 +27,8 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.seqfeatures.FeatureRenderer;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
+import jalview.schemes.UserColourScheme;
 import jalview.viewmodel.AlignmentViewport;
 
 import java.awt.Color;
@@ -52,28 +53,19 @@ public abstract class FeatureRendererModel implements
    */
   protected float transparency = 1.0f;
 
-  protected Map<String, Object> featureColours = new ConcurrentHashMap<String, Object>();
+  protected Map<String, FeatureColourI> featureColours = new ConcurrentHashMap<String, FeatureColourI>();
 
   protected Map<String, Boolean> featureGroups = new ConcurrentHashMap<String, Boolean>();
 
-  protected Object currentColour;
-
-  /*
-   * feature types in ordering of rendering, where last means on top
-   */
   protected String[] renderOrder;
 
+  Map<String, Float> featureOrder = null;
+
   protected PropertyChangeSupport changeSupport = new PropertyChangeSupport(
           this);
 
   protected AlignmentViewport av;
 
-  /*
-   * map holds per feature type, {{min, max}, {min, max}} feature score
-   * values for positional and non-positional features respectively
-   */
-  private Map<String, float[][]> minmax = new Hashtable<String, float[][]>();
-
   @Override
   public AlignViewportI getViewport()
   {
@@ -200,6 +192,8 @@ public abstract class FeatureRendererModel implements
     renderOrder = neworder;
   }
 
+  protected Map<String, float[][]> minmax = new Hashtable<String, float[][]>();
+
   public Map<String, float[][]> getMinMax()
   {
     return minmax;
@@ -449,7 +443,6 @@ public abstract class FeatureRendererModel implements
     List<String> allfeatures = new ArrayList<String>(allFeatures);
     String[] oldRender = renderOrder;
     renderOrder = new String[allfeatures.size()];
-    Object mmrange, fc = null;
     boolean initOrders = (featureOrder == null);
     int opos = 0;
     if (oldRender != null && oldRender.length > 0)
@@ -469,16 +462,13 @@ public abstract class FeatureRendererModel implements
             allfeatures.remove(oldRender[j]);
             if (minmax != null)
             {
-              mmrange = minmax.get(oldRender[j]);
+              float[][] mmrange = minmax.get(oldRender[j]);
               if (mmrange != null)
               {
-                fc = featureColours.get(oldRender[j]);
-                if (fc != null && fc instanceof GraduatedColor
-                        && ((GraduatedColor) fc).isAutoScale())
+                FeatureColourI fc = featureColours.get(oldRender[j]);
+                if (fc != null && !fc.isSimpleColour() && fc.isAutoScaled())
                 {
-                  ((GraduatedColor) fc).updateBounds(
-                          ((float[][]) mmrange)[0][0],
-                          ((float[][]) mmrange)[0][1]);
+                  fc.updateBounds(mmrange[0][0], mmrange[0][1]);
                 }
               }
             }
@@ -502,15 +492,13 @@ public abstract class FeatureRendererModel implements
       if (minmax != null)
       {
         // update from new features minmax if necessary
-        mmrange = minmax.get(newf[i]);
+        float[][] mmrange = minmax.get(newf[i]);
         if (mmrange != null)
         {
-          fc = featureColours.get(newf[i]);
-          if (fc != null && fc instanceof GraduatedColor
-                  && ((GraduatedColor) fc).isAutoScale())
+          FeatureColourI fc = featureColours.get(newf[i]);
+          if (fc != null && !fc.isSimpleColour() && fc.isAutoScaled())
           {
-            ((GraduatedColor) fc).updateBounds(((float[][]) mmrange)[0][0],
-                    ((float[][]) mmrange)[0][1]);
+            fc.updateBounds(mmrange[0][0], mmrange[0][1]);
           }
         }
       }
@@ -522,7 +510,7 @@ public abstract class FeatureRendererModel implements
         setOrder(newf[i], i / (float) denom);
       }
       // set order from newly found feature from persisted ordering.
-      sortOrder[i] = 2 - ((Float) featureOrder.get(newf[i])).floatValue();
+      sortOrder[i] = 2 - featureOrder.get(newf[i]).floatValue();
       if (i < iSize)
       {
         // only sort if we need to
@@ -540,52 +528,25 @@ public abstract class FeatureRendererModel implements
 
   /**
    * get a feature style object for the given type string. Creates a
-   * java.awt.Color for a featureType with no existing colourscheme. TODO:
-   * replace return type with object implementing standard abstract colour/style
-   * interface
+   * java.awt.Color for a featureType with no existing colourscheme.
    * 
    * @param featureType
-   * @return java.awt.Color or GraduatedColor
+   * @return
    */
   @Override
-  public Object getFeatureStyle(String featureType)
+  public FeatureColourI getFeatureStyle(String featureType)
   {
-    Object fc = featureColours.get(featureType);
+    FeatureColourI fc = featureColours.get(featureType);
     if (fc == null)
     {
-      jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme();
-      Color col = ucs.createColourFromName(featureType);
-      featureColours.put(featureType, fc = col);
+      Color col = UserColourScheme.createColourFromName(featureType);
+      fc = new FeatureColour(col);
+      featureColours.put(featureType, fc);
     }
     return fc;
   }
 
   /**
-   * 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.
    * 
@@ -594,33 +555,14 @@ public abstract class FeatureRendererModel implements
    */
   public Color getColour(SequenceFeature feature)
   {
-    Object fc = getFeatureStyle(feature.getType());
-    if (fc instanceof Color)
-    {
-      return (Color) fc;
-    }
-    else
-    {
-      if (fc instanceof GraduatedColor)
-      {
-        return ((GraduatedColor) fc).findColor(feature);
-      }
-    }
-    throw new Error("Implementation Error: Unrecognised render object "
-            + fc.getClass() + " for features of type " + feature.getType());
+    FeatureColourI fc = getFeatureStyle(feature.getType());
+    return fc.getColor(feature);
   }
 
   protected boolean showFeature(SequenceFeature sequenceFeature)
   {
-    Object fc = getFeatureStyle(sequenceFeature.type);
-    if (fc instanceof GraduatedColor)
-    {
-      return ((GraduatedColor) fc).isColored(sequenceFeature);
-    }
-    else
-    {
-      return true;
-    }
+    FeatureColourI fc = getFeatureStyle(sequenceFeature.type);
+    return fc.isColored(sequenceFeature);
   }
 
   protected boolean showFeatureOfType(String type)
@@ -629,26 +571,9 @@ public abstract class FeatureRendererModel implements
   }
 
   @Override
-  public void setColour(String featureType, Object col)
+  public void setColour(String featureType, FeatureColourI col)
   {
-    // overwrite
-    // Color _col = (col instanceof Color) ? ((Color) col) : (col instanceof
-    // GraduatedColor) ? ((GraduatedColor) col).getMaxColor() : null;
-    // Object c = featureColours.get(featureType);
-    // if (c == null || c instanceof Color || (c instanceof GraduatedColor &&
-    // !((GraduatedColor)c).getMaxColor().equals(_col)))
-    if (col instanceof FeatureColourI)
-    {
-      if (((FeatureColourI) col).isGraduatedColour())
-      {
-        col = new GraduatedColor((FeatureColourI) col);
-      }
-      else
-      {
-        col = ((FeatureColourI) col).getColour();
-      }
-    }
-      featureColours.put(featureType, col);
+     featureColours.put(featureType, col);
   }
 
   public void setTransparency(float value)
@@ -661,8 +586,6 @@ public abstract class FeatureRendererModel implements
     return transparency;
   }
 
-  Map featureOrder = null;
-
   /**
    * analogous to colour - store a normalized ordering for all feature types in
    * this rendering context.
@@ -677,7 +600,7 @@ public abstract class FeatureRendererModel implements
   {
     if (featureOrder == null)
     {
-      featureOrder = new Hashtable();
+      featureOrder = new Hashtable<String, Float>();
     }
     featureOrder.put(type, new Float(position));
     return position;
@@ -695,14 +618,14 @@ public abstract class FeatureRendererModel implements
     {
       if (featureOrder.containsKey(type))
       {
-        return ((Float) featureOrder.get(type)).floatValue();
+        return featureOrder.get(type).floatValue();
       }
     }
     return -1;
   }
 
   @Override
-  public Map<String, Object> getFeatureColours()
+  public Map<String, FeatureColourI> getFeatureColours()
   {
     return featureColours;
   }
@@ -735,7 +658,7 @@ public abstract class FeatureRendererModel implements
      * note visible feature ordering and colours before update
      */
     List<String> visibleFeatures = getDisplayedFeatureTypes();
-    Map<String, Object> visibleColours = new HashMap<String, Object>(
+    Map<String, FeatureColourI> visibleColours = new HashMap<String, FeatureColourI>(
             getFeatureColours());
 
     FeaturesDisplayedI av_featuresdisplayed = null;
@@ -768,8 +691,7 @@ public abstract class FeatureRendererModel implements
       for (int i = 0; i < data.length; i++)
       {
         String type = data[i][0].toString();
-        setColour(type, data[i][1]); // todo : typesafety - feature color
-        // interface object
+        setColour(type, (FeatureColourI) data[i][1]);
         if (((Boolean) data[i][2]).booleanValue())
         {
           av_featuresdisplayed.setVisible(type);
@@ -838,6 +760,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)
@@ -891,9 +816,9 @@ public abstract class FeatureRendererModel implements
   {
     if (featureGroups != null)
     {
-      ArrayList gp = new ArrayList();
+      List<String> gp = new ArrayList<String>();
 
-      for (Object grp : featureGroups.keySet())
+      for (String grp : featureGroups.keySet())
       {
         Boolean state = featureGroups.get(grp);
         if (state.booleanValue() == visible)
@@ -935,19 +860,19 @@ public abstract class FeatureRendererModel implements
   }
 
   @Override
-  public Hashtable getDisplayedFeatureCols()
+  public Map<String, FeatureColourI> getDisplayedFeatureCols()
   {
-    Hashtable fcols = new Hashtable();
+    Map<String, FeatureColourI> fcols = new Hashtable<String, FeatureColourI>();
     if (getViewport().getFeaturesDisplayed() == null)
     {
       return fcols;
     }
-    Iterator<String> en = getViewport().getFeaturesDisplayed()
+    Iterator<String> features = getViewport().getFeaturesDisplayed()
             .getVisibleFeatures();
-    while (en.hasNext())
+    while (features.hasNext())
     {
-      String col = en.next();
-      fcols.put(col, getColour(col));
+      String feature = features.next();
+      fcols.put(feature, getFeatureStyle(feature));
     }
     return fcols;
   }
index 1985b6d..dc2ae11 100644 (file)
  */
 package jalview.viewmodel.seqfeatures;
 
-import jalview.schemes.GraduatedColor;
+import jalview.api.FeatureColourI;
+import jalview.schemes.FeatureColour;
 
 import java.util.Arrays;
-import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -32,24 +32,33 @@ public class FeatureRendererSettings implements Cloneable
 {
   String[] renderOrder;
 
-  Map featureGroups;
+  /*
+   * map of {groupName, isDisplayed}
+   */
+  Map<String, Boolean> featureGroups;
 
-  Map featureColours;
+  /*
+   * map of {featureType, colourScheme}
+   */
+  Map<String, FeatureColourI> featureColours;
 
   float transparency;
 
-  Map featureOrder;
+  Map<String, Float> featureOrder;
 
   public FeatureRendererSettings(String[] renderOrder,
-          Hashtable featureGroups, Hashtable featureColours,
-          float transparency, Hashtable featureOrder)
+          Map<String, Boolean> featureGroups,
+          Map<String, FeatureColourI> featureColours, float transparency,
+          Map<String, Float> featureOrder)
   {
     super();
     this.renderOrder = Arrays.copyOf(renderOrder, renderOrder.length);
-    this.featureGroups = new ConcurrentHashMap(featureGroups);
-    this.featureColours = new ConcurrentHashMap(featureColours);
+    this.featureGroups = new ConcurrentHashMap<String, Boolean>(
+            featureGroups);
+    this.featureColours = new ConcurrentHashMap<String, FeatureColourI>(
+            featureColours);
     this.transparency = transparency;
-    this.featureOrder = new ConcurrentHashMap(featureOrder);
+    this.featureOrder = new ConcurrentHashMap<String, Float>(featureOrder);
   }
 
   /**
@@ -61,9 +70,9 @@ public class FeatureRendererSettings implements Cloneable
           jalview.viewmodel.seqfeatures.FeatureRendererModel fr)
   {
     renderOrder = null;
-    featureGroups = new ConcurrentHashMap();
-    featureColours = new ConcurrentHashMap();
-    featureOrder = new ConcurrentHashMap();
+    featureGroups = new ConcurrentHashMap<String, Boolean>();
+    featureColours = new ConcurrentHashMap<String, FeatureColourI>();
+    featureOrder = new ConcurrentHashMap<String, Float>();
     if (fr.renderOrder != null)
     {
       this.renderOrder = new String[fr.renderOrder.length];
@@ -72,26 +81,30 @@ public class FeatureRendererSettings implements Cloneable
     }
     if (fr.featureGroups != null)
     {
-      this.featureGroups = new ConcurrentHashMap(fr.featureGroups);
+      this.featureGroups = new ConcurrentHashMap<String, Boolean>(
+              fr.featureGroups);
     }
     if (fr.featureColours != null)
     {
-      this.featureColours = new ConcurrentHashMap(fr.featureColours);
+      this.featureColours = new ConcurrentHashMap<String, FeatureColourI>(
+              fr.featureColours);
     }
-    Iterator en = fr.featureColours.keySet().iterator();
+    Iterator<String> en = fr.featureColours.keySet().iterator();
     while (en.hasNext())
     {
-      Object next = en.next();
-      Object val = featureColours.get(next);
-      if (val instanceof GraduatedColor)
+      String next = en.next();
+      FeatureColourI val = featureColours.get(next);
+      // if (val instanceof GraduatedColor)
+      if (val.isGraduatedColour() || val.isColourByLabel()) // why this test?
       {
-        featureColours.put(next, new GraduatedColor((GraduatedColor) val));
+        featureColours.put(next, new FeatureColour((FeatureColour) val));
       }
     }
     this.transparency = fr.transparency;
     if (fr.featureOrder != null)
     {
-      this.featureOrder = new ConcurrentHashMap(fr.featureOrder);
+      this.featureOrder = new ConcurrentHashMap<String, Float>(
+              fr.featureOrder);
     }
   }
 }
index 37f3ca5..520b232 100644 (file)
@@ -1,9 +1,9 @@
 package jalview.workers;
 
+import jalview.bin.Jalview;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.gui.AlignFrame;
-import jalview.gui.Desktop;
 
 import java.awt.Color;
 
@@ -28,9 +28,9 @@ public class AlignmentAnnotationFactory
    */
   public static void newCalculator(FeatureCounterI counter)
   {
-    if (Desktop.getCurrentAlignFrame() != null)
+    if (Jalview.getCurrentAlignFrame() != null)
     {
-      newCalculator(Desktop.getCurrentAlignFrame(), counter);
+      newCalculator(Jalview.getCurrentAlignFrame(), counter);
     }
     else
     {
@@ -60,9 +60,9 @@ public class AlignmentAnnotationFactory
    */
   public static void newCalculator(AnnotationProviderI calculator)
   {
-    if (Desktop.getCurrentAlignFrame() != null)
+    if (Jalview.getCurrentAlignFrame() != null)
     {
-      newCalculator(Desktop.getCurrentAlignFrame(), calculator);
+      newCalculator(Jalview.getCurrentAlignFrame(), calculator);
     }
     else
     {
index 3483dac..4249112 100644 (file)
@@ -94,12 +94,15 @@ public class StrucConsensusThread extends AlignCalcWorker
               .getAlignmentAnnotation();
       AlignmentAnnotation rnaStruc = null;
       // select rna struct to use for calculation
-      for (int i = 0; i < aa.length; i++)
+      if (aa != null)
       {
-        if (aa[i].visible && aa[i].isRNA() && aa[i].isValidStruc())
+        for (int i = 0; i < aa.length; i++)
         {
-          rnaStruc = aa[i];
-          break;
+          if (aa[i].visible && aa[i].isRNA() && aa[i].isValidStruc())
+          {
+            rnaStruc = aa[i];
+            break;
+          }
         }
       }
       // check to see if its valid
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 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 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 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 b2e9b35..66fddd1 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.ws.jws1;
 
 import jalview.analysis.AlignSeq;
+import jalview.api.FeatureColourI;
 import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentView;
@@ -172,7 +173,7 @@ class SeqSearchWSThread extends JWS1Thread implements WSClientI
      * @return null or { Alignment(+features and annotation), NewickFile)}
      */
     public Object[] getAlignment(Alignment dataset,
-            Map<String, Object> featureColours)
+            Map<String, FeatureColourI> featureColours)
     {
 
       if (result != null && result.isFinished())
@@ -622,7 +623,7 @@ class SeqSearchWSThread extends JWS1Thread implements WSClientI
     // NewickFile nf[] = new NewickFile[jobs.length];
     for (int j = 0; j < jobs.length; j++)
     {
-      Map<String, Object> featureColours = new HashMap<String, Object>();
+      Map<String, FeatureColourI> featureColours = new HashMap<String, FeatureColourI>();
       Alignment al = null;
       NewickFile nf = null;
       if (jobs[j].hasResults())
index f4b1c31..0cf76e0 100644 (file)
  */
 package jalview.ws.jws2;
 
+import jalview.api.AlignCalcWorkerI;
+import jalview.api.FeatureColourI;
 import jalview.bin.Cache;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.GraphLine;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
 import jalview.schemes.UserColourScheme;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.params.WsParamSetI;
@@ -306,8 +308,8 @@ public class AADisorderClient extends JabawsCalcWorker
                 annot.description += "<br/>" + threshNote;
               }
               annot.description += "</html>";
-              Color col = new UserColourScheme(typeName)
-                      .createColourFromName(typeName + scr.getMethod());
+              Color col = UserColourScheme.createColourFromName(typeName
+                      + scr.getMethod());
               for (int p = 0, ps = annot.annotations.length; p < ps; p++)
               {
                 if (annot.annotations[p] != null)
@@ -335,13 +337,13 @@ public class AADisorderClient extends JabawsCalcWorker
                   .cloneFeatureRenderer();
           for (String ft : fc.keySet())
           {
-            Object gc = fr.getFeatureStyle(ft);
-            if (gc instanceof Color)
+            FeatureColourI gc = fr.getFeatureStyle(ft);
+            if (gc.isSimpleColour())
             {
               // set graduated color as fading to white for minimum, and
               // autoscaling to values on alignment
-              GraduatedColor ggc = new GraduatedColor(Color.white,
-                      (Color) gc, Float.MIN_VALUE, Float.MAX_VALUE);
+              FeatureColourI ggc = new FeatureColour(Color.white,
+                      gc.getColour(), Float.MIN_VALUE, Float.MAX_VALUE);
               ggc.setAutoScaled(true);
               fr.setColour(ft, ggc);
             }
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 c06e51f..aa65f49 100644 (file)
@@ -20,8 +20,6 @@ public class MappingOutputPojo
 
   private String type;
 
-  private int wrapHeight;
-
   private static final int MAX_ID_LENGTH = 30;
 
   public String getSeqName()
@@ -116,14 +114,5 @@ public class MappingOutputPojo
     this.type = type;
   }
 
-  public int getWrapHeight()
-  {
-    return wrapHeight;
-  }
-
-  public void setWrapHeight(int wrapHeight)
-  {
-    this.wrapHeight = wrapHeight;
-  }
 
 }
index e04bbb7..a88bacb 100644 (file)
@@ -37,11 +37,9 @@ import jalview.xml.binding.sifts.Entry.Entity.Segment.ListMapRegion.MapRegion;
 import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue;
 import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue.CrossRefDb;
 import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue.ResidueDetail;
-import jalview.xml.binding.sifts.Entry.ListDB.Db;
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -59,20 +57,18 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.TreeMap;
 import java.util.zip.GZIPInputStream;
 
 import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
 import javax.xml.bind.Unmarshaller;
-import javax.xml.stream.FactoryConfigurationError;
 import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 
 import MCview.Atom;
 import MCview.PDBChain;
-import MCview.PDBfile;
 
 public class SiftsClient implements SiftsClientI
 {
@@ -84,8 +80,6 @@ public class SiftsClient implements SiftsClientI
 
   private String structId;
 
-  private String segStartEnd;
-
   private CoordinateSys seqCoordSys = CoordinateSys.UNIPROT;
 
   private static final int BUFFER_SIZE = 4096;
@@ -96,11 +90,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();
 
@@ -108,7 +100,7 @@ public class SiftsClient implements SiftsClientI
 
   private HashSet<String> curDBRefAccessionIdsString;
 
-  public enum CoordinateSys
+  private enum CoordinateSys
   {
     UNIPROT("UniProt"), PDB("PDBresnum"), PDBe("PDBe");
     private String name;
@@ -124,7 +116,7 @@ public class SiftsClient implements SiftsClientI
     }
   };
 
-  public enum ResidueDetailType
+  private enum ResidueDetailType
   {
     NAME_SEC_STRUCTURE("nameSecondaryStructure"), CODE_SEC_STRUCTURE(
             "codeSecondaryStructure"), ANNOTATION("Annotation");
@@ -156,21 +148,6 @@ public class SiftsClient implements SiftsClientI
     siftsEntry = parseSIFTs(siftsFile);
   }
 
-  /**
-   * Construct an instance of SiftsClient using the supplied SIFTs file. Note:
-   * The SIFTs file should correspond to the PDB Id in PDBfile instance
-   * 
-   * @param pdbId
-   * @param siftsFile
-   * @throws SiftsException
-   * @throws Exception
-   */
-  public SiftsClient(PDBfile pdb, File siftsFile) throws SiftsException
-  {
-    this.pdb = pdb;
-    this.pdbId = pdb.getId();
-    siftsEntry = parseSIFTs(siftsFile);
-  }
 
   /**
    * Parse the given SIFTs File and return a JAXB POJO of parsed data
@@ -192,23 +169,7 @@ public class SiftsClient implements SiftsClientI
               .createXMLStreamReader(gzis);
       Unmarshaller um = jc.createUnmarshaller();
       return (Entry) um.unmarshal(streamReader);
-    } catch (JAXBException e)
-    {
-      e.printStackTrace();
-      throw new SiftsException(e.getMessage());
-    } catch (FileNotFoundException e)
-    {
-      e.printStackTrace();
-      throw new SiftsException(e.getMessage());
-    } catch (XMLStreamException e)
-    {
-      e.printStackTrace();
-      throw new SiftsException(e.getMessage());
-    } catch (FactoryConfigurationError e)
-    {
-      e.printStackTrace();
-      throw new SiftsException(e.getMessage());
-    } catch (IOException e)
+    } catch (Exception e)
     {
       e.printStackTrace();
       throw new SiftsException(e.getMessage());
@@ -225,8 +186,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 +197,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 +256,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 +275,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 +290,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 +334,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 +349,7 @@ public class SiftsClient implements SiftsClientI
                 && (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT) || dbRef
                         .getSource().equalsIgnoreCase(DBRefSource.PDB)))
         {
+          seq.setSourceDBRef(dbRef);
           return dbRef;
         }
       }
@@ -393,7 +369,7 @@ public class SiftsClient implements SiftsClientI
    *          - DBRefEntry to validate
    * @return true validation is successful otherwise false is returned.
    */
-  private boolean isValidDBRefEntry(DBRefEntryI entry)
+  boolean isValidDBRefEntry(DBRefEntryI entry)
   {
     return entry != null && entry.getAccessionId() != null
             && isFoundInSiftsEntry(entry.getAccessionId());
@@ -413,7 +389,8 @@ public class SiftsClient implements SiftsClientI
                 .getMapRegion();
         for (MapRegion mapRegion : mapRegions)
         {
-          accessions.add(mapRegion.getDb().getDbAccessionId());
+          accessions
+                  .add(mapRegion.getDb().getDbAccessionId().toLowerCase());
         }
       }
     }
@@ -455,7 +432,7 @@ public class SiftsClient implements SiftsClientI
   public HashMap<Integer, int[]> getGreedyMapping(String entityId,
           SequenceI seq, java.io.PrintStream os) throws SiftsException
   {
-    ArrayList<Integer> omitNonObserved = new ArrayList<Integer>();
+    List<Integer> omitNonObserved = new ArrayList<Integer>();
     int nonObservedShiftIndex = 0;
     // System.out.println("Generating mappings for : " + entityId);
     Entity entity = null;
@@ -464,12 +441,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))
@@ -489,10 +463,91 @@ public class SiftsClient implements SiftsClientI
 
     TreeMap<Integer, String> resNumMap = new TreeMap<Integer, String>();
     List<Segment> segments = entity.getSegment();
+    SegmentHelperPojo shp = new SegmentHelperPojo(seq, mapping, resNumMap,
+            omitNonObserved, nonObservedShiftIndex);
+    processSegments(segments, shp);
+    try
+    {
+      populateAtomPositions(entityId, mapping);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    if (seqCoordSys == CoordinateSys.UNIPROT)
+    {
+      padWithGaps(resNumMap, omitNonObserved);
+    }
+    int seqStart = UNASSIGNED;
+    int seqEnd = UNASSIGNED;
+    int pdbStart = UNASSIGNED;
+    int pdbEnd = UNASSIGNED;
+
+    Integer[] keys = mapping.keySet().toArray(new Integer[0]);
+    Arrays.sort(keys);
+    if (keys.length < 1)
+    {
+      throw new SiftsException(">>> Empty SIFTS mapping generated!!");
+    }
+    seqStart = keys[0];
+    seqEnd = keys[keys.length - 1];
+
+    String matchedSeq = originalSeq;
+    if (seqStart != UNASSIGNED)
+    {
+      pdbStart = mapping.get(seqStart)[PDB_RES_POS];
+      pdbEnd = mapping.get(seqEnd)[PDB_RES_POS];
+      int orignalSeqStart = seq.getStart();
+      if (orignalSeqStart >= 1)
+      {
+        int subSeqStart = (seqStart >= orignalSeqStart) ? seqStart
+                - orignalSeqStart : 0;
+        int subSeqEnd = seqEnd - (orignalSeqStart - 1);
+        subSeqEnd = originalSeq.length() < subSeqEnd ? originalSeq.length()
+                : subSeqEnd;
+        matchedSeq = originalSeq.substring(subSeqStart, subSeqEnd);
+      }
+      else
+      {
+        matchedSeq = originalSeq.substring(1, originalSeq.length());
+      }
+    }
+
+    StringBuilder targetStrucSeqs = new StringBuilder();
+    for (String res : resNumMap.values())
+    {
+      targetStrucSeqs.append(res);
+    }
+
+    if (os != null)
+    {
+      MappingOutputPojo mop = new MappingOutputPojo();
+      mop.setSeqStart(pdbStart);
+      mop.setSeqEnd(pdbEnd);
+      mop.setSeqName(seq.getName());
+      mop.setSeqResidue(matchedSeq);
+
+      mop.setStrStart(seqStart);
+      mop.setStrEnd(seqEnd);
+      mop.setStrName(structId);
+      mop.setStrResidue(targetStrucSeqs.toString());
+
+      mop.setType("pep");
+      os.print(getMappingOutput(mop).toString());
+      os.println();
+    }
+    return mapping;
+  }
+
+  void processSegments(List<Segment> segments, SegmentHelperPojo shp)
+  {
+    SequenceI seq = shp.getSeq();
+    HashMap<Integer, int[]> mapping = shp.getMapping();
+    TreeMap<Integer, String> resNumMap = shp.getResNumMap();
+    List<Integer> omitNonObserved = shp.getOmitNonObserved();
+    int nonObservedShiftIndex = shp.getNonObservedShiftIndex();
     for (Segment segment : segments)
     {
-      segStartEnd = segment.getStart() + " - " + segment.getEnd();
-      // System.out.println("Mapping segments : " + segment.getSegId() + "\\"
+      // System.out.println("Mapping segments : " + segment.getSegId() + "\\"s
       // + segStartEnd);
       List<Residue> residues = segment.getListResidue().getResidue();
       for (Residue residue : residues)
@@ -566,77 +621,7 @@ public class SiftsClient implements SiftsClientI
         }
       }
     }
-    try
-    {
-      populateAtomPositions(entityId, mapping);
-    } catch (Exception e)
-    {
-      e.printStackTrace();
-    }
-    if (seqCoordSys == CoordinateSys.UNIPROT)
-    {
-      padWithGaps(resNumMap, omitNonObserved);
-    }
-    int seqStart = UNASSIGNED;
-    int seqEnd = UNASSIGNED;
-    int pdbStart = UNASSIGNED;
-    int pdbEnd = UNASSIGNED;
-
-    Integer[] keys = mapping.keySet().toArray(new Integer[0]);
-    Arrays.sort(keys);
-    if (keys.length < 1)
-    {
-      throw new SiftsException(">>> Empty SIFTS mapping generated!!");
-    }
-    seqStart = keys[0];
-    seqEnd = keys[keys.length - 1];
-
-    String matchedSeq = originalSeq;
-    if (seqStart != UNASSIGNED)
-    {
-      pdbStart = mapping.get(seqStart)[PDB_RES_POS];
-      pdbEnd = mapping.get(seqEnd)[PDB_RES_POS];
-      int orignalSeqStart = seq.getStart();
-      if (orignalSeqStart >= 1)
-      {
-        int subSeqStart = (seqStart >= orignalSeqStart) ? seqStart
-                - orignalSeqStart : 0;
-        int subSeqEnd = seqEnd - (orignalSeqStart - 1);
-        subSeqEnd = originalSeq.length() < subSeqEnd ? originalSeq.length()
-                : subSeqEnd;
-        matchedSeq = originalSeq.substring(subSeqStart, subSeqEnd);
-      }
-      else
-      {
-        matchedSeq = originalSeq.substring(1, originalSeq.length());
-      }
-    }
-
-    StringBuilder targetStrucSeqs = new StringBuilder();
-    for (String res : resNumMap.values())
-    {
-      targetStrucSeqs.append(res);
-    }
-
-    if (os != null)
-    {
-      MappingOutputPojo mop = new MappingOutputPojo();
-      mop.setSeqStart(pdbStart);
-      mop.setSeqEnd(pdbEnd);
-      mop.setSeqName(seq.getName());
-      mop.setSeqResidue(matchedSeq);
-
-      mop.setStrStart(seqStart);
-      mop.setStrEnd(seqEnd);
-      mop.setStrName(structId);
-      mop.setStrResidue(targetStrucSeqs.toString());
-
-      mop.setType("pep");
-      os.print(getMappingOutput(mop).toString());
-    }
-    return mapping;
   }
-
   /**
    * 
    * @param chainId
@@ -645,9 +630,10 @@ public class SiftsClient implements SiftsClientI
    *          Two dimension array of residue index versus atom position
    * @throws IllegalArgumentException
    *           Thrown if chainId or mapping is null
+   * @throws SiftsException
    */
-  void populateAtomPositions(String chainId,
-          HashMap<Integer, int[]> mapping) throws IllegalArgumentException
+  void populateAtomPositions(String chainId, Map<Integer, int[]> mapping)
+          throws IllegalArgumentException, SiftsException
   {
     try
     {
@@ -665,9 +651,12 @@ public class SiftsClient implements SiftsClientI
           map[PDB_ATOM_POS] = getAtomIndex(map[PDB_RES_POS], chain.atoms);
         }
       }
+    } catch (NullPointerException e)
+    {
+      throw new SiftsException(e.getMessage());
     } catch (Exception e)
     {
-      e.printStackTrace();
+      throw new SiftsException(e.getMessage());
     }
   }
 
@@ -704,7 +693,7 @@ public class SiftsClient implements SiftsClientI
    */
   private boolean isResidueObserved(Residue residue)
   {
-    HashSet<String> annotations = getResidueAnnotaitons(residue,
+    Set<String> annotations = getResidueAnnotaitons(residue,
             ResidueDetailType.ANNOTATION);
     if (annotations == null || annotations.isEmpty())
     {
@@ -727,7 +716,7 @@ public class SiftsClient implements SiftsClientI
    * @param type
    * @return
    */
-  private HashSet<String> getResidueAnnotaitons(Residue residue,
+  private Set<String> getResidueAnnotaitons(Residue residue,
           ResidueDetailType type)
   {
     HashSet<String> foundAnnotations = new HashSet<String>();
@@ -752,8 +741,9 @@ public class SiftsClient implements SiftsClientI
 
   private boolean isFoundInSiftsEntry(String accessionId)
   {
+    Set<String> siftsDBRefs = getAllMappingAccession();
     return accessionId != null
-            && getAllMappingAccession().contains(accessionId);
+            && siftsDBRefs.contains(accessionId.toLowerCase());
   }
 
   /**
@@ -761,15 +751,15 @@ public class SiftsClient implements SiftsClientI
    * 
    * @param resNumMap
    */
-  void padWithGaps(TreeMap<Integer, String> resNumMap,
-          ArrayList<Integer> omitNonObserved)
+  void padWithGaps(Map<Integer, String> resNumMap,
+          List<Integer> omitNonObserved)
   {
     if (resNumMap == null || resNumMap.isEmpty())
     {
       return;
     }
     Integer[] keys = resNumMap.keySet().toArray(new Integer[0]);
-    Arrays.sort(keys);
+    // Arrays.sort(keys);
     int firstIndex = keys[0];
     int lastIndex = keys[keys.length - 1];
     // System.out.println("Min value " + firstIndex);
@@ -788,28 +778,8 @@ public class SiftsClient implements SiftsClientI
   @Override
   public Entity getEntityById(String id) throws SiftsException
   {
-    // Sometimes SIFTS mappings are wrongly swapped between different chains of
-    // a PDB entry. This results to wrong mappings being generated. The boolean
-    // flag 'isGetEntityIdDirectly, determines whether an entity to process is
-    // determined by a greedy heuristic search or by just matching the Chain Id
-    // directly against the entity Id tag. Setting the default value to 'false'
-    // utilise the heuristic search which always produces correct mappings but
-    // less optimised processing, where as changing the value to 'true'
-    // optimises performance but might result to incorrect mapping in some cases
-    // where SIFTS mappings are wrongly swapped between different chains.
-    boolean isGetEntityIdDirectly = false;
-    if (isGetEntityIdDirectly)
-    {
-      List<Entity> entities = siftsEntry.getEntity();
-      for (Entity entity : entities)
-      {
-        if (!entity.getEntityId().equalsIgnoreCase(id))
-        {
-          continue;
-        }
-        return entity;
-      }
-    }
+    // Determines an entity to process by performing a heuristic matching of all
+    // Entities with the given chainId and choosing the best matching Entity
     Entity entity = getEntityByMostOptimalMatchedId(id);
     if (entity != null)
     {
@@ -879,7 +849,7 @@ public class SiftsClient implements SiftsClientI
     return null;
   }
 
-  public class SiftsEntitySortPojo implements
+  private class SiftsEntitySortPojo implements
           Comparable<SiftsEntitySortPojo>
   {
     public String entityId;
@@ -897,18 +867,79 @@ public class SiftsClient implements SiftsClientI
     }
   }
 
-  @Override
-  public String[] getEntryDBs()
+  private class SegmentHelperPojo
   {
-    System.out.println("\nListing DB entries...");
-    List<String> availDbs = new ArrayList<String>();
-    List<Db> dbs = siftsEntry.getListDB().getDb();
-    for (Db db : dbs)
+    private SequenceI seq;
+
+    private HashMap<Integer, int[]> mapping;
+
+    private TreeMap<Integer, String> resNumMap;
+
+    private List<Integer> omitNonObserved;
+
+    private int nonObservedShiftIndex;
+
+    public SegmentHelperPojo(SequenceI seq,
+            HashMap<Integer, int[]> mapping,
+            TreeMap<Integer, String> resNumMap,
+            List<Integer> omitNonObserved, int nonObservedShiftIndex)
+    {
+      setSeq(seq);
+      setMapping(mapping);
+      setResNumMap(resNumMap);
+      setOmitNonObserved(omitNonObserved);
+      setNonObservedShiftIndex(nonObservedShiftIndex);
+    }
+
+    public SequenceI getSeq()
+    {
+      return seq;
+    }
+
+    public void setSeq(SequenceI seq)
+    {
+      this.seq = seq;
+    }
+
+    public HashMap<Integer, int[]> getMapping()
+    {
+      return mapping;
+    }
+
+    public void setMapping(HashMap<Integer, int[]> mapping)
+    {
+      this.mapping = mapping;
+    }
+
+    public TreeMap<Integer, String> getResNumMap()
+    {
+      return resNumMap;
+    }
+
+    public void setResNumMap(TreeMap<Integer, String> resNumMap)
+    {
+      this.resNumMap = resNumMap;
+    }
+
+    public List<Integer> getOmitNonObserved()
+    {
+      return omitNonObserved;
+    }
+
+    public void setOmitNonObserved(List<Integer> omitNonObserved)
     {
-      availDbs.add(db.getDbSource());
-      System.out.println(db.getDbSource() + " | " + db.getDbCoordSys());
+      this.omitNonObserved = omitNonObserved;
+    }
+
+    public int getNonObservedShiftIndex()
+    {
+      return nonObservedShiftIndex;
+    }
+
+    public void setNonObservedShiftIndex(int nonObservedShiftIndex)
+    {
+      this.nonObservedShiftIndex = nonObservedShiftIndex;
     }
-    return availDbs.toArray(new String[0]);
   }
 
   @Override
@@ -1031,7 +1062,6 @@ public class SiftsClient implements SiftsClientI
     output.append("Length of alignment = " + seqRes.length()).append(
             NEWLINE);
     output.append(new Format("Percentage ID = %2.2f").form(pid));
-    output.append(NEWLINE);
     return output;
   }
 
@@ -1054,12 +1084,6 @@ public class SiftsClient implements SiftsClientI
   }
 
   @Override
-  public String getDbEvidence()
-  {
-    return siftsEntry.getDbEvidence();
-  }
-
-  @Override
   public String getDbSource()
   {
     return siftsEntry.getDbSource();
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 63f80b2..1a7ae32 100644 (file)
@@ -155,6 +155,21 @@ public class ColumnSelectionTest
 
   }
 
+  @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()
   {
@@ -463,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());
+  }
 }
diff --git a/test/jalview/datamodel/HiddenSequencesTest.java b/test/jalview/datamodel/HiddenSequencesTest.java
new file mode 100644 (file)
index 0000000..8b50a8b
--- /dev/null
@@ -0,0 +1,378 @@
+package jalview.datamodel;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertNotSame;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertSame;
+import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
+
+import jalview.gui.AlignViewport;
+
+import java.util.List;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+@Test(singleThreaded = true)
+public class HiddenSequencesTest
+{
+  static int SEQ_COUNT = 10;
+
+  SequenceI[] seqs;
+  
+  /**
+   * Set up an alignment of 10 sequences
+   */
+  @BeforeTest(alwaysRun = true)
+  public void setUp()
+  {
+    seqs = new SequenceI[SEQ_COUNT];
+    for (int i = 0; i < SEQ_COUNT; i++)
+    {
+      // sequence lengths are 1, 2, ... 10
+      seqs[i] = new Sequence("Seq" + i, "abcdefghijk".substring(0, i + 1));
+    }
+  }
+
+  /**
+   * Test the method that converts sequence alignment index to what it would be
+   * if all sequences were unhidden
+   */
+  @Test(groups = "Functional")
+  public void testAdjustForHiddenSeqs()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    for (int i = 0; i < SEQ_COUNT; i++)
+    {
+      assertEquals(i, hs.adjustForHiddenSeqs(i));
+    }
+
+    // hide seq1 and seq5 and seq6
+    hs.hideSequence(seqs[1]);
+    hs.hideSequence(seqs[5]);
+    hs.hideSequence(seqs[6]);
+
+    /*
+     * alignment is now seq0/2/3/4/7/8/9
+     */
+    assertEquals(7, al.getHeight());
+    assertEquals(0, hs.adjustForHiddenSeqs(0));
+    assertEquals(2, hs.adjustForHiddenSeqs(1));
+    assertEquals(3, hs.adjustForHiddenSeqs(2));
+    assertEquals(4, hs.adjustForHiddenSeqs(3));
+    assertEquals(7, hs.adjustForHiddenSeqs(4));
+    assertEquals(8, hs.adjustForHiddenSeqs(5));
+    assertEquals(9, hs.adjustForHiddenSeqs(6));
+  }
+
+  /**
+   * Test the method that increments the internal array size if a sequence is
+   * added to the alignment (ugh this should not be exposed to the light of day)
+   */
+  @Test(groups = "Functional")
+  public void testAdjustHeightSequenceAdded()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertEquals(SEQ_COUNT, al.getHeight());
+
+    HiddenSequences hs = al.getHiddenSequences();
+    // initially does nothing
+    hs.adjustHeightSequenceAdded();
+    assertNull(hs.hiddenSequences);
+
+    // hide one sequence
+    hs.hideSequence(seqs[3]);
+    assertEquals(1, hs.getSize());
+    assertEquals(SEQ_COUNT - 1, al.getHeight());
+    assertEquals(SEQ_COUNT, hs.hiddenSequences.length);
+
+    /*
+     * add a sequence to the alignment
+     * - the safe way to call hs.adjustHeightSequenceAdded!
+     * (implementation depends on alignment height having
+     * been already updated for the added sequence)
+     */
+    al.addSequence(new Sequence("a", "b"));
+    assertEquals(1, hs.getSize());
+    assertEquals(SEQ_COUNT, al.getHeight());
+    assertEquals(SEQ_COUNT + 1, hs.hiddenSequences.length);
+  }
+
+  /**
+   * Test the method that decrements the internal array size if a sequence is
+   * deleted from the alignment (ugh this should not be exposed to the light of
+   * day)
+   */
+  @Test(groups = "Functional")
+  public void testAdjustHeightSequenceDeleted()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertEquals(SEQ_COUNT, al.getHeight());
+
+    HiddenSequences hs = al.getHiddenSequences();
+    // initially does nothing
+    hs.adjustHeightSequenceAdded();
+    assertNull(hs.hiddenSequences);
+
+    // hide two sequences
+    hs.hideSequence(seqs[3]);
+    hs.hideSequence(seqs[5]);
+    assertEquals(2, hs.getSize());
+    assertTrue(hs.isHidden(seqs[3]));
+    assertTrue(hs.isHidden(seqs[5]));
+    assertEquals(SEQ_COUNT - 2, al.getHeight());
+    assertEquals(SEQ_COUNT, hs.hiddenSequences.length);
+
+    /*
+     * delete a visible sequence from the alignment
+     * - the safe way to call hs.adjustHeightSequenceDeleted!
+     * (implementation depends on alignment height having
+     * been already updated for the removed sequence)
+     */
+    al.deleteSequence(seqs[2]);
+    assertEquals(2, hs.getSize());
+    // the visible alignment is unchanged:
+    assertEquals(SEQ_COUNT - 3, al.getHeight());
+    // sequences array size has decremented:
+    assertEquals(SEQ_COUNT - 1, hs.hiddenSequences.length);
+  }
+
+  /**
+   * Test the method that converts a 'full alignment' sequence index into the
+   * equivalent in the alignment with sequences hidden
+   */
+  @Test(groups = "Functional")
+  public void testFindIndexWithoutHiddenSeqs()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    for (int i = 0; i < SEQ_COUNT; i++)
+    {
+      assertEquals(i, hs.findIndexWithoutHiddenSeqs(i));
+    }
+
+    // hide seq1 and seq5 and seq6
+    hs.hideSequence(seqs[1]);
+    hs.hideSequence(seqs[5]);
+    hs.hideSequence(seqs[6]);
+
+    /*
+     * alignment is now seq0/2/3/4/7/8/9
+     */
+    assertEquals(7, al.getHeight());
+    assertEquals(0, hs.findIndexWithoutHiddenSeqs(0));
+    assertEquals(0, hs.findIndexWithoutHiddenSeqs(1));
+    assertEquals(1, hs.findIndexWithoutHiddenSeqs(2));
+    assertEquals(2, hs.findIndexWithoutHiddenSeqs(3));
+    assertEquals(3, hs.findIndexWithoutHiddenSeqs(4));
+    assertEquals(3, hs.findIndexWithoutHiddenSeqs(5));
+    assertEquals(3, hs.findIndexWithoutHiddenSeqs(6));
+    assertEquals(4, hs.findIndexWithoutHiddenSeqs(7));
+    assertEquals(5, hs.findIndexWithoutHiddenSeqs(8));
+    assertEquals(6, hs.findIndexWithoutHiddenSeqs(9));
+  }
+
+  /**
+   * Test the method that reconstructs (sort of) the full alignment including
+   * hidden sequences
+   */
+  @Test(groups = "Functional")
+  public void testGetFullAlignment()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertArrayEquals(seqs, al.getSequencesArray());
+    al.setProperty("a", "b");
+    al.addAnnotation(new AlignmentAnnotation("ann", "label", 12f));
+    al.setSeqrep(seqs[4]);
+    SequenceGroup sg = new SequenceGroup();
+    sg.addSequence(seqs[8], false);
+    al.addGroup(sg);
+    ((Alignment) al).hasRNAStructure = true;
+
+    HiddenSequences hs = al.getHiddenSequences();
+    AlignmentI al2 = hs.getFullAlignment();
+    // new alignment but with original sequences
+    assertNotSame(al, al2);
+    assertArrayEquals(al.getSequencesArray(), al2.getSequencesArray());
+
+    hs.hideSequence(seqs[4]);
+    hs.hideSequence(seqs[9]);
+    al2 = hs.getFullAlignment();
+    assertNotSame(al, al2);
+    assertArrayEquals(seqs, al2.getSequencesArray());
+    assertNotNull(al2.getProperties());
+    assertSame(al.getProperties(), al2.getProperties());
+    assertNotNull(al2.getAlignmentAnnotation());
+    assertSame(al.getAlignmentAnnotation(), al2.getAlignmentAnnotation());
+    assertSame(seqs[4], al2.getSeqrep());
+    assertNotNull(al2.getGroups());
+    assertSame(al.getGroups(), al2.getGroups());
+    assertTrue(al2.hasRNAStructure());
+  }
+
+  /**
+   * Test the method that returns the hidden sequence at a given index in the
+   * full alignment
+   * 
+   * @return either the sequence (if hidden) or null (if not hidden)
+   */
+  @Test(groups = "Functional")
+  public void testGetHiddenSequence()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    assertNull(hs.getHiddenSequence(0));
+    hs.hideSequence(seqs[3]);
+    assertSame(seqs[3], hs.getHiddenSequence(3));
+    assertNull(hs.getHiddenSequence(2));
+    assertNull(hs.getHiddenSequence(4));
+  }
+
+  @Test(groups = "Functional")
+  public void testGetSize()
+  {
+  }
+
+  @Test(groups = "Functional")
+  public void testGetWidth()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    assertEquals(0, hs.getWidth());
+    hs.hideSequence(seqs[6]);
+    hs.hideSequence(seqs[8]);
+    assertEquals(9, hs.getWidth());
+  }
+
+  /**
+   * Test the method that adds a sequence to the hidden sequences and deletes it
+   * from the alignment, and its converse
+   */
+  @Test(groups = "Functional")
+  public void testHideShowSequence()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertTrue(al.getSequences().contains(seqs[1]));
+    HiddenSequences hs = al.getHiddenSequences();
+    assertEquals(0, hs.getSize());
+    assertEquals(10, al.getHeight());
+
+    /*
+     * hide the second sequence in the alignment
+     */
+    hs.hideSequence(seqs[1]);
+    assertFalse(hs.isHidden(seqs[0]));
+    assertTrue(hs.isHidden(seqs[1]));
+    assertFalse(al.getSequences().contains(seqs[1]));
+    assertEquals(1, hs.getSize());
+    assertEquals(9, al.getHeight());
+    assertSame(seqs[2], al.getSequenceAt(1));
+
+    /*
+     * hide what is now the second sequence in the alignment
+     */
+    hs.hideSequence(seqs[2]);
+    assertFalse(hs.isHidden(seqs[0]));
+    assertTrue(hs.isHidden(seqs[1]));
+    assertTrue(hs.isHidden(seqs[2]));
+    assertFalse(al.getSequences().contains(seqs[1]));
+    assertFalse(al.getSequences().contains(seqs[2]));
+    assertEquals(2, hs.getSize());
+    assertEquals(8, al.getHeight());
+
+    /*
+     * perform 'reveal' on what is now the second sequence in the alignment
+     * this should unhide the two sequences that precede it
+     */
+    List<SequenceI> revealed = hs.showSequence(1, null);
+    assertEquals(2, revealed.size());
+    assertTrue(revealed.contains(seqs[1]));
+    assertTrue(revealed.contains(seqs[2]));
+    assertEquals(0, hs.getSize());
+    assertEquals(10, al.getHeight());
+  }
+
+  @Test(groups = "Functional")
+  public void testIsHidden()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    hs.hideSequence(seqs[7]);
+    hs.hideSequence(seqs[4]);
+    assertTrue(hs.isHidden(seqs[4]));
+    assertFalse(hs.isHidden(seqs[5]));
+    assertFalse(hs.isHidden(seqs[6]));
+    assertTrue(hs.isHidden(seqs[7]));
+    assertFalse(hs.isHidden(null));
+    assertFalse(hs.isHidden(new Sequence("", "")));
+  }
+
+  /**
+   * Test hiding and unhiding a group with a representative sequence. The
+   * representative should be left visible when the group is hidden, and
+   * included in the selected group when it is unhidden.
+   */
+  @Test(groups = "Functional")
+  public void testHideShowSequence_withHiddenRepSequence()
+  {
+    AlignmentI al = new Alignment(seqs);
+
+    /*
+     * represent seqs 2-4 with seq3
+     * this hides seq2 and seq4 but not seq3
+     */
+    AlignViewport av = new AlignViewport(al);
+    SequenceGroup sg = new SequenceGroup();
+    sg.addSequence(seqs[1], false);
+    sg.addSequence(seqs[2], false);
+    sg.addSequence(seqs[3], false);
+    av.setSelectionGroup(sg);
+
+    /*
+     * hiding group with reference sequence is done via AlignViewport
+     */
+    av.hideSequences(seqs[2], true);
+    HiddenSequences hs = al.getHiddenSequences();
+    assertEquals(2, hs.getSize());
+    assertTrue(hs.isHidden(seqs[1]));
+    assertFalse(hs.isHidden(seqs[2]));
+    assertTrue(hs.isHidden(seqs[3]));
+
+    /*
+     * should now be no sequences selected in the alignment
+     */
+    assertNull(av.getSelectionGroup());
+
+    /*
+     * visible alignment is now seq0/2/4/5/6/7/8/9
+     * 'reveal sequences' at the representative sequence (index = 1)
+     * this should unhide the one above i.e. seq1
+     * and return a selection list including seq2
+     * 
+     * note have to call via AlignViewport to get the expected
+     * resulting sequence selection
+     */
+    av.showSequence(1);
+
+    /*
+     * only seq3 is now hidden
+     */
+    assertEquals(1, hs.getSize());
+    assertTrue(hs.isHidden(seqs[3]));
+    assertEquals(SEQ_COUNT - 1, al.getHeight());
+    sg = av.getSelectionGroup();
+
+    /*
+     * unhidden and representative sequence selected
+     * (this behaviour may change! JAL-2133)
+     */
+    assertEquals(2, sg.getSize());
+    assertTrue(sg.getSequences().contains(seqs[1]));
+    assertTrue(sg.getSequences().contains(seqs[2]));
+    assertFalse(sg.getSequences().contains(seqs[3]));
+  }
+}
index 8a3b925..42bb091 100644 (file)
@@ -34,7 +34,7 @@ public class PDBEntryTest
   {
   }
 
-  @AfterMethod
+  @AfterMethod(alwaysRun = true)
   public void tearDown() throws Exception
   {
   }
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 90c38d4..fb7e143 100644 (file)
@@ -21,13 +21,13 @@ import org.testng.annotations.Test;
 
 public class EnsemblCdnaTest
 {
-  @BeforeClass
+  @BeforeClass(alwaysRun = true)
   public void setUp()
   {
     SequenceOntologyFactory.setInstance(new SequenceOntologyLite());
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public void tearDown()
   {
     SequenceOntologyFactory.setInstance(null);
index 183f933..5344575 100644 (file)
@@ -20,13 +20,13 @@ import org.testng.annotations.Test;
 
 public class EnsemblCdsTest
 {
-  @BeforeClass
+  @BeforeClass(alwaysRun = true)
   public void setUp()
   {
     SequenceOntologyFactory.setInstance(new SequenceOntologyLite());
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public void tearDown()
   {
     SequenceOntologyFactory.setInstance(null);
index 5cf296c..4e815d1 100644 (file)
@@ -22,13 +22,13 @@ import org.testng.annotations.Test;
 
 public class EnsemblGeneTest
 {
-  @BeforeClass
+  @BeforeClass(alwaysRun = true)
   public void setUp()
   {
     SequenceOntologyFactory.setInstance(new SequenceOntologyLite());
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public void tearDown()
   {
     SequenceOntologyFactory.setInstance(null);
index daad8b1..c711279 100644 (file)
@@ -19,13 +19,13 @@ import org.testng.annotations.Test;
 
 public class EnsemblGenomeTest
 {
-  @BeforeClass
+  @BeforeClass(alwaysRun = true)
   public void setUp()
   {
     SequenceOntologyFactory.setInstance(new SequenceOntologyLite());
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public void tearDown()
   {
     SequenceOntologyFactory.setInstance(null);
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..2d3948f 100644 (file)
@@ -6,7 +6,6 @@ import static org.testng.AssertJUnit.assertTrue;
 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
 
 import jalview.datamodel.Alignment;
-import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.io.AppletFormatAdapter;
@@ -16,10 +15,7 @@ import jalview.io.gff.SequenceOntologyFactory;
 import jalview.io.gff.SequenceOntologyLite;
 
 import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
 import java.util.Arrays;
-import java.util.List;
 
 import org.testng.Assert;
 import org.testng.annotations.AfterClass;
@@ -109,13 +105,13 @@ public class EnsemblSeqProxyTest
                   + "NRDQIIFMVGRGYLSPDLSKVRSNCPKAMKRLMAECLKKKRDERPLFPQILASIELLARS\n"
                   + "LPKIHRSASEPSLNRAGFQTEDFSLYACASPKTPIQAGGYGAFPVH" } };
 
-  @BeforeClass
+  @BeforeClass(alwaysRun = true)
   public void setUp()
   {
     SequenceOntologyFactory.setInstance(new SequenceOntologyLite());
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public void tearDown()
   {
     SequenceOntologyFactory.setInstance(null);
@@ -160,61 +156,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 c9b2980..10224fa 100644 (file)
@@ -53,7 +53,7 @@ public class JmolViewerTest
   /**
    * @throws java.lang.Exception
    */
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
     jalview.gui.Desktop.instance.closeAll_actionPerformed(null);
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 cd28a2b..93a98b8 100644 (file)
@@ -54,7 +54,7 @@ public class JalviewChimeraView
   /**
    * @throws java.lang.Exception
    */
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
     jalview.gui.Desktop.instance.closeAll_actionPerformed(null);
index be07485..ea92e3c 100644 (file)
@@ -3,11 +3,8 @@ package jalview.ext.so;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertTrue;
 
-import jalview.ext.so.SequenceOntology;
-import jalview.io.gff.SequenceOntologyFactory;
 import jalview.io.gff.SequenceOntologyI;
 
-import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
@@ -15,20 +12,20 @@ public class SequenceOntologyTest
 {
   private SequenceOntologyI so;
 
-  @BeforeClass
+  @BeforeClass(alwaysRun = true)
   public void setUp() {
     long now = System.currentTimeMillis();
-    SequenceOntologyFactory.setInstance(new SequenceOntology());
+    try
+    {
+      so = new SequenceOntology();
+    } catch (Throwable t)
+    {
+      System.out.println("SOTest error ");
+      t.printStackTrace(System.err);
+    }
     long elapsed = System.currentTimeMillis() - now;
     System.out.println("Load and cache of Sequence Ontology took "
             + elapsed + "ms");
-    so = SequenceOntologyFactory.getInstance();
-  }
-
-  @AfterClass
-  public void tearDown()
-  {
-    SequenceOntologyFactory.setInstance(null);
   }
 
   @Test(groups = "Functional")
index 0dac04b..eae5575 100644 (file)
@@ -40,7 +40,7 @@ public class FTSRestClientTest
   public void getPrimaryKeyColumIndexTest()
   {
     Collection<FTSDataColumnI> wantedFields = ftsRestClient
-            .getAllDefaulDisplayedDataColumns();
+            .getAllDefaultDisplayedFTSDataColumns();
     int foundIndex = -1;
     try
     {
@@ -61,10 +61,10 @@ 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()
+    Assert.assertEquals(ftsRestClient.getAllDefaultDisplayedFTSDataColumns()
             .size(), 7);
   }
 
@@ -72,11 +72,11 @@ public class FTSRestClientTest
   public void getDataColumnsFieldsAsCommaDelimitedString()
   {
     Collection<FTSDataColumnI> wantedFields = ftsRestClient
-            .getAllDefaulDisplayedDataColumns();
+            .getAllDefaultDisplayedFTSDataColumns();
     String actual = ftsRestClient
             .getDataColumnsFieldsAsCommaDelimitedString(wantedFields);
     Assert.assertEquals(actual,
-            "id,entry name,protein names,genes,organism,length,reviewed");
+            "id,entry name,protein names,genes,organism,reviewed,length");
   }
 
 
@@ -95,7 +95,7 @@ public class FTSRestClientTest
     Collection<FTSDataColumnI> searchalbeFields = ftsRestClient
             .getSearchableDataColumns();
     Assert.assertNotNull(searchalbeFields);
-    Assert.assertEquals(searchalbeFields.size(), 30);
+    Assert.assertEquals(searchalbeFields.size(), 22);
   }
 
   @Test(groups = { "Functional" })
@@ -151,7 +151,7 @@ public class FTSRestClientTest
   public void getDefaultResponsePageSize()
   {
     int defaultResSize = ftsRestClient.getDefaultResponsePageSize();
-    Assert.assertEquals(defaultResSize, 100);
+    Assert.assertEquals(defaultResSize, 500);
   }
 
   @Test(groups = { "Functional" })
@@ -213,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);
@@ -235,11 +237,12 @@ 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(), 30);
+    Assert.assertEquals(uniqueSet.size(), 22);
   }
 
   @Test(groups = { "Functional" })
index ac1d304..69792bb 100644 (file)
@@ -23,8 +23,6 @@ package jalview.fts.service.pdb;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertTrue;
 
-import jalview.fts.service.pdb.PDBFTSPanel;
-
 import javax.swing.JInternalFrame;
 import javax.swing.JTextField;
 
@@ -40,7 +38,7 @@ public class PDBFTSPanelTest
   {
   }
 
-  @AfterMethod
+  @AfterMethod(alwaysRun = true)
   public void tearDown() throws Exception
   {
   }
index ebc0405..ed248bb 100644 (file)
@@ -59,7 +59,7 @@ public class PDBFTSRestClientTest
   {
   }
 
-  @AfterMethod
+  @AfterMethod(alwaysRun = true)
   public void tearDown() throws Exception
   {
   }
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 ff8c179..9d0cedb 100644 (file)
@@ -47,7 +47,7 @@ public class JAL1353bugdemo
   {
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
   }
index 52eadcb..212bcce 100644 (file)
@@ -48,7 +48,7 @@ public class PaintRefresherTest
     PaintRefresher.components.clear();
   }
 
-  @AfterMethod
+  @AfterMethod(alwaysRun = true)
   public void tearDown()
   {
     PaintRefresher.components.clear();
index c2209d6..bad536b 100644 (file)
@@ -24,6 +24,7 @@ import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
@@ -60,7 +61,7 @@ public class StructureChooserTest
     seq.setPDBId(pdbIds);
   }
 
-  @AfterMethod
+  @AfterMethod(alwaysRun = true)
   public void tearDown() throws Exception
   {
     seq = null;
@@ -80,6 +81,27 @@ public class StructureChooserTest
     seq.setDBRefs(null);
     query = StructureChooser.buildQuery(seq);
     assertEquals("text:4kqy", query);
+
+    DBRefEntry uniprotDBRef = new DBRefEntry();
+    uniprotDBRef.setAccessionId("P12345");
+    uniprotDBRef.setSource(DBRefSource.UNIPROT);
+    seq.addDBRef(uniprotDBRef);
+
+    DBRefEntry pdbDBRef = new DBRefEntry();
+    pdbDBRef.setAccessionId("1XYZ");
+    pdbDBRef.setSource(DBRefSource.PDB);
+    seq.addDBRef(pdbDBRef);
+
+    for (int x = 1; x < 5; x++)
+    {
+      DBRefEntry dbRef = new DBRefEntry();
+      dbRef.setAccessionId("XYZ_" + x);
+      seq.addDBRef(dbRef);
+    }
+    query = StructureChooser.buildQuery(seq);
+    assertEquals(
+            "uniprot_accession:P12345 OR uniprot_id:P12345 OR pdb_id:1xyz",
+            query);
   }
 
   @Test(groups = { "Functional" })
@@ -116,4 +138,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));
+  }
 }
diff --git a/test/jalview/io/1a70.pdb b/test/jalview/io/1a70.pdb
new file mode 100644 (file)
index 0000000..1c69a73
--- /dev/null
@@ -0,0 +1,1146 @@
+HEADER    IRON-SULFUR PROTEIN                     19-MAR-98   1A70              
+TITLE     SPINACH FERREDOXIN                                                    
+COMPND    MOL_ID: 1;                                                            
+COMPND   2 MOLECULE: FERREDOXIN;                                                
+COMPND   3 CHAIN: A;                                                            
+COMPND   4 ENGINEERED: YES;                                                     
+COMPND   5 MUTATION: YES                                                        
+SOURCE    MOL_ID: 1;                                                            
+SOURCE   2 ORGANISM_SCIENTIFIC: SPINACIA OLERACEA;                              
+SOURCE   3 ORGANISM_COMMON: SPINACH;                                            
+SOURCE   4 ORGANISM_TAXID: 3562;                                                
+SOURCE   5 EXPRESSION_SYSTEM: ESCHERICHIA COLI;                                 
+SOURCE   6 EXPRESSION_SYSTEM_TAXID: 562                                         
+KEYWDS    IRON-SULFUR PROTEIN, PHOTOSYNTHESIS, ELECTRON TRANSPORT               
+EXPDTA    X-RAY DIFFRACTION                                                     
+AUTHOR    C.BINDA,A.CODA,A.MATTEVI,A.ALIVERTI,G.ZANETTI                         
+REVDAT   3   24-FEB-09 1A70    1       VERSN                                    
+REVDAT   2   13-JAN-99 1A70    3       ATOM   SOURCE COMPND REMARK              
+REVDAT   2 2                   3       HETATM JRNL   KEYWDS TER                 
+REVDAT   2 3                   3       CONECT                                   
+REVDAT   1   25-NOV-98 1A70    0                                                
+JRNL        AUTH   C.BINDA,A.CODA,A.ALIVERTI,G.ZANETTI,A.MATTEVI                
+JRNL        TITL   STRUCTURE OF THE MUTANT E92K OF [2FE-2S]                     
+JRNL        TITL 2 FERREDOXIN I FROM SPINACIA OLERACEA AT 1.7 A                 
+JRNL        TITL 3 RESOLUTION.                                                  
+JRNL        REF    ACTA CRYSTALLOGR.,SECT.D      V.  54  1353 1998              
+JRNL        REFN                   ISSN 0907-4449                               
+JRNL        PMID   10089511                                                     
+JRNL        DOI    10.1107/S0907444998005137                                    
+REMARK   1                                                                      
+REMARK   2                                                                      
+REMARK   2 RESOLUTION.    1.70 ANGSTROMS.                                       
+REMARK   3                                                                      
+REMARK   3 REFINEMENT.                                                          
+REMARK   3   PROGRAM     : TNT V. 5-D                                           
+REMARK   3   AUTHORS     : TRONRUD,TEN EYCK,MATTHEWS                            
+REMARK   3                                                                      
+REMARK   3  DATA USED IN REFINEMENT.                                            
+REMARK   3   RESOLUTION RANGE HIGH (ANGSTROMS) : 1.70                           
+REMARK   3   RESOLUTION RANGE LOW  (ANGSTROMS) : 100.00                         
+REMARK   3   DATA CUTOFF            (SIGMA(F)) : 0.000                          
+REMARK   3   COMPLETENESS FOR RANGE        (%) : 97.6                           
+REMARK   3   NUMBER OF REFLECTIONS             : 11755                          
+REMARK   3                                                                      
+REMARK   3  USING DATA ABOVE SIGMA CUTOFF.                                      
+REMARK   3   CROSS-VALIDATION METHOD          : A POSTERIORI                    
+REMARK   3   FREE R VALUE TEST SET SELECTION  : EVERY 10TH REFLECTION           
+REMARK   3   R VALUE     (WORKING + TEST SET) : 0.190                           
+REMARK   3   R VALUE            (WORKING SET) : 0.182                           
+REMARK   3   FREE R VALUE                     : 0.200                           
+REMARK   3   FREE R VALUE TEST SET SIZE   (%) : 10.000                          
+REMARK   3   FREE R VALUE TEST SET COUNT      : 1090                            
+REMARK   3                                                                      
+REMARK   3  USING ALL DATA, NO SIGMA CUTOFF.                                    
+REMARK   3   R VALUE   (WORKING + TEST SET, NO CUTOFF) : 0.2010                 
+REMARK   3   R VALUE          (WORKING SET, NO CUTOFF) : 0.1960                 
+REMARK   3   FREE R VALUE                  (NO CUTOFF) : 0.259                  
+REMARK   3   FREE R VALUE TEST SET SIZE (%, NO CUTOFF) : 10.00                  
+REMARK   3   FREE R VALUE TEST SET COUNT   (NO CUTOFF) : 1176                   
+REMARK   3   TOTAL NUMBER OF REFLECTIONS   (NO CUTOFF) : 11755                  
+REMARK   3                                                                      
+REMARK   3  NUMBER OF NON-HYDROGEN ATOMS USED IN REFINEMENT.                    
+REMARK   3   PROTEIN ATOMS            : 732                                     
+REMARK   3   NUCLEIC ACID ATOMS       : 0                                       
+REMARK   3   HETEROGEN ATOMS          : 4                                       
+REMARK   3   SOLVENT ATOMS            : 81                                      
+REMARK   3                                                                      
+REMARK   3  WILSON B VALUE (FROM FCALC, A**2) : 5.100                           
+REMARK   3                                                                      
+REMARK   3  RMS DEVIATIONS FROM IDEAL VALUES.    RMS    WEIGHT  COUNT           
+REMARK   3   BOND LENGTHS                 (A) : 0.019 ; 70.000; 620             
+REMARK   3   BOND ANGLES            (DEGREES) : 2.994 ; 90.000; 855             
+REMARK   3   TORSION ANGLES         (DEGREES) : 18.500; 0.000 ; 300             
+REMARK   3   PSEUDOROTATION ANGLES  (DEGREES) : NULL  ; NULL  ; NULL            
+REMARK   3   TRIGONAL CARBON PLANES       (A) : 0.021 ; 70.000; 13              
+REMARK   3   GENERAL PLANES               (A) : 0.021 ; 240.000; 94             
+REMARK   3   ISOTROPIC THERMAL FACTORS (A**2) : 4.300 ; 2.100 ; 620             
+REMARK   3   NON-BONDED CONTACTS          (A) : 0.039 ; 125.000; 9              
+REMARK   3                                                                      
+REMARK   3  INCORRECT CHIRAL-CENTERS (COUNT) : NULL                             
+REMARK   3                                                                      
+REMARK   3  BULK SOLVENT MODELING.                                              
+REMARK   3   METHOD USED : BABINET SCALING                                      
+REMARK   3   KSOL        : 0.80                                                 
+REMARK   3   BSOL        : 150.00                                               
+REMARK   3                                                                      
+REMARK   3  RESTRAINT LIBRARIES.                                                
+REMARK   3   STEREOCHEMISTRY : TNT PROTGEO                                      
+REMARK   3   ISOTROPIC THERMAL FACTOR RESTRAINTS : TNT BCORREL V1.0             
+REMARK   3                                                                      
+REMARK   3  OTHER REFINEMENT REMARKS: NULL                                      
+REMARK   4                                                                      
+REMARK   4 1A70 COMPLIES WITH FORMAT V. 3.15, 01-DEC-08                         
+REMARK 100                                                                      
+REMARK 100 THIS ENTRY HAS BEEN PROCESSED BY BNL.                                
+REMARK 200                                                                      
+REMARK 200 EXPERIMENTAL DETAILS                                                 
+REMARK 200  EXPERIMENT TYPE                : X-RAY DIFFRACTION                  
+REMARK 200  DATE OF DATA COLLECTION        : JUN-96                             
+REMARK 200  TEMPERATURE           (KELVIN) : 293                                
+REMARK 200  PH                             : 7.5                                
+REMARK 200  NUMBER OF CRYSTALS USED        : 1                                  
+REMARK 200                                                                      
+REMARK 200  SYNCHROTRON              (Y/N) : N                                  
+REMARK 200  RADIATION SOURCE               : ROTATING ANODE                     
+REMARK 200  BEAMLINE                       : NULL                               
+REMARK 200  X-RAY GENERATOR MODEL          : RIGAKU RUH2R                       
+REMARK 200  MONOCHROMATIC OR LAUE    (M/L) : M                                  
+REMARK 200  WAVELENGTH OR RANGE        (A) : 1.5418                             
+REMARK 200  MONOCHROMATOR                  : GRAPHITE(002)                      
+REMARK 200  OPTICS                         : MIRRORS                            
+REMARK 200                                                                      
+REMARK 200  DETECTOR TYPE                  : IMAGE PLATE                        
+REMARK 200  DETECTOR MANUFACTURER          : MARRESEARCH                        
+REMARK 200  INTENSITY-INTEGRATION SOFTWARE : MOSFLM                             
+REMARK 200  DATA SCALING SOFTWARE          : AGROVATA                           
+REMARK 200                                                                      
+REMARK 200  NUMBER OF UNIQUE REFLECTIONS   : 11755                              
+REMARK 200  RESOLUTION RANGE HIGH      (A) : 1.700                              
+REMARK 200  RESOLUTION RANGE LOW       (A) : NULL                               
+REMARK 200  REJECTION CRITERIA  (SIGMA(I)) : 2.000                              
+REMARK 200                                                                      
+REMARK 200 OVERALL.                                                             
+REMARK 200  COMPLETENESS FOR RANGE     (%) : 97.6                               
+REMARK 200  DATA REDUNDANCY                : 2.500                              
+REMARK 200  R MERGE                    (I) : 0.07800                            
+REMARK 200  R SYM                      (I) : 0.11200                            
+REMARK 200  <I/SIGMA(I)> FOR THE DATA SET  : 10.0000                            
+REMARK 200                                                                      
+REMARK 200 IN THE HIGHEST RESOLUTION SHELL.                                     
+REMARK 200  HIGHEST RESOLUTION SHELL, RANGE HIGH (A) : 1.70                     
+REMARK 200  HIGHEST RESOLUTION SHELL, RANGE LOW  (A) : 1.80                     
+REMARK 200  COMPLETENESS FOR SHELL     (%) : 68.0                               
+REMARK 200  DATA REDUNDANCY IN SHELL       : 2.50                               
+REMARK 200  R MERGE FOR SHELL          (I) : 0.20200                            
+REMARK 200  R SYM FOR SHELL            (I) : 0.30500                            
+REMARK 200  <I/SIGMA(I)> FOR SHELL         : 2.000                              
+REMARK 200                                                                      
+REMARK 200 DIFFRACTION PROTOCOL: NULL                                           
+REMARK 200 METHOD USED TO DETERMINE THE STRUCTURE: MOLECULAR REPLACEMENT        
+REMARK 200 SOFTWARE USED: AMORE                                                 
+REMARK 200 STARTING MODEL: PDB ENTRY 1FRR                                       
+REMARK 200                                                                      
+REMARK 200 REMARK: NULL                                                         
+REMARK 280                                                                      
+REMARK 280 CRYSTAL                                                              
+REMARK 280 SOLVENT CONTENT, VS   (%): 50.00                                     
+REMARK 280 MATTHEWS COEFFICIENT, VM (ANGSTROMS**3/DA): 1.50                     
+REMARK 280                                                                      
+REMARK 280 CRYSTALLIZATION CONDITIONS: PROTEIN WAS CRYSTALLIZED FROM 2.6M       
+REMARK 280  AMMONIUM SULPHATE IN 50MM PHOSPHATE BUFFER, PH 7.5                  
+REMARK 290                                                                      
+REMARK 290 CRYSTALLOGRAPHIC SYMMETRY                                            
+REMARK 290 SYMMETRY OPERATORS FOR SPACE GROUP: P 21 21 21                       
+REMARK 290                                                                      
+REMARK 290      SYMOP   SYMMETRY                                                
+REMARK 290     NNNMMM   OPERATOR                                                
+REMARK 290       1555   X,Y,Z                                                   
+REMARK 290       2555   -X+1/2,-Y,Z+1/2                                         
+REMARK 290       3555   -X,Y+1/2,-Z+1/2                                         
+REMARK 290       4555   X+1/2,-Y+1/2,-Z                                         
+REMARK 290                                                                      
+REMARK 290     WHERE NNN -> OPERATOR NUMBER                                     
+REMARK 290           MMM -> TRANSLATION VECTOR                                  
+REMARK 290                                                                      
+REMARK 290 CRYSTALLOGRAPHIC SYMMETRY TRANSFORMATIONS                            
+REMARK 290 THE FOLLOWING TRANSFORMATIONS OPERATE ON THE ATOM/HETATM             
+REMARK 290 RECORDS IN THIS ENTRY TO PRODUCE CRYSTALLOGRAPHICALLY                
+REMARK 290 RELATED MOLECULES.                                                   
+REMARK 290   SMTRY1   1  1.000000  0.000000  0.000000        0.00000            
+REMARK 290   SMTRY2   1  0.000000  1.000000  0.000000        0.00000            
+REMARK 290   SMTRY3   1  0.000000  0.000000  1.000000        0.00000            
+REMARK 290   SMTRY1   2 -1.000000  0.000000  0.000000       15.50000            
+REMARK 290   SMTRY2   2  0.000000 -1.000000  0.000000        0.00000            
+REMARK 290   SMTRY3   2  0.000000  0.000000  1.000000       41.76000            
+REMARK 290   SMTRY1   3 -1.000000  0.000000  0.000000        0.00000            
+REMARK 290   SMTRY2   3  0.000000  1.000000  0.000000       19.59000            
+REMARK 290   SMTRY3   3  0.000000  0.000000 -1.000000       41.76000            
+REMARK 290   SMTRY1   4  1.000000  0.000000  0.000000       15.50000            
+REMARK 290   SMTRY2   4  0.000000 -1.000000  0.000000       19.59000            
+REMARK 290   SMTRY3   4  0.000000  0.000000 -1.000000        0.00000            
+REMARK 290                                                                      
+REMARK 290 REMARK: NULL                                                         
+REMARK 300                                                                      
+REMARK 300 BIOMOLECULE: 1                                                       
+REMARK 300 SEE REMARK 350 FOR THE AUTHOR PROVIDED AND/OR PROGRAM                
+REMARK 300 GENERATED ASSEMBLY INFORMATION FOR THE STRUCTURE IN                  
+REMARK 300 THIS ENTRY. THE REMARK MAY ALSO PROVIDE INFORMATION ON               
+REMARK 300 BURIED SURFACE AREA.                                                 
+REMARK 350                                                                      
+REMARK 350 COORDINATES FOR A COMPLETE MULTIMER REPRESENTING THE KNOWN           
+REMARK 350 BIOLOGICALLY SIGNIFICANT OLIGOMERIZATION STATE OF THE                
+REMARK 350 MOLECULE CAN BE GENERATED BY APPLYING BIOMT TRANSFORMATIONS          
+REMARK 350 GIVEN BELOW.  BOTH NON-CRYSTALLOGRAPHIC AND                          
+REMARK 350 CRYSTALLOGRAPHIC OPERATIONS ARE GIVEN.                               
+REMARK 350                                                                      
+REMARK 350 BIOMOLECULE: 1                                                       
+REMARK 350 AUTHOR DETERMINED BIOLOGICAL UNIT: MONOMERIC                         
+REMARK 350 APPLY THE FOLLOWING TO CHAINS: A                                     
+REMARK 350   BIOMT1   1  1.000000  0.000000  0.000000        0.00000            
+REMARK 350   BIOMT2   1  0.000000  1.000000  0.000000        0.00000            
+REMARK 350   BIOMT3   1  0.000000  0.000000  1.000000        0.00000            
+REMARK 500                                                                      
+REMARK 500 GEOMETRY AND STEREOCHEMISTRY                                         
+REMARK 500 SUBTOPIC: COVALENT BOND ANGLES                                       
+REMARK 500                                                                      
+REMARK 500 THE STEREOCHEMICAL PARAMETERS OF THE FOLLOWING RESIDUES              
+REMARK 500 HAVE VALUES WHICH DEVIATE FROM EXPECTED VALUES BY MORE               
+REMARK 500 THAN 6*RMSD (M=MODEL NUMBER; RES=RESIDUE NAME; C=CHAIN               
+REMARK 500 IDENTIFIER; SSEQ=SEQUENCE NUMBER; I=INSERTION CODE).                 
+REMARK 500                                                                      
+REMARK 500 STANDARD TABLE:                                                      
+REMARK 500 FORMAT: (10X,I3,1X,A3,1X,A1,I4,A1,3(1X,A4,2X),12X,F5.1)              
+REMARK 500                                                                      
+REMARK 500 EXPECTED VALUES PROTEIN: ENGH AND HUBER, 1999                        
+REMARK 500 EXPECTED VALUES NUCLEIC ACID: CLOWNEY ET AL 1996                     
+REMARK 500                                                                      
+REMARK 500  M RES CSSEQI ATM1   ATM2   ATM3                                     
+REMARK 500    ASP A  20   CB  -  CG  -  OD2 ANGL. DEV. =  -6.8 DEGREES          
+REMARK 500    ASP A  34   CB  -  CG  -  OD1 ANGL. DEV. =   6.1 DEGREES          
+REMARK 500    ASP A  34   CB  -  CG  -  OD2 ANGL. DEV. =  -5.9 DEGREES          
+REMARK 500    ARG A  40   NE  -  CZ  -  NH2 ANGL. DEV. =  -4.7 DEGREES          
+REMARK 500    ASP A  59   CB  -  CG  -  OD2 ANGL. DEV. =  -5.6 DEGREES          
+REMARK 500    ASP A  65   CB  -  CG  -  OD1 ANGL. DEV. =   5.7 DEGREES          
+REMARK 500    ASP A  84   CB  -  CG  -  OD1 ANGL. DEV. =  12.2 DEGREES          
+REMARK 500    ASP A  84   CB  -  CG  -  OD2 ANGL. DEV. = -14.6 DEGREES          
+REMARK 500                                                                      
+REMARK 500 REMARK: NULL                                                         
+REMARK 500                                                                      
+REMARK 500 GEOMETRY AND STEREOCHEMISTRY                                         
+REMARK 500 SUBTOPIC: TORSION ANGLES                                             
+REMARK 500                                                                      
+REMARK 500 TORSION ANGLES OUTSIDE THE EXPECTED RAMACHANDRAN REGIONS:            
+REMARK 500 (M=MODEL NUMBER; RES=RESIDUE NAME; C=CHAIN IDENTIFIER;               
+REMARK 500 SSEQ=SEQUENCE NUMBER; I=INSERTION CODE).                             
+REMARK 500                                                                      
+REMARK 500 STANDARD TABLE:                                                      
+REMARK 500 FORMAT:(10X,I3,1X,A3,1X,A1,I4,A1,4X,F7.2,3X,F7.2)                    
+REMARK 500                                                                      
+REMARK 500 EXPECTED VALUES: GJ KLEYWEGT AND TA JONES (1996). PHI/PSI-           
+REMARK 500 CHOLOGY: RAMACHANDRAN REVISITED. STRUCTURE 4, 1395 - 1400            
+REMARK 500                                                                      
+REMARK 500  M RES CSSEQI        PSI       PHI                                   
+REMARK 500    SER A  38      -77.42   -141.70                                   
+REMARK 500                                                                      
+REMARK 500 REMARK: NULL                                                         
+REMARK 500                                                                      
+REMARK 500 GEOMETRY AND STEREOCHEMISTRY                                         
+REMARK 500 SUBTOPIC: CHIRAL CENTERS                                             
+REMARK 500                                                                      
+REMARK 500 UNEXPECTED CONFIGURATION OF THE FOLLOWING CHIRAL                     
+REMARK 500 CENTER(S) USING IMPROPER CA--C--CB--N CHIRALITY                      
+REMARK 500 M=MODEL NUMBER; RES=RESIDUE NAME; C=CHAIN                            
+REMARK 500 IDENTIFIER; SSEQ=SEQUENCE NUMBER; I=INSERTION CODE                   
+REMARK 500                                                                      
+REMARK 500 STANDARD TABLE:                                                      
+REMARK 500 FORMAT: (11X,I3,1X,A3,1X,A1,I4,A1,6X,F5.1,6X,A1,10X,A1,3X,A16)       
+REMARK 500                                                                      
+REMARK 500   M RES CSSEQI    IMPROPER   EXPECTED   FOUND DETAILS                
+REMARK 500     ALA A   1       115.2                     ALPHA-CARBON           
+REMARK 500                                                                      
+REMARK 500 REMARK: NULL                                                         
+REMARK 525                                                                      
+REMARK 525 SOLVENT                                                              
+REMARK 525                                                                      
+REMARK 525 THE SOLVENT MOLECULES HAVE CHAIN IDENTIFIERS THAT                    
+REMARK 525 INDICATE THE POLYMER CHAIN WITH WHICH THEY ARE MOST                  
+REMARK 525 CLOSELY ASSOCIATED. THE REMARK LISTS ALL THE SOLVENT                 
+REMARK 525 MOLECULES WHICH ARE MORE THAN 5A AWAY FROM THE                       
+REMARK 525 NEAREST POLYMER CHAIN (M = MODEL NUMBER;                             
+REMARK 525 RES=RESIDUE NAME; C=CHAIN IDENTIFIER; SSEQ=SEQUENCE                  
+REMARK 525 NUMBER; I=INSERTION CODE):                                           
+REMARK 525                                                                      
+REMARK 525  M RES CSSEQI                                                        
+REMARK 525    HOH A1653        DISTANCE =  5.18 ANGSTROMS                       
+REMARK 525    HOH A1666        DISTANCE =  5.57 ANGSTROMS                       
+REMARK 525    HOH A1680        DISTANCE =  8.72 ANGSTROMS                       
+REMARK 800                                                                      
+REMARK 800 SITE                                                                 
+REMARK 800 SITE_IDENTIFIER: AC1                                                 
+REMARK 800 EVIDENCE_CODE: SOFTWARE                                              
+REMARK 800 SITE_DESCRIPTION: BINDING SITE FOR RESIDUE FES A 1602                
+DBREF  1A70 A    1    97  UNP    P00221   FER1_SPIOL      51    147             
+SEQADV 1A70 LYS A   92  UNP  P00221    GLU   142 ENGINEERED                     
+SEQRES   1 A   97  ALA ALA TYR LYS VAL THR LEU VAL THR PRO THR GLY ASN          
+SEQRES   2 A   97  VAL GLU PHE GLN CYS PRO ASP ASP VAL TYR ILE LEU ASP          
+SEQRES   3 A   97  ALA ALA GLU GLU GLU GLY ILE ASP LEU PRO TYR SER CYS          
+SEQRES   4 A   97  ARG ALA GLY SER CYS SER SER CYS ALA GLY LYS LEU LYS          
+SEQRES   5 A   97  THR GLY SER LEU ASN GLN ASP ASP GLN SER PHE LEU ASP          
+SEQRES   6 A   97  ASP ASP GLN ILE ASP GLU GLY TRP VAL LEU THR CYS ALA          
+SEQRES   7 A   97  ALA TYR PRO VAL SER ASP VAL THR ILE GLU THR HIS LYS          
+SEQRES   8 A   97  LYS GLU GLU LEU THR ALA                                      
+HET    FES  A1602       4                                                       
+HETNAM     FES FE2/S2 (INORGANIC) CLUSTER                                       
+FORMUL   2  FES    FE2 S2                                                       
+FORMUL   3  HOH   *81(H2 O)                                                     
+HELIX    1   1 ILE A   24  GLU A   30  1                                   7    
+HELIX    2   2 ASP A   66  GLU A   71  1                                   6    
+HELIX    3   3 THR A   76  ALA A   78  5                                   3    
+HELIX    4   4 LYS A   92  GLU A   94  5                                   3    
+SHEET    1   A 5 GLY A  12  PRO A  19  0                                        
+SHEET    2   A 5 ALA A   2  THR A   9 -1  N  THR A   9   O  GLY A  12           
+SHEET    3   A 5 VAL A  85  GLU A  88  1  N  VAL A  85   O  THR A   6           
+SHEET    4   A 5 ALA A  48  THR A  53 -1  N  THR A  53   O  THR A  86           
+SHEET    5   A 5 TRP A  73  LEU A  75 -1  N  VAL A  74   O  GLY A  49           
+LINK        FE1  FES A1602                 SG  CYS A  39     1555   1555  2.32  
+LINK        FE1  FES A1602                 SG  CYS A  44     1555   1555  2.28  
+LINK        FE2  FES A1602                 SG  CYS A  47     1555   1555  2.36  
+LINK        FE2  FES A1602                 SG  CYS A  77     1555   1555  2.27  
+SITE     1 AC1  8 SER A  38  CYS A  39  ARG A  40  GLY A  42                    
+SITE     2 AC1  8 SER A  43  CYS A  44  CYS A  47  CYS A  77                    
+CRYST1   31.000   39.180   83.520  90.00  90.00  90.00 P 21 21 21    4          
+ORIGX1      1.000000  0.000000  0.000000        0.00000                         
+ORIGX2      0.000000  1.000000  0.000000        0.00000                         
+ORIGX3      0.000000  0.000000  1.000000        0.00000                         
+SCALE1      0.032258  0.000000  0.000000        0.00000                         
+SCALE2      0.000000  0.025523  0.000000        0.00000                         
+SCALE3      0.000000  0.000000  0.011973        0.00000                         
+ATOM      1  N   ALA A   1       1.578  -4.284   5.235  1.00 64.26           N  
+ATOM      2  CA  ALA A   1       2.384  -5.448   5.549  1.00 56.75           C  
+ATOM      3  C   ALA A   1       3.756  -4.955   5.925  1.00 52.65           C  
+ATOM      4  O   ALA A   1       3.885  -4.610   7.073  1.00 48.15           O  
+ATOM      5  CB  ALA A   1       1.801  -6.118   6.780  1.00 57.60           C  
+ATOM      6  N   ALA A   2       4.702  -4.829   4.989  1.00 44.72           N  
+ATOM      7  CA  ALA A   2       6.033  -4.319   5.297  1.00 39.74           C  
+ATOM      8  C   ALA A   2       6.471  -3.432   4.151  1.00 38.97           C  
+ATOM      9  O   ALA A   2       6.000  -3.558   3.005  1.00 35.65           O  
+ATOM     10  CB  ALA A   2       6.977  -5.471   5.509  1.00 39.07           C  
+ATOM     11  N   TYR A   3       7.381  -2.517   4.408  1.00 35.77           N  
+ATOM     12  CA  TYR A   3       7.706  -1.626   3.320  1.00 34.41           C  
+ATOM     13  C   TYR A   3       9.186  -1.384   3.280  1.00 33.59           C  
+ATOM     14  O   TYR A   3       9.923  -1.779   4.188  1.00 31.95           O  
+ATOM     15  CB  TYR A   3       6.953  -0.249   3.319  1.00 39.83           C  
+ATOM     16  CG  TYR A   3       5.433  -0.309   3.472  1.00 45.38           C  
+ATOM     17  CD1 TYR A   3       4.627  -0.464   2.343  1.00 44.25           C  
+ATOM     18  CD2 TYR A   3       4.849  -0.181   4.741  1.00 42.82           C  
+ATOM     19  CE1 TYR A   3       3.235  -0.498   2.478  1.00 44.87           C  
+ATOM     20  CE2 TYR A   3       3.455  -0.215   4.877  1.00 31.11           C  
+ATOM     21  CZ  TYR A   3       2.650  -0.374   3.744  1.00 36.82           C  
+ATOM     22  OH  TYR A   3       1.297  -0.407   3.867  1.00 45.94           O  
+ATOM     23  N   LYS A   4       9.588  -0.749   2.216  1.00 25.97           N  
+ATOM     24  CA  LYS A   4      10.996  -0.492   1.999  1.00 26.02           C  
+ATOM     25  C   LYS A   4      11.389   0.887   2.512  1.00 27.15           C  
+ATOM     26  O   LYS A   4      10.856   1.920   2.077  1.00 29.78           O  
+ATOM     27  CB  LYS A   4      11.330  -0.599   0.521  1.00 28.74           C  
+ATOM     28  CG  LYS A   4      12.767  -0.182   0.231  1.00 41.18           C  
+ATOM     29  CD  LYS A   4      13.579  -1.258  -0.483  1.00 65.99           C  
+ATOM     30  CE  LYS A   4      13.898  -2.462   0.403  1.00 71.21           C  
+ATOM     31  NZ  LYS A   4      15.116  -3.169  -0.011  1.00100.00           N  
+ATOM     32  N   VAL A   5      12.331   0.863   3.439  1.00 25.81           N  
+ATOM     33  CA  VAL A   5      12.856   2.091   4.022  1.00 21.97           C  
+ATOM     34  C   VAL A   5      14.205   2.397   3.480  1.00 24.32           C  
+ATOM     35  O   VAL A   5      15.049   1.515   3.638  1.00 28.20           O  
+ATOM     36  CB  VAL A   5      12.952   2.019   5.546  1.00 26.13           C  
+ATOM     37  CG1 VAL A   5      13.589   3.279   6.154  1.00 24.03           C  
+ATOM     38  CG2 VAL A   5      11.587   1.886   6.220  1.00 28.00           C  
+ATOM     39  N   THR A   6      14.446   3.585   2.881  1.00 23.42           N  
+ATOM     40  CA  THR A   6      15.819   3.958   2.510  1.00 22.77           C  
+ATOM     41  C   THR A   6      16.295   5.055   3.506  1.00 27.61           C  
+ATOM     42  O   THR A   6      15.661   6.102   3.654  1.00 28.00           O  
+ATOM     43  CB  THR A   6      15.821   4.529   1.094  1.00 26.23           C  
+ATOM     44  OG1 THR A   6      15.370   3.515   0.217  1.00 27.15           O  
+ATOM     45  CG2 THR A   6      17.230   4.964   0.813  1.00 27.17           C  
+ATOM     46  N   LEU A   7      17.379   4.897   4.238  1.00 20.82           N  
+ATOM     47  CA  LEU A   7      17.815   5.979   5.096  1.00 18.17           C  
+ATOM     48  C   LEU A   7      19.102   6.537   4.478  1.00 26.80           C  
+ATOM     49  O   LEU A   7      20.054   5.815   4.166  1.00 31.28           O  
+ATOM     50  CB  LEU A   7      18.204   5.474   6.533  1.00 24.27           C  
+ATOM     51  CG  LEU A   7      17.064   4.808   7.373  1.00 25.99           C  
+ATOM     52  CD1 LEU A   7      17.597   4.132   8.670  1.00 28.24           C  
+ATOM     53  CD2 LEU A   7      15.847   5.760   7.582  1.00 23.18           C  
+ATOM     54  N   VAL A   8      19.178   7.825   4.390  1.00 24.64           N  
+ATOM     55  CA  VAL A   8      20.351   8.582   3.937  1.00 24.53           C  
+ATOM     56  C   VAL A   8      21.067   9.037   5.189  1.00 25.60           C  
+ATOM     57  O   VAL A   8      20.609  10.034   5.788  1.00 24.85           O  
+ATOM     58  CB  VAL A   8      19.949   9.817   3.074  1.00 26.13           C  
+ATOM     59  CG1 VAL A   8      21.154  10.667   2.669  1.00 26.51           C  
+ATOM     60  CG2 VAL A   8      19.153   9.301   1.862  1.00 23.87           C  
+ATOM     61  N   THR A   9      22.132   8.282   5.580  1.00 23.15           N  
+ATOM     62  CA  THR A   9      22.863   8.664   6.790  1.00 23.40           C  
+ATOM     63  C   THR A   9      24.173   9.314   6.438  1.00 33.13           C  
+ATOM     64  O   THR A   9      24.654   9.241   5.303  1.00 31.04           O  
+ATOM     65  CB  THR A   9      23.218   7.469   7.641  1.00 29.07           C  
+ATOM     66  OG1 THR A   9      24.437   6.916   7.123  1.00 34.25           O  
+ATOM     67  CG2 THR A   9      22.097   6.424   7.576  1.00 23.85           C  
+ATOM     68  N   PRO A  10      24.773   9.907   7.443  1.00 32.74           N  
+ATOM     69  CA  PRO A  10      26.012  10.626   7.192  1.00 40.21           C  
+ATOM     70  C   PRO A  10      27.145   9.843   6.552  1.00 39.02           C  
+ATOM     71  O   PRO A  10      27.994  10.367   5.811  1.00 40.41           O  
+ATOM     72  CB  PRO A  10      26.365  11.354   8.512  1.00 40.85           C  
+ATOM     73  CG  PRO A  10      25.100  11.360   9.383  1.00 38.81           C  
+ATOM     74  CD  PRO A  10      24.169  10.310   8.772  1.00 29.25           C  
+ATOM     75  N   THR A  11      27.149   8.583   6.860  1.00 29.69           N  
+ATOM     76  CA  THR A  11      28.191   7.741   6.370  1.00 31.68           C  
+ATOM     77  C   THR A  11      27.680   6.836   5.253  1.00 40.26           C  
+ATOM     78  O   THR A  11      28.315   5.815   4.937  1.00 32.78           O  
+ATOM     79  CB  THR A  11      28.745   6.892   7.546  1.00 35.16           C  
+ATOM     80  OG1 THR A  11      27.737   6.011   8.077  1.00 41.86           O  
+ATOM     81  CG2 THR A  11      29.280   7.785   8.637  1.00 34.63           C  
+ATOM     82  N   GLY A  12      26.479   7.095   4.715  1.00 29.29           N  
+ATOM     83  CA  GLY A  12      26.019   6.151   3.680  1.00 27.67           C  
+ATOM     84  C   GLY A  12      24.548   5.765   3.657  1.00 31.61           C  
+ATOM     85  O   GLY A  12      23.861   5.746   4.657  1.00 27.16           O  
+ATOM     86  N   ASN A  13      24.028   5.411   2.492  1.00 27.49           N  
+ATOM     87  CA  ASN A  13      22.641   4.967   2.352  1.00 28.15           C  
+ATOM     88  C   ASN A  13      22.472   3.508   2.820  1.00 34.35           C  
+ATOM     89  O   ASN A  13      23.261   2.592   2.523  1.00 34.29           O  
+ATOM     90  CB  ASN A  13      22.229   5.041   0.859  1.00 22.27           C  
+ATOM     91  CG  ASN A  13      22.215   6.448   0.279  1.00 28.56           C  
+ATOM     92  OD1 ASN A  13      22.151   7.484   0.966  1.00 29.38           O  
+ATOM     93  ND2 ASN A  13      22.260   6.532  -1.054  1.00 29.02           N  
+ATOM     94  N   VAL A  14      21.376   3.154   3.448  1.00 24.93           N  
+ATOM     95  CA  VAL A  14      21.199   1.768   3.845  1.00 24.17           C  
+ATOM     96  C   VAL A  14      19.689   1.494   3.624  1.00 35.26           C  
+ATOM     97  O   VAL A  14      18.847   2.366   3.880  1.00 34.14           O  
+ATOM     98  CB  VAL A  14      21.457   1.553   5.350  1.00 35.72           C  
+ATOM     99  CG1 VAL A  14      22.781   2.158   5.819  1.00 45.19           C  
+ATOM    100  CG2 VAL A  14      20.379   2.191   6.228  1.00 37.45           C  
+ATOM    101  N   GLU A  15      19.318   0.319   3.133  1.00 25.56           N  
+ATOM    102  CA  GLU A  15      17.873  -0.022   2.949  1.00 24.81           C  
+ATOM    103  C   GLU A  15      17.513  -1.257   3.780  1.00 28.51           C  
+ATOM    104  O   GLU A  15      18.367  -2.054   4.152  1.00 39.92           O  
+ATOM    105  CB  GLU A  15      17.528  -0.396   1.499  1.00 26.55           C  
+ATOM    106  CG  GLU A  15      18.058   0.554   0.428  1.00 76.87           C  
+ATOM    107  CD  GLU A  15      17.768   0.033  -0.987  1.00100.00           C  
+ATOM    108  OE1 GLU A  15      17.197  -1.116  -1.149  1.00 68.35           O  
+ATOM    109  OE2 GLU A  15      18.097   0.737  -2.014  1.00100.00           O  
+ATOM    110  N   PHE A  16      16.247  -1.431   4.065  1.00 26.52           N  
+ATOM    111  CA  PHE A  16      15.777  -2.608   4.823  1.00 28.30           C  
+ATOM    112  C   PHE A  16      14.244  -2.584   4.803  1.00 33.00           C  
+ATOM    113  O   PHE A  16      13.635  -1.520   4.649  1.00 30.39           O  
+ATOM    114  CB  PHE A  16      16.306  -2.569   6.266  1.00 32.53           C  
+ATOM    115  CG  PHE A  16      15.886  -1.332   7.078  1.00 25.02           C  
+ATOM    116  CD1 PHE A  16      14.640  -1.297   7.723  1.00 32.70           C  
+ATOM    117  CD2 PHE A  16      16.753  -0.235   7.192  1.00 28.27           C  
+ATOM    118  CE1 PHE A  16      14.269  -0.176   8.481  1.00 33.73           C  
+ATOM    119  CE2 PHE A  16      16.383   0.883   7.952  1.00 30.83           C  
+ATOM    120  CZ  PHE A  16      15.142   0.913   8.597  1.00 28.38           C  
+ATOM    121  N   GLN A  17      13.645  -3.759   4.941  1.00 35.55           N  
+ATOM    122  CA  GLN A  17      12.164  -3.892   4.941  1.00 33.09           C  
+ATOM    123  C   GLN A  17      11.622  -3.664   6.368  1.00 36.52           C  
+ATOM    124  O   GLN A  17      12.161  -4.187   7.348  1.00 34.16           O  
+ATOM    125  CB  GLN A  17      11.745  -5.297   4.473  1.00 40.84           C  
+ATOM    126  CG  GLN A  17      12.118  -5.610   3.015  1.00 75.19           C  
+ATOM    127  CD  GLN A  17      11.176  -5.056   1.937  1.00100.00           C  
+ATOM    128  OE1 GLN A  17      10.033  -5.500   1.819  1.00 91.53           O  
+ATOM    129  NE2 GLN A  17      11.600  -4.099   1.131  1.00 56.40           N  
+ATOM    130  N   CYS A  18      10.541  -2.882   6.483  1.00 32.45           N  
+ATOM    131  CA  CYS A  18       9.949  -2.554   7.813  1.00 34.72           C  
+ATOM    132  C   CYS A  18       8.464  -2.778   7.839  1.00 34.29           C  
+ATOM    133  O   CYS A  18       7.700  -2.208   7.075  1.00 31.05           O  
+ATOM    134  CB  CYS A  18      10.249  -1.090   8.161  1.00 29.02           C  
+ATOM    135  SG  CYS A  18       9.658  -0.587   9.853  1.00 28.94           S  
+ATOM    136  N   PRO A  19       8.085  -3.629   8.787  1.00 33.32           N  
+ATOM    137  CA  PRO A  19       6.690  -3.963   9.026  1.00 32.10           C  
+ATOM    138  C   PRO A  19       6.006  -2.702   9.499  1.00 40.78           C  
+ATOM    139  O   PRO A  19       6.592  -1.893  10.222  1.00 36.47           O  
+ATOM    140  CB  PRO A  19       6.661  -5.023  10.134  1.00 34.58           C  
+ATOM    141  CG  PRO A  19       8.108  -5.439  10.360  1.00 38.47           C  
+ATOM    142  CD  PRO A  19       9.005  -4.461   9.587  1.00 36.38           C  
+ATOM    143  N   ASP A  20       4.761  -2.545   9.044  1.00 34.47           N  
+ATOM    144  CA  ASP A  20       3.939  -1.390   9.316  1.00 33.10           C  
+ATOM    145  C   ASP A  20       3.594  -1.249  10.782  1.00 37.33           C  
+ATOM    146  O   ASP A  20       3.007  -0.234  11.167  1.00 33.51           O  
+ATOM    147  CB  ASP A  20       2.776  -1.182   8.329  1.00 44.18           C  
+ATOM    148  CG  ASP A  20       1.663  -2.172   8.473  1.00 58.88           C  
+ATOM    149  OD1 ASP A  20       1.737  -3.155   9.206  1.00 56.81           O  
+ATOM    150  OD2 ASP A  20       0.598  -1.806   7.784  1.00 79.64           O  
+ATOM    151  N   ASP A  21       3.977  -2.293  11.543  1.00 35.64           N  
+ATOM    152  CA  ASP A  21       3.728  -2.237  12.962  1.00 40.82           C  
+ATOM    153  C   ASP A  21       4.983  -2.105  13.764  1.00 45.13           C  
+ATOM    154  O   ASP A  21       4.965  -2.495  14.923  1.00 45.86           O  
+ATOM    155  CB  ASP A  21       2.706  -3.233  13.568  1.00 39.20           C  
+ATOM    156  CG  ASP A  21       3.075  -4.710  13.573  1.00 64.17           C  
+ATOM    157  OD1 ASP A  21       4.036  -5.157  12.965  1.00 61.46           O  
+ATOM    158  OD2 ASP A  21       2.230  -5.476  14.256  1.00 79.00           O  
+ATOM    159  N   VAL A  22       6.067  -1.601  13.191  1.00 30.02           N  
+ATOM    160  CA  VAL A  22       7.303  -1.467  13.989  1.00 23.17           C  
+ATOM    161  C   VAL A  22       7.875  -0.083  13.703  1.00 37.42           C  
+ATOM    162  O   VAL A  22       7.841   0.425  12.545  1.00 29.14           O  
+ATOM    163  CB  VAL A  22       8.279  -2.554  13.524  1.00 35.95           C  
+ATOM    164  CG1 VAL A  22       9.671  -2.333  14.072  1.00 33.42           C  
+ATOM    165  CG2 VAL A  22       7.790  -3.977  13.845  1.00 40.60           C  
+ATOM    166  N   TYR A  23       8.319   0.603  14.747  1.00 31.07           N  
+ATOM    167  CA  TYR A  23       8.868   1.922  14.526  1.00 23.20           C  
+ATOM    168  C   TYR A  23      10.146   1.813  13.697  1.00 20.53           C  
+ATOM    169  O   TYR A  23      10.967   0.886  13.815  1.00 22.64           O  
+ATOM    170  CB  TYR A  23       9.207   2.601  15.864  1.00 24.89           C  
+ATOM    171  CG  TYR A  23       8.048   2.917  16.813  1.00 29.11           C  
+ATOM    172  CD1 TYR A  23       6.967   3.710  16.422  1.00 25.37           C  
+ATOM    173  CD2 TYR A  23       8.087   2.419  18.126  1.00 29.47           C  
+ATOM    174  CE1 TYR A  23       5.959   3.981  17.342  1.00 33.05           C  
+ATOM    175  CE2 TYR A  23       7.167   2.794  19.097  1.00 27.42           C  
+ATOM    176  CZ  TYR A  23       6.100   3.579  18.677  1.00 29.98           C  
+ATOM    177  OH  TYR A  23       5.135   3.895  19.566  1.00 32.49           O  
+ATOM    178  N   ILE A  24      10.358   2.857  12.891  1.00 26.63           N  
+ATOM    179  CA  ILE A  24      11.544   3.002  12.045  1.00 23.62           C  
+ATOM    180  C   ILE A  24      12.848   2.723  12.839  1.00 27.47           C  
+ATOM    181  O   ILE A  24      13.721   1.942  12.446  1.00 25.11           O  
+ATOM    182  CB  ILE A  24      11.530   4.355  11.265  1.00 27.34           C  
+ATOM    183  CG1 ILE A  24      10.308   4.326  10.338  1.00 27.39           C  
+ATOM    184  CG2 ILE A  24      12.839   4.618  10.484  1.00 25.71           C  
+ATOM    185  CD1 ILE A  24      10.409   5.326   9.248  1.00 35.33           C  
+ATOM    186  N   LEU A  25      13.016   3.398  13.982  1.00 21.68           N  
+ATOM    187  CA  LEU A  25      14.226   3.232  14.751  1.00 23.19           C  
+ATOM    188  C   LEU A  25      14.494   1.805  15.152  1.00 19.67           C  
+ATOM    189  O   LEU A  25      15.622   1.287  15.036  1.00 21.97           O  
+ATOM    190  CB  LEU A  25      14.214   4.251  15.971  1.00 25.03           C  
+ATOM    191  CG  LEU A  25      15.399   4.134  16.985  1.00 33.85           C  
+ATOM    192  CD1 LEU A  25      16.767   4.626  16.432  1.00 28.22           C  
+ATOM    193  CD2 LEU A  25      15.003   4.794  18.321  1.00 23.35           C  
+ATOM    194  N   ASP A  26      13.445   1.170  15.740  1.00 21.80           N  
+ATOM    195  CA  ASP A  26      13.567  -0.238  16.197  1.00 24.22           C  
+ATOM    196  C   ASP A  26      13.968  -1.184  15.076  1.00 28.12           C  
+ATOM    197  O   ASP A  26      14.887  -2.035  15.191  1.00 26.29           O  
+ATOM    198  CB  ASP A  26      12.229  -0.815  16.715  1.00 26.64           C  
+ATOM    199  CG  ASP A  26      11.713  -0.170  18.009  1.00 37.98           C  
+ATOM    200  OD1 ASP A  26      12.168   0.845  18.458  1.00 46.55           O  
+ATOM    201  OD2 ASP A  26      10.581  -0.638  18.464  1.00 44.33           O  
+ATOM    202  N   ALA A  27      13.266  -0.995  13.938  1.00 28.45           N  
+ATOM    203  CA  ALA A  27      13.559  -1.804  12.709  1.00 30.31           C  
+ATOM    204  C   ALA A  27      15.013  -1.637  12.266  1.00 24.55           C  
+ATOM    205  O   ALA A  27      15.704  -2.620  11.990  1.00 26.78           O  
+ATOM    206  CB  ALA A  27      12.584  -1.510  11.550  1.00 27.80           C  
+ATOM    207  N   ALA A  28      15.467  -0.370  12.227  1.00 21.71           N  
+ATOM    208  CA  ALA A  28      16.844  -0.113  11.872  1.00 22.96           C  
+ATOM    209  C   ALA A  28      17.837  -0.801  12.830  1.00 31.14           C  
+ATOM    210  O   ALA A  28      18.866  -1.394  12.440  1.00 29.37           O  
+ATOM    211  CB  ALA A  28      17.190   1.365  11.769  1.00 30.64           C  
+ATOM    212  N   GLU A  29      17.519  -0.733  14.138  1.00 32.57           N  
+ATOM    213  CA  GLU A  29      18.383  -1.339  15.157  1.00 33.34           C  
+ATOM    214  C   GLU A  29      18.598  -2.824  14.926  1.00 23.91           C  
+ATOM    215  O   GLU A  29      19.748  -3.285  14.959  1.00 29.83           O  
+ATOM    216  CB  GLU A  29      17.921  -0.963  16.602  1.00 25.60           C  
+ATOM    217  CG  GLU A  29      18.305   0.502  16.913  1.00 24.44           C  
+ATOM    218  CD  GLU A  29      17.457   1.018  18.046  1.00 25.19           C  
+ATOM    219  OE1 GLU A  29      16.460   0.426  18.438  1.00 24.78           O  
+ATOM    220  OE2 GLU A  29      17.923   2.098  18.586  1.00 23.81           O  
+ATOM    221  N   GLU A  30      17.448  -3.455  14.709  1.00 27.47           N  
+ATOM    222  CA  GLU A  30      17.286  -4.882  14.380  1.00 37.83           C  
+ATOM    223  C   GLU A  30      18.140  -5.359  13.188  1.00 40.11           C  
+ATOM    224  O   GLU A  30      18.573  -6.495  13.120  1.00 39.63           O  
+ATOM    225  CB  GLU A  30      15.794  -5.252  14.170  1.00 40.07           C  
+ATOM    226  CG  GLU A  30      14.957  -5.155  15.458  1.00 42.44           C  
+ATOM    227  CD  GLU A  30      13.539  -5.612  15.275  1.00 56.36           C  
+ATOM    228  OE1 GLU A  30      13.164  -6.260  14.314  1.00 50.54           O  
+ATOM    229  OE2 GLU A  30      12.725  -5.114  16.174  1.00 36.99           O  
+ATOM    230  N   GLU A  31      18.344  -4.473  12.222  1.00 38.32           N  
+ATOM    231  CA  GLU A  31      19.177  -4.703  11.071  1.00 35.60           C  
+ATOM    232  C   GLU A  31      20.646  -4.398  11.378  1.00 52.16           C  
+ATOM    233  O   GLU A  31      21.518  -4.562  10.510  1.00 49.05           O  
+ATOM    234  CB  GLU A  31      18.620  -3.894   9.866  1.00 32.36           C  
+ATOM    235  CG  GLU A  31      17.343  -4.552   9.270  1.00 42.97           C  
+ATOM    236  CD  GLU A  31      17.511  -6.010   8.860  1.00 67.41           C  
+ATOM    237  OE1 GLU A  31      18.482  -6.441   8.262  1.00 80.04           O  
+ATOM    238  OE2 GLU A  31      16.571  -6.805   9.318  1.00 80.93           O  
+ATOM    239  N   GLY A  32      20.934  -3.911  12.608  1.00 36.45           N  
+ATOM    240  CA  GLY A  32      22.297  -3.587  13.006  1.00 31.78           C  
+ATOM    241  C   GLY A  32      22.778  -2.203  12.703  1.00 31.69           C  
+ATOM    242  O   GLY A  32      23.972  -1.976  12.642  1.00 34.57           O  
+ATOM    243  N   ILE A  33      21.850  -1.251  12.501  1.00 35.35           N  
+ATOM    244  CA  ILE A  33      22.177   0.144  12.177  1.00 28.42           C  
+ATOM    245  C   ILE A  33      22.256   1.009  13.444  1.00 33.98           C  
+ATOM    246  O   ILE A  33      21.378   0.942  14.287  1.00 32.45           O  
+ATOM    247  CB  ILE A  33      21.135   0.765  11.251  1.00 31.00           C  
+ATOM    248  CG1 ILE A  33      20.902  -0.025   9.950  1.00 47.25           C  
+ATOM    249  CG2 ILE A  33      21.426   2.216  10.846  1.00 27.16           C  
+ATOM    250  CD1 ILE A  33      19.920   0.766   9.061  1.00 51.98           C  
+ATOM    251  N   ASP A  34      23.258   1.860  13.579  1.00 31.29           N  
+ATOM    252  CA  ASP A  34      23.303   2.712  14.757  1.00 34.35           C  
+ATOM    253  C   ASP A  34      22.744   4.100  14.464  1.00 43.06           C  
+ATOM    254  O   ASP A  34      23.349   4.874  13.724  1.00 33.14           O  
+ATOM    255  CB  ASP A  34      24.761   2.854  15.196  1.00 38.16           C  
+ATOM    256  CG  ASP A  34      24.920   3.628  16.465  1.00 60.77           C  
+ATOM    257  OD1 ASP A  34      24.013   4.180  17.048  1.00 67.71           O  
+ATOM    258  OD2 ASP A  34      26.160   3.670  16.870  1.00100.00           O  
+ATOM    259  N   LEU A  35      21.606   4.432  15.063  1.00 25.84           N  
+ATOM    260  CA  LEU A  35      20.982   5.725  14.886  1.00 25.49           C  
+ATOM    261  C   LEU A  35      20.972   6.503  16.230  1.00 30.02           C  
+ATOM    262  O   LEU A  35      20.894   5.970  17.324  1.00 30.20           O  
+ATOM    263  CB  LEU A  35      19.524   5.626  14.330  1.00 29.86           C  
+ATOM    264  CG  LEU A  35      19.326   4.995  12.913  1.00 34.99           C  
+ATOM    265  CD1 LEU A  35      17.826   5.101  12.508  1.00 25.92           C  
+ATOM    266  CD2 LEU A  35      20.204   5.766  11.885  1.00 28.46           C  
+ATOM    267  N   PRO A  36      20.991   7.774  16.189  1.00 24.98           N  
+ATOM    268  CA  PRO A  36      20.915   8.450  17.496  1.00 27.92           C  
+ATOM    269  C   PRO A  36      19.519   8.369  18.150  1.00 34.05           C  
+ATOM    270  O   PRO A  36      18.406   8.438  17.518  1.00 24.43           O  
+ATOM    271  CB  PRO A  36      21.187   9.939  17.172  1.00 25.14           C  
+ATOM    272  CG  PRO A  36      21.223  10.101  15.644  1.00 33.38           C  
+ATOM    273  CD  PRO A  36      21.123   8.723  15.027  1.00 27.27           C  
+ATOM    274  N   TYR A  37      19.578   8.381  19.481  1.00 24.54           N  
+ATOM    275  CA  TYR A  37      18.347   8.494  20.237  1.00 24.90           C  
+ATOM    276  C   TYR A  37      18.650   8.899  21.687  1.00 44.09           C  
+ATOM    277  O   TYR A  37      19.790   8.838  22.140  1.00 28.24           O  
+ATOM    278  CB  TYR A  37      17.491   7.256  20.362  1.00 18.81           C  
+ATOM    279  CG  TYR A  37      18.233   6.159  21.122  1.00 24.63           C  
+ATOM    280  CD1 TYR A  37      19.137   5.311  20.464  1.00 26.04           C  
+ATOM    281  CD2 TYR A  37      18.018   5.944  22.486  1.00 29.97           C  
+ATOM    282  CE1 TYR A  37      19.817   4.294  21.132  1.00 30.23           C  
+ATOM    283  CE2 TYR A  37      18.673   4.912  23.167  1.00 24.88           C  
+ATOM    284  CZ  TYR A  37      19.581   4.091  22.501  1.00 30.95           C  
+ATOM    285  OH  TYR A  37      20.213   3.062  23.175  1.00 38.22           O  
+ATOM    286  N   SER A  38      17.595   9.277  22.418  1.00 29.18           N  
+ATOM    287  CA  SER A  38      17.725   9.558  23.845  1.00 32.26           C  
+ATOM    288  C   SER A  38      16.490   9.055  24.659  1.00 25.30           C  
+ATOM    289  O   SER A  38      16.606   7.975  25.282  1.00 25.32           O  
+ATOM    290  CB  SER A  38      18.302  10.927  24.200  1.00 22.00           C  
+ATOM    291  OG  SER A  38      17.293  11.869  24.016  1.00 33.52           O  
+ATOM    292  N   CYS A  39      15.380   9.816  24.591  1.00 23.71           N  
+ATOM    293  CA  CYS A  39      14.183   9.490  25.362  1.00 26.55           C  
+ATOM    294  C   CYS A  39      13.438   8.285  24.842  1.00 34.48           C  
+ATOM    295  O   CYS A  39      12.786   7.587  25.618  1.00 26.18           O  
+ATOM    296  CB  CYS A  39      13.199  10.697  25.491  1.00 29.83           C  
+ATOM    297  SG  CYS A  39      12.242  11.025  23.939  1.00 29.79           S  
+ATOM    298  N   ARG A  40      13.487   8.054  23.495  1.00 24.58           N  
+ATOM    299  CA  ARG A  40      12.723   6.913  22.913  1.00 28.18           C  
+ATOM    300  C   ARG A  40      11.205   7.064  23.170  1.00 30.09           C  
+ATOM    301  O   ARG A  40      10.487   6.085  23.025  1.00 31.35           O  
+ATOM    302  CB  ARG A  40      13.215   5.463  23.156  1.00 26.06           C  
+ATOM    303  CG  ARG A  40      14.725   5.291  22.954  1.00 26.48           C  
+ATOM    304  CD  ARG A  40      15.197   3.855  23.177  1.00 29.25           C  
+ATOM    305  NE  ARG A  40      14.665   2.882  22.173  1.00 29.50           N  
+ATOM    306  CZ  ARG A  40      15.384   2.358  21.164  1.00 24.32           C  
+ATOM    307  NH1 ARG A  40      16.675   2.663  20.962  1.00 22.08           N  
+ATOM    308  NH2 ARG A  40      14.730   1.522  20.369  1.00 24.44           N  
+ATOM    309  N   ALA A  41      10.703   8.251  23.551  1.00 30.98           N  
+ATOM    310  CA  ALA A  41       9.258   8.340  23.833  1.00 35.10           C  
+ATOM    311  C   ALA A  41       8.586   9.429  23.005  1.00 32.60           C  
+ATOM    312  O   ALA A  41       7.617   9.978  23.480  1.00 33.61           O  
+ATOM    313  CB  ALA A  41       9.061   8.685  25.305  1.00 32.00           C  
+ATOM    314  N   GLY A  42       9.184   9.924  21.887  1.00 37.71           N  
+ATOM    315  CA  GLY A  42       8.569  11.038  21.100  1.00 32.94           C  
+ATOM    316  C   GLY A  42       8.463  12.452  21.726  1.00 33.79           C  
+ATOM    317  O   GLY A  42       7.614  13.321  21.347  1.00 27.19           O  
+ATOM    318  N   SER A  43       9.383  12.734  22.670  1.00 29.21           N  
+ATOM    319  CA  SER A  43       9.217  14.009  23.222  1.00 27.72           C  
+ATOM    320  C   SER A  43      10.468  14.838  23.104  1.00 36.35           C  
+ATOM    321  O   SER A  43      10.575  15.886  23.772  1.00 37.69           O  
+ATOM    322  CB  SER A  43       8.702  13.848  24.657  1.00 41.18           C  
+ATOM    323  OG  SER A  43       9.762  13.391  25.438  1.00 37.35           O  
+ATOM    324  N   CYS A  44      11.424  14.383  22.281  1.00 24.01           N  
+ATOM    325  CA  CYS A  44      12.645  15.163  22.186  1.00 26.72           C  
+ATOM    326  C   CYS A  44      13.177  15.352  20.744  1.00 34.67           C  
+ATOM    327  O   CYS A  44      12.489  14.868  19.850  1.00 30.25           O  
+ATOM    328  CB  CYS A  44      13.745  14.604  23.122  1.00 22.69           C  
+ATOM    329  SG  CYS A  44      14.770  13.299  22.485  1.00 24.81           S  
+ATOM    330  N   SER A  45      14.308  16.078  20.499  1.00 24.73           N  
+ATOM    331  CA  SER A  45      14.777  16.268  19.112  1.00 26.39           C  
+ATOM    332  C   SER A  45      15.868  15.266  18.722  1.00 30.37           C  
+ATOM    333  O   SER A  45      16.412  15.218  17.615  1.00 28.25           O  
+ATOM    334  CB  SER A  45      15.275  17.674  18.949  1.00 27.38           C  
+ATOM    335  OG  SER A  45      16.431  17.813  19.806  1.00 29.38           O  
+ATOM    336  N   SER A  46      16.301  14.457  19.674  1.00 21.91           N  
+ATOM    337  CA  SER A  46      17.426  13.616  19.381  1.00 21.12           C  
+ATOM    338  C   SER A  46      17.353  12.724  18.144  1.00 25.42           C  
+ATOM    339  O   SER A  46      18.410  12.471  17.586  1.00 26.31           O  
+ATOM    340  CB  SER A  46      17.834  12.702  20.561  1.00 28.46           C  
+ATOM    341  OG  SER A  46      18.253  13.537  21.616  1.00 36.10           O  
+ATOM    342  N   CYS A  47      16.247  12.026  17.904  1.00 21.93           N  
+ATOM    343  CA  CYS A  47      16.202  11.056  16.827  1.00 21.80           C  
+ATOM    344  C   CYS A  47      15.649  11.698  15.536  1.00 21.02           C  
+ATOM    345  O   CYS A  47      15.149  10.997  14.648  1.00 23.37           O  
+ATOM    346  CB  CYS A  47      15.227   9.940  17.245  1.00 20.46           C  
+ATOM    347  SG  CYS A  47      13.560  10.572  17.479  1.00 24.27           S  
+ATOM    348  N   ALA A  48      15.664  12.998  15.481  1.00 23.57           N  
+ATOM    349  CA  ALA A  48      15.062  13.721  14.300  1.00 27.12           C  
+ATOM    350  C   ALA A  48      15.728  13.356  12.956  1.00 23.33           C  
+ATOM    351  O   ALA A  48      16.985  13.288  12.810  1.00 22.29           O  
+ATOM    352  CB  ALA A  48      15.001  15.246  14.459  1.00 23.21           C  
+ATOM    353  N   GLY A  49      14.841  13.313  11.994  1.00 26.74           N  
+ATOM    354  CA  GLY A  49      15.186  13.132  10.580  1.00 29.02           C  
+ATOM    355  C   GLY A  49      14.265  14.081   9.719  1.00 28.23           C  
+ATOM    356  O   GLY A  49      13.303  14.752  10.210  1.00 20.19           O  
+ATOM    357  N   LYS A  50      14.518  14.061   8.367  1.00 22.94           N  
+ATOM    358  CA  LYS A  50      13.710  14.863   7.373  1.00 21.93           C  
+ATOM    359  C   LYS A  50      13.181  13.817   6.316  1.00 27.46           C  
+ATOM    360  O   LYS A  50      13.986  13.010   5.743  1.00 22.40           O  
+ATOM    361  CB  LYS A  50      14.564  15.966   6.685  1.00 22.08           C  
+ATOM    362  CG  LYS A  50      14.605  17.254   7.500  1.00 70.03           C  
+ATOM    363  CD  LYS A  50      13.535  18.294   7.153  1.00 70.65           C  
+ATOM    364  CE  LYS A  50      14.198  19.537   6.556  1.00 95.81           C  
+ATOM    365  NZ  LYS A  50      13.315  20.498   5.873  1.00100.00           N  
+ATOM    366  N   LEU A  51      11.843  13.756   6.190  1.00 23.93           N  
+ATOM    367  CA  LEU A  51      11.182  12.820   5.242  1.00 22.04           C  
+ATOM    368  C   LEU A  51      11.343  13.464   3.811  1.00 26.89           C  
+ATOM    369  O   LEU A  51      11.019  14.617   3.489  1.00 26.02           O  
+ATOM    370  CB  LEU A  51       9.711  12.786   5.619  1.00 23.42           C  
+ATOM    371  CG  LEU A  51       8.853  12.151   4.557  1.00 26.07           C  
+ATOM    372  CD1 LEU A  51       9.040  10.663   4.609  1.00 32.32           C  
+ATOM    373  CD2 LEU A  51       7.389  12.360   4.843  1.00 35.33           C  
+ATOM    374  N   LYS A  52      11.980  12.719   2.963  1.00 24.44           N  
+ATOM    375  CA  LYS A  52      12.215  13.149   1.602  1.00 23.16           C  
+ATOM    376  C   LYS A  52      11.098  12.677   0.642  1.00 30.50           C  
+ATOM    377  O   LYS A  52      10.510  13.473  -0.152  1.00 32.15           O  
+ATOM    378  CB  LYS A  52      13.547  12.573   1.200  1.00 24.68           C  
+ATOM    379  CG  LYS A  52      14.590  13.069   2.203  1.00 61.41           C  
+ATOM    380  CD  LYS A  52      14.704  14.575   2.120  1.00 88.91           C  
+ATOM    381  CE  LYS A  52      15.163  15.276   3.378  1.00 99.36           C  
+ATOM    382  NZ  LYS A  52      15.668  16.630   3.069  1.00100.00           N  
+ATOM    383  N   THR A  53      10.723  11.429   0.796  1.00 22.25           N  
+ATOM    384  CA  THR A  53       9.693  10.822  -0.062  1.00 24.34           C  
+ATOM    385  C   THR A  53       8.818   9.802   0.661  1.00 27.89           C  
+ATOM    386  O   THR A  53       9.369   8.972   1.390  1.00 28.95           O  
+ATOM    387  CB  THR A  53      10.434   9.920  -1.104  1.00 31.58           C  
+ATOM    388  OG1 THR A  53      11.485  10.615  -1.745  1.00 36.65           O  
+ATOM    389  CG2 THR A  53       9.392   9.465  -2.097  1.00 28.92           C  
+ATOM    390  N   GLY A  54       7.520   9.785   0.437  1.00 23.82           N  
+ATOM    391  CA  GLY A  54       6.697   8.779   1.103  1.00 22.96           C  
+ATOM    392  C   GLY A  54       5.747   9.381   2.211  1.00 21.97           C  
+ATOM    393  O   GLY A  54       5.664  10.588   2.423  1.00 25.52           O  
+ATOM    394  N   SER A  55       5.072   8.494   2.960  1.00 25.22           N  
+ATOM    395  CA  SER A  55       4.154   8.875   4.011  1.00 28.49           C  
+ATOM    396  C   SER A  55       4.486   8.103   5.302  1.00 24.34           C  
+ATOM    397  O   SER A  55       4.973   6.965   5.258  1.00 27.68           O  
+ATOM    398  CB  SER A  55       2.761   8.352   3.609  1.00 29.79           C  
+ATOM    399  OG  SER A  55       2.398   8.865   2.336  1.00 41.45           O  
+ATOM    400  N   LEU A  56       4.183   8.723   6.426  1.00 26.66           N  
+ATOM    401  CA  LEU A  56       4.424   8.134   7.760  1.00 25.62           C  
+ATOM    402  C   LEU A  56       3.240   8.370   8.687  1.00 30.33           C  
+ATOM    403  O   LEU A  56       2.434   9.273   8.469  1.00 29.36           O  
+ATOM    404  CB  LEU A  56       5.559   8.867   8.490  1.00 26.75           C  
+ATOM    405  CG  LEU A  56       6.906   8.861   7.782  1.00 34.83           C  
+ATOM    406  CD1 LEU A  56       7.858   9.937   8.326  1.00 29.42           C  
+ATOM    407  CD2 LEU A  56       7.639   7.531   7.941  1.00 28.43           C  
+ATOM    408  N   ASN A  57       3.150   7.556   9.719  1.00 28.09           N  
+ATOM    409  CA  ASN A  57       2.162   7.782  10.791  1.00 24.87           C  
+ATOM    410  C   ASN A  57       2.970   8.183  12.032  1.00 23.91           C  
+ATOM    411  O   ASN A  57       3.748   7.365  12.556  1.00 25.64           O  
+ATOM    412  CB  ASN A  57       1.327   6.524  11.056  1.00 26.11           C  
+ATOM    413  CG  ASN A  57       0.408   6.647  12.288  1.00 35.12           C  
+ATOM    414  OD1 ASN A  57       0.559   7.569  13.092  1.00 40.95           O  
+ATOM    415  ND2 ASN A  57      -0.544   5.753  12.492  1.00 41.01           N  
+ATOM    416  N   GLN A  58       2.776   9.444  12.447  1.00 27.37           N  
+ATOM    417  CA  GLN A  58       3.511  10.052  13.595  1.00 31.76           C  
+ATOM    418  C   GLN A  58       2.582  10.362  14.800  1.00 34.04           C  
+ATOM    419  O   GLN A  58       2.879  11.183  15.671  1.00 29.19           O  
+ATOM    420  CB  GLN A  58       4.233  11.333  13.150  1.00 25.80           C  
+ATOM    421  CG  GLN A  58       5.444  11.050  12.242  1.00 28.40           C  
+ATOM    422  CD  GLN A  58       6.459  12.201  12.190  1.00 47.72           C  
+ATOM    423  OE1 GLN A  58       6.420  13.019  11.268  1.00 34.30           O  
+ATOM    424  NE2 GLN A  58       7.377  12.316  13.133  1.00 26.13           N  
+ATOM    425  N   ASP A  59       1.433   9.693  14.869  1.00 36.72           N  
+ATOM    426  CA  ASP A  59       0.490   9.937  15.971  1.00 38.66           C  
+ATOM    427  C   ASP A  59       1.091   9.815  17.356  1.00 35.94           C  
+ATOM    428  O   ASP A  59       0.654  10.514  18.266  1.00 39.04           O  
+ATOM    429  CB  ASP A  59      -0.584   8.841  15.935  1.00 42.70           C  
+ATOM    430  CG  ASP A  59      -1.530   8.991  14.788  1.00 46.32           C  
+ATOM    431  OD1 ASP A  59      -1.658  10.028  14.186  1.00 38.83           O  
+ATOM    432  OD2 ASP A  59      -2.364   7.994  14.691  1.00 59.49           O  
+ATOM    433  N   ASP A  60       1.995   8.847  17.545  1.00 24.98           N  
+ATOM    434  CA  ASP A  60       2.571   8.658  18.857  1.00 24.28           C  
+ATOM    435  C   ASP A  60       3.580   9.740  19.204  1.00 40.65           C  
+ATOM    436  O   ASP A  60       4.138   9.656  20.278  1.00 43.03           O  
+ATOM    437  CB  ASP A  60       3.322   7.326  18.890  1.00 27.18           C  
+ATOM    438  CG  ASP A  60       2.315   6.216  18.808  1.00 57.16           C  
+ATOM    439  OD1 ASP A  60       1.117   6.432  18.881  1.00 51.58           O  
+ATOM    440  OD2 ASP A  60       2.833   5.017  18.626  1.00 41.88           O  
+ATOM    441  N   GLN A  61       3.968  10.668  18.334  1.00 27.55           N  
+ATOM    442  CA  GLN A  61       4.973  11.625  18.768  1.00 30.08           C  
+ATOM    443  C   GLN A  61       4.316  12.872  19.438  1.00 40.72           C  
+ATOM    444  O   GLN A  61       3.179  13.216  19.124  1.00 34.19           O  
+ATOM    445  CB  GLN A  61       5.776  12.028  17.544  1.00 33.63           C  
+ATOM    446  CG  GLN A  61       5.117  13.131  16.681  1.00 25.93           C  
+ATOM    447  CD  GLN A  61       5.331  14.519  17.217  1.00 28.73           C  
+ATOM    448  OE1 GLN A  61       6.402  14.827  17.721  1.00 30.35           O  
+ATOM    449  NE2 GLN A  61       4.427  15.450  16.881  1.00 35.06           N  
+ATOM    450  N   SER A  62       4.967  13.636  20.333  1.00 27.75           N  
+ATOM    451  CA  SER A  62       4.283  14.824  20.910  1.00 30.90           C  
+ATOM    452  C   SER A  62       5.077  16.100  20.909  1.00 36.75           C  
+ATOM    453  O   SER A  62       4.690  17.110  21.441  1.00 52.66           O  
+ATOM    454  CB  SER A  62       3.864  14.633  22.379  1.00 35.95           C  
+ATOM    455  OG  SER A  62       4.952  14.105  23.125  1.00 46.21           O  
+ATOM    456  N   PHE A  63       6.252  16.067  20.384  1.00 29.60           N  
+ATOM    457  CA  PHE A  63       7.102  17.228  20.417  1.00 27.99           C  
+ATOM    458  C   PHE A  63       6.946  18.183  19.229  1.00 31.11           C  
+ATOM    459  O   PHE A  63       7.002  19.359  19.419  1.00 27.26           O  
+ATOM    460  CB  PHE A  63       8.530  16.630  20.559  1.00 25.49           C  
+ATOM    461  CG  PHE A  63       9.618  17.648  20.427  1.00 30.88           C  
+ATOM    462  CD1 PHE A  63       9.947  18.463  21.509  1.00 26.86           C  
+ATOM    463  CD2 PHE A  63      10.321  17.816  19.230  1.00 29.02           C  
+ATOM    464  CE1 PHE A  63      11.013  19.366  21.435  1.00 29.07           C  
+ATOM    465  CE2 PHE A  63      11.373  18.727  19.142  1.00 29.76           C  
+ATOM    466  CZ  PHE A  63      11.726  19.519  20.243  1.00 33.72           C  
+ATOM    467  N   LEU A  64       6.865  17.724  17.971  1.00 25.68           N  
+ATOM    468  CA  LEU A  64       6.831  18.662  16.842  1.00 24.82           C  
+ATOM    469  C   LEU A  64       5.450  19.287  16.739  1.00 26.70           C  
+ATOM    470  O   LEU A  64       4.460  18.591  16.986  1.00 31.40           O  
+ATOM    471  CB  LEU A  64       7.034  17.871  15.491  1.00 22.47           C  
+ATOM    472  CG  LEU A  64       8.369  17.086  15.396  1.00 29.46           C  
+ATOM    473  CD1 LEU A  64       8.417  16.185  14.142  1.00 30.53           C  
+ATOM    474  CD2 LEU A  64       9.647  17.977  15.456  1.00 24.48           C  
+ATOM    475  N   ASP A  65       5.405  20.538  16.305  1.00 28.62           N  
+ATOM    476  CA  ASP A  65       4.152  21.243  16.006  1.00 34.60           C  
+ATOM    477  C   ASP A  65       3.666  20.894  14.548  1.00 41.36           C  
+ATOM    478  O   ASP A  65       4.444  20.342  13.747  1.00 26.86           O  
+ATOM    479  CB  ASP A  65       4.279  22.755  16.344  1.00 31.77           C  
+ATOM    480  CG  ASP A  65       5.013  23.596  15.359  1.00 47.04           C  
+ATOM    481  OD1 ASP A  65       5.134  23.317  14.193  1.00 48.63           O  
+ATOM    482  OD2 ASP A  65       5.539  24.667  15.877  1.00 71.08           O  
+ATOM    483  N   ASP A  66       2.394  21.176  14.206  1.00 31.65           N  
+ATOM    484  CA  ASP A  66       1.862  20.859  12.888  1.00 33.85           C  
+ATOM    485  C   ASP A  66       2.718  21.427  11.772  1.00 38.51           C  
+ATOM    486  O   ASP A  66       2.894  20.807  10.719  1.00 38.50           O  
+ATOM    487  CB  ASP A  66       0.336  21.139  12.705  1.00 35.51           C  
+ATOM    488  CG  ASP A  66      -0.498  20.102  13.425  1.00 95.83           C  
+ATOM    489  OD1 ASP A  66      -0.319  18.893  13.287  1.00100.00           O  
+ATOM    490  OD2 ASP A  66      -1.318  20.615  14.323  1.00 84.76           O  
+ATOM    491  N   ASP A  67       3.271  22.611  12.040  1.00 33.26           N  
+ATOM    492  CA  ASP A  67       4.128  23.303  11.083  1.00 33.10           C  
+ATOM    493  C   ASP A  67       5.410  22.560  10.803  1.00 45.29           C  
+ATOM    494  O   ASP A  67       5.837  22.433   9.647  1.00 34.92           O  
+ATOM    495  CB  ASP A  67       4.521  24.678  11.546  1.00 31.04           C  
+ATOM    496  CG  ASP A  67       3.513  25.724  11.117  1.00 90.55           C  
+ATOM    497  OD1 ASP A  67       2.330  25.355  10.766  1.00 92.64           O  
+ATOM    498  OD2 ASP A  67       3.854  26.959  11.106  1.00100.00           O  
+ATOM    499  N   GLN A  68       6.015  22.094  11.853  1.00 38.59           N  
+ATOM    500  CA  GLN A  68       7.260  21.369  11.718  1.00 32.76           C  
+ATOM    501  C   GLN A  68       7.016  20.090  10.901  1.00 26.08           C  
+ATOM    502  O   GLN A  68       7.814  19.732  10.023  1.00 30.32           O  
+ATOM    503  CB  GLN A  68       7.820  21.057  13.091  1.00 22.57           C  
+ATOM    504  CG  GLN A  68       8.535  22.262  13.705  1.00 26.78           C  
+ATOM    505  CD  GLN A  68       8.904  22.067  15.173  1.00 35.57           C  
+ATOM    506  OE1 GLN A  68       8.118  21.511  15.936  1.00 29.91           O  
+ATOM    507  NE2 GLN A  68      10.069  22.499  15.619  1.00 29.90           N  
+ATOM    508  N   ILE A  69       5.903  19.435  11.205  1.00 25.11           N  
+ATOM    509  CA  ILE A  69       5.499  18.196  10.509  1.00 27.87           C  
+ATOM    510  C   ILE A  69       5.327  18.483   9.019  1.00 34.66           C  
+ATOM    511  O   ILE A  69       5.811  17.729   8.162  1.00 29.47           O  
+ATOM    512  CB  ILE A  69       4.171  17.674  11.063  1.00 32.70           C  
+ATOM    513  CG1 ILE A  69       4.302  17.089  12.470  1.00 40.33           C  
+ATOM    514  CG2 ILE A  69       3.565  16.559  10.207  1.00 29.13           C  
+ATOM    515  CD1 ILE A  69       5.045  15.752  12.495  1.00 32.83           C  
+ATOM    516  N   ASP A  70       4.637  19.573   8.776  1.00 31.86           N  
+ATOM    517  CA  ASP A  70       4.370  20.072   7.426  1.00 38.31           C  
+ATOM    518  C   ASP A  70       5.714  20.306   6.684  1.00 40.55           C  
+ATOM    519  O   ASP A  70       5.839  20.039   5.474  1.00 48.39           O  
+ATOM    520  CB  ASP A  70       3.604  21.400   7.532  1.00 52.17           C  
+ATOM    521  CG  ASP A  70       2.078  21.257   7.683  1.00 55.19           C  
+ATOM    522  OD1 ASP A  70       1.545  20.107   7.915  1.00 80.92           O  
+ATOM    523  OD2 ASP A  70       1.323  22.303   7.572  1.00 63.35           O  
+ATOM    524  N   GLU A  71       6.703  20.810   7.446  1.00 34.13           N  
+ATOM    525  CA  GLU A  71       8.074  21.120   6.933  1.00 34.15           C  
+ATOM    526  C   GLU A  71       8.794  19.823   6.526  1.00 30.41           C  
+ATOM    527  O   GLU A  71       9.763  19.846   5.748  1.00 35.23           O  
+ATOM    528  CB  GLU A  71       8.924  21.851   8.000  1.00 41.29           C  
+ATOM    529  CG  GLU A  71       8.882  23.387   7.868  1.00 64.85           C  
+ATOM    530  CD  GLU A  71      10.268  24.068   7.864  1.00100.00           C  
+ATOM    531  OE1 GLU A  71      11.290  23.479   8.387  1.00 55.31           O  
+ATOM    532  OE2 GLU A  71      10.413  25.243   7.337  1.00100.00           O  
+ATOM    533  N   GLY A  72       8.295  18.726   7.081  1.00 27.79           N  
+ATOM    534  CA  GLY A  72       8.784  17.369   6.766  1.00 32.80           C  
+ATOM    535  C   GLY A  72       9.646  16.761   7.895  1.00 32.09           C  
+ATOM    536  O   GLY A  72      10.348  15.757   7.699  1.00 25.25           O  
+ATOM    537  N   TRP A  73       9.595  17.356   9.076  1.00 22.23           N  
+ATOM    538  CA  TRP A  73      10.383  16.849  10.220  1.00 21.49           C  
+ATOM    539  C   TRP A  73       9.765  15.543  10.734  1.00 26.19           C  
+ATOM    540  O   TRP A  73       8.548  15.414  10.743  1.00 26.06           O  
+ATOM    541  CB  TRP A  73      10.454  17.886  11.341  1.00 23.52           C  
+ATOM    542  CG  TRP A  73      11.396  19.048  11.007  1.00 26.22           C  
+ATOM    543  CD1 TRP A  73      11.039  20.269  10.605  1.00 28.20           C  
+ATOM    544  CD2 TRP A  73      12.823  19.008  11.067  1.00 24.95           C  
+ATOM    545  NE1 TRP A  73      12.238  21.017  10.401  1.00 28.21           N  
+ATOM    546  CE2 TRP A  73      13.272  20.262  10.674  1.00 34.89           C  
+ATOM    547  CE3 TRP A  73      13.768  18.030  11.414  1.00 24.84           C  
+ATOM    548  CZ2 TRP A  73      14.626  20.610  10.598  1.00 32.01           C  
+ATOM    549  CZ3 TRP A  73      15.133  18.390  11.338  1.00 28.18           C  
+ATOM    550  CH2 TRP A  73      15.540  19.620  10.948  1.00 32.61           C  
+ATOM    551  N   VAL A  74      10.593  14.559  11.200  1.00 23.35           N  
+ATOM    552  CA  VAL A  74      10.113  13.267  11.705  1.00 26.91           C  
+ATOM    553  C   VAL A  74      10.908  12.880  12.956  1.00 21.84           C  
+ATOM    554  O   VAL A  74      12.136  13.080  12.973  1.00 22.56           O  
+ATOM    555  CB  VAL A  74      10.512  12.092  10.734  1.00 34.43           C  
+ATOM    556  CG1 VAL A  74       9.845  10.767  11.131  1.00 31.94           C  
+ATOM    557  CG2 VAL A  74      10.272  12.404   9.276  1.00 34.41           C  
+ATOM    558  N   LEU A  75      10.212  12.238  13.882  1.00 23.50           N  
+ATOM    559  CA  LEU A  75      10.892  11.635  15.066  1.00 25.89           C  
+ATOM    560  C   LEU A  75      10.923  10.134  14.847  1.00 21.88           C  
+ATOM    561  O   LEU A  75       9.878   9.418  14.894  1.00 24.28           O  
+ATOM    562  CB  LEU A  75      10.252  12.047  16.425  1.00 24.52           C  
+ATOM    563  CG  LEU A  75      10.262  13.564  16.716  1.00 29.19           C  
+ATOM    564  CD1 LEU A  75       9.589  13.895  18.095  1.00 27.15           C  
+ATOM    565  CD2 LEU A  75      11.679  14.128  16.642  1.00 24.99           C  
+ATOM    566  N   THR A  76      12.124   9.633  14.510  1.00 20.95           N  
+ATOM    567  CA  THR A  76      12.251   8.258  14.122  1.00 22.14           C  
+ATOM    568  C   THR A  76      11.899   7.212  15.221  1.00 25.69           C  
+ATOM    569  O   THR A  76      11.533   6.102  14.878  1.00 20.55           O  
+ATOM    570  CB  THR A  76      13.595   7.943  13.417  1.00 29.14           C  
+ATOM    571  OG1 THR A  76      14.619   8.070  14.358  1.00 22.12           O  
+ATOM    572  CG2 THR A  76      13.851   8.815  12.151  1.00 21.65           C  
+ATOM    573  N   CYS A  77      11.936   7.604  16.523  1.00 19.42           N  
+ATOM    574  CA  CYS A  77      11.573   6.588  17.500  1.00 23.31           C  
+ATOM    575  C   CYS A  77      10.080   6.382  17.585  1.00 23.91           C  
+ATOM    576  O   CYS A  77       9.604   5.521  18.330  1.00 27.19           O  
+ATOM    577  CB  CYS A  77      12.096   7.056  18.896  1.00 26.08           C  
+ATOM    578  SG  CYS A  77      11.280   8.530  19.603  1.00 24.96           S  
+ATOM    579  N   ALA A  78       9.316   7.248  16.935  1.00 20.23           N  
+ATOM    580  CA  ALA A  78       7.844   7.176  17.084  1.00 26.31           C  
+ATOM    581  C   ALA A  78       7.033   7.191  15.789  1.00 36.64           C  
+ATOM    582  O   ALA A  78       5.853   7.565  15.774  1.00 30.28           O  
+ATOM    583  CB  ALA A  78       7.355   8.353  17.931  1.00 24.52           C  
+ATOM    584  N   ALA A  79       7.710   6.814  14.700  1.00 29.72           N  
+ATOM    585  CA  ALA A  79       7.111   6.869  13.368  1.00 32.19           C  
+ATOM    586  C   ALA A  79       6.958   5.506  12.733  1.00 25.32           C  
+ATOM    587  O   ALA A  79       7.919   4.711  12.753  1.00 24.70           O  
+ATOM    588  CB  ALA A  79       7.896   7.902  12.468  1.00 25.97           C  
+ATOM    589  N   TYR A  80       5.749   5.231  12.211  1.00 25.90           N  
+ATOM    590  CA  TYR A  80       5.484   4.014  11.425  1.00 24.76           C  
+ATOM    591  C   TYR A  80       5.417   4.400   9.929  1.00 24.61           C  
+ATOM    592  O   TYR A  80       4.854   5.446   9.553  1.00 25.82           O  
+ATOM    593  CB  TYR A  80       4.219   3.175  11.706  1.00 26.45           C  
+ATOM    594  CG  TYR A  80       4.106   2.676  13.134  1.00 31.84           C  
+ATOM    595  CD1 TYR A  80       4.830   1.580  13.624  1.00 34.25           C  
+ATOM    596  CD2 TYR A  80       3.242   3.365  13.990  1.00 34.72           C  
+ATOM    597  CE1 TYR A  80       4.714   1.193  14.964  1.00 30.56           C  
+ATOM    598  CE2 TYR A  80       3.065   2.963  15.314  1.00 30.24           C  
+ATOM    599  CZ  TYR A  80       3.790   1.866  15.770  1.00 35.29           C  
+ATOM    600  OH  TYR A  80       3.624   1.546  17.078  1.00 51.62           O  
+ATOM    601  N   PRO A  81       6.018   3.558   9.080  1.00 27.26           N  
+ATOM    602  CA  PRO A  81       5.949   3.836   7.625  1.00 29.66           C  
+ATOM    603  C   PRO A  81       4.575   3.430   7.093  1.00 31.14           C  
+ATOM    604  O   PRO A  81       4.053   2.403   7.575  1.00 29.26           O  
+ATOM    605  CB  PRO A  81       6.936   2.848   6.980  1.00 28.79           C  
+ATOM    606  CG  PRO A  81       7.194   1.736   8.003  1.00 31.75           C  
+ATOM    607  CD  PRO A  81       6.736   2.280   9.352  1.00 26.94           C  
+ATOM    608  N   VAL A  82       3.960   4.235   6.214  1.00 27.18           N  
+ATOM    609  CA  VAL A  82       2.685   3.782   5.638  1.00 35.74           C  
+ATOM    610  C   VAL A  82       2.831   3.398   4.139  1.00 42.39           C  
+ATOM    611  O   VAL A  82       1.907   3.001   3.426  1.00 34.16           O  
+ATOM    612  CB  VAL A  82       1.424   4.610   5.984  1.00 36.83           C  
+ATOM    613  CG1 VAL A  82       1.091   4.669   7.474  1.00 37.46           C  
+ATOM    614  CG2 VAL A  82       1.473   6.001   5.423  1.00 34.29           C  
+ATOM    615  N   SER A  83       4.039   3.560   3.645  1.00 36.29           N  
+ATOM    616  CA  SER A  83       4.438   3.307   2.273  1.00 34.79           C  
+ATOM    617  C   SER A  83       5.941   3.232   2.282  1.00 35.38           C  
+ATOM    618  O   SER A  83       6.586   3.383   3.330  1.00 27.25           O  
+ATOM    619  CB  SER A  83       4.139   4.497   1.347  1.00 30.61           C  
+ATOM    620  OG  SER A  83       5.019   5.647   1.485  1.00 28.06           O  
+ATOM    621  N   ASP A  84       6.494   3.021   1.094  1.00 26.06           N  
+ATOM    622  CA  ASP A  84       7.922   3.058   1.040  1.00 30.29           C  
+ATOM    623  C   ASP A  84       8.379   4.468   1.376  1.00 30.65           C  
+ATOM    624  O   ASP A  84       7.718   5.431   0.999  1.00 31.40           O  
+ATOM    625  CB  ASP A  84       8.418   2.707  -0.338  1.00 29.55           C  
+ATOM    626  CG  ASP A  84       8.195   1.254  -0.617  1.00 40.79           C  
+ATOM    627  OD1 ASP A  84       7.890   0.313   0.155  1.00 34.20           O  
+ATOM    628  OD2 ASP A  84       8.405   1.151  -1.879  1.00 47.36           O  
+ATOM    629  N   VAL A  85       9.526   4.644   2.031  1.00 22.99           N  
+ATOM    630  CA  VAL A  85       9.939   6.010   2.333  1.00 20.82           C  
+ATOM    631  C   VAL A  85      11.478   6.190   2.308  1.00 24.03           C  
+ATOM    632  O   VAL A  85      12.262   5.206   2.513  1.00 27.17           O  
+ATOM    633  CB  VAL A  85       9.478   6.435   3.755  1.00 28.89           C  
+ATOM    634  CG1 VAL A  85       7.965   6.527   3.938  1.00 26.65           C  
+ATOM    635  CG2 VAL A  85      10.152   5.504   4.814  1.00 29.90           C  
+ATOM    636  N   THR A  86      11.848   7.460   1.993  1.00 20.22           N  
+ATOM    637  CA  THR A  86      13.198   7.883   2.071  1.00 21.23           C  
+ATOM    638  C   THR A  86      13.330   8.952   3.174  1.00 25.70           C  
+ATOM    639  O   THR A  86      12.605   9.949   3.191  1.00 22.59           O  
+ATOM    640  CB  THR A  86      13.718   8.431   0.769  1.00 23.30           C  
+ATOM    641  OG1 THR A  86      13.519   7.475  -0.260  1.00 26.36           O  
+ATOM    642  CG2 THR A  86      15.210   8.768   0.824  1.00 22.87           C  
+ATOM    643  N   ILE A  87      14.262   8.733   4.102  1.00 22.97           N  
+ATOM    644  CA  ILE A  87      14.463   9.665   5.240  1.00 23.87           C  
+ATOM    645  C   ILE A  87      15.949  10.014   5.452  1.00 19.36           C  
+ATOM    646  O   ILE A  87      16.814   9.140   5.475  1.00 24.47           O  
+ATOM    647  CB  ILE A  87      13.972   9.014   6.543  1.00 21.55           C  
+ATOM    648  CG1 ILE A  87      12.454   8.826   6.572  1.00 27.50           C  
+ATOM    649  CG2 ILE A  87      14.331   9.833   7.785  1.00 20.65           C  
+ATOM    650  CD1 ILE A  87      11.969   7.924   7.710  1.00 31.38           C  
+ATOM    651  N   GLU A  88      16.242  11.311   5.598  1.00 21.01           N  
+ATOM    652  CA  GLU A  88      17.622  11.757   5.934  1.00 22.22           C  
+ATOM    653  C   GLU A  88      17.735  11.750   7.465  1.00 27.78           C  
+ATOM    654  O   GLU A  88      16.941  12.400   8.152  1.00 24.12           O  
+ATOM    655  CB  GLU A  88      17.905  13.188   5.441  1.00 28.56           C  
+ATOM    656  CG  GLU A  88      17.653  13.397   3.950  1.00 41.70           C  
+ATOM    657  CD  GLU A  88      18.260  14.697   3.405  1.00 48.78           C  
+ATOM    658  OE1 GLU A  88      18.764  15.569   4.210  1.00 55.59           O  
+ATOM    659  OE2 GLU A  88      18.265  14.913   2.133  1.00 95.14           O  
+ATOM    660  N   THR A  89      18.708  11.014   7.991  1.00 21.38           N  
+ATOM    661  CA  THR A  89      18.881  10.871   9.468  1.00 25.41           C  
+ATOM    662  C   THR A  89      19.936  11.870  10.028  1.00 30.23           C  
+ATOM    663  O   THR A  89      20.541  12.649   9.288  1.00 22.22           O  
+ATOM    664  CB  THR A  89      19.313   9.435   9.803  1.00 24.95           C  
+ATOM    665  OG1 THR A  89      20.566   9.146   9.196  1.00 26.36           O  
+ATOM    666  CG2 THR A  89      18.316   8.369   9.323  1.00 23.11           C  
+ATOM    667  N   HIS A  90      20.129  11.829  11.361  1.00 29.25           N  
+ATOM    668  CA  HIS A  90      21.114  12.699  12.096  1.00 30.89           C  
+ATOM    669  C   HIS A  90      20.896  14.194  11.746  1.00 19.65           C  
+ATOM    670  O   HIS A  90      21.807  14.876  11.254  1.00 24.29           O  
+ATOM    671  CB  HIS A  90      22.552  12.359  11.680  1.00 23.67           C  
+ATOM    672  CG  HIS A  90      22.966  10.925  12.015  1.00 28.74           C  
+ATOM    673  ND1 HIS A  90      22.367   9.824  11.412  1.00 25.05           N  
+ATOM    674  CD2 HIS A  90      23.901  10.429  12.868  1.00 25.95           C  
+ATOM    675  CE1 HIS A  90      22.932   8.732  11.896  1.00 26.62           C  
+ATOM    676  NE2 HIS A  90      23.848   9.075  12.766  1.00 27.96           N  
+ATOM    677  N   LYS A  91      19.692  14.702  12.017  1.00 21.85           N  
+ATOM    678  CA  LYS A  91      19.328  16.104  11.671  1.00 24.48           C  
+ATOM    679  C   LYS A  91      18.969  16.961  12.899  1.00 22.53           C  
+ATOM    680  O   LYS A  91      18.507  18.105  12.767  1.00 24.20           O  
+ATOM    681  CB  LYS A  91      18.092  16.125  10.769  1.00 24.74           C  
+ATOM    682  CG  LYS A  91      18.394  15.720   9.329  1.00 33.72           C  
+ATOM    683  CD  LYS A  91      19.267  16.737   8.594  1.00 33.40           C  
+ATOM    684  CE  LYS A  91      19.650  16.284   7.184  1.00 56.58           C  
+ATOM    685  NZ  LYS A  91      20.051  17.398   6.313  1.00 70.22           N  
+ATOM    686  N   LYS A  92      19.193  16.402  14.066  1.00 29.41           N  
+ATOM    687  CA  LYS A  92      18.862  17.064  15.343  1.00 29.57           C  
+ATOM    688  C   LYS A  92      19.404  18.499  15.416  1.00 31.36           C  
+ATOM    689  O   LYS A  92      18.727  19.418  15.897  1.00 30.72           O  
+ATOM    690  CB  LYS A  92      19.478  16.299  16.516  1.00 28.26           C  
+ATOM    691  CG  LYS A  92      19.717  17.184  17.743  1.00 42.15           C  
+ATOM    692  CD  LYS A  92      19.736  16.395  19.054  1.00 58.10           C  
+ATOM    693  CE  LYS A  92      21.130  16.311  19.680  1.00 74.57           C  
+ATOM    694  NZ  LYS A  92      21.096  16.204  21.146  1.00 73.77           N  
+ATOM    695  N   GLU A  93      20.609  18.655  14.934  1.00 25.37           N  
+ATOM    696  CA  GLU A  93      21.334  19.926  15.008  1.00 33.41           C  
+ATOM    697  C   GLU A  93      20.816  20.964  13.971  1.00 34.04           C  
+ATOM    698  O   GLU A  93      21.217  22.136  13.972  1.00 37.10           O  
+ATOM    699  CB  GLU A  93      22.827  19.630  14.806  1.00 36.08           C  
+ATOM    700  CG  GLU A  93      23.635  19.664  16.121  1.00100.00           C  
+ATOM    701  CD  GLU A  93      23.858  18.339  16.907  1.00100.00           C  
+ATOM    702  OE1 GLU A  93      22.862  17.695  17.423  1.00100.00           O  
+ATOM    703  OE2 GLU A  93      25.060  17.880  17.081  1.00100.00           O  
+ATOM    704  N   GLU A  94      19.911  20.554  13.095  1.00 33.03           N  
+ATOM    705  CA  GLU A  94      19.390  21.462  12.044  1.00 33.87           C  
+ATOM    706  C   GLU A  94      17.957  21.905  12.326  1.00 30.08           C  
+ATOM    707  O   GLU A  94      17.403  22.771  11.634  1.00 29.33           O  
+ATOM    708  CB  GLU A  94      19.373  20.759  10.693  1.00 36.71           C  
+ATOM    709  CG  GLU A  94      20.771  20.470  10.160  1.00 52.81           C  
+ATOM    710  CD  GLU A  94      20.788  20.210   8.656  1.00100.00           C  
+ATOM    711  OE1 GLU A  94      19.722  20.405   7.957  1.00 57.89           O  
+ATOM    712  OE2 GLU A  94      21.868  19.796   8.088  1.00 85.85           O  
+ATOM    713  N   LEU A  95      17.393  21.306  13.332  1.00 26.01           N  
+ATOM    714  CA  LEU A  95      16.011  21.563  13.709  1.00 26.71           C  
+ATOM    715  C   LEU A  95      15.801  23.027  14.206  1.00 33.16           C  
+ATOM    716  O   LEU A  95      16.584  23.603  15.002  1.00 28.74           O  
+ATOM    717  CB  LEU A  95      15.601  20.616  14.840  1.00 24.05           C  
+ATOM    718  CG  LEU A  95      14.137  20.768  15.253  1.00 37.37           C  
+ATOM    719  CD1 LEU A  95      13.161  20.208  14.216  1.00 39.22           C  
+ATOM    720  CD2 LEU A  95      13.808  20.048  16.563  1.00 48.43           C  
+ATOM    721  N   THR A  96      14.690  23.657  13.803  1.00 24.29           N  
+ATOM    722  CA  THR A  96      14.357  24.971  14.259  1.00 20.50           C  
+ATOM    723  C   THR A  96      12.842  25.027  14.364  1.00 29.60           C  
+ATOM    724  O   THR A  96      12.150  24.097  13.856  1.00 27.87           O  
+ATOM    725  CB  THR A  96      14.675  26.113  13.293  1.00 29.55           C  
+ATOM    726  OG1 THR A  96      13.917  25.851  12.128  1.00 30.05           O  
+ATOM    727  CG2 THR A  96      16.120  26.211  13.007  1.00 23.85           C  
+ATOM    728  N   ALA A  97      12.313  26.090  15.052  1.00 27.16           N  
+ATOM    729  CA  ALA A  97      10.851  26.183  15.191  1.00 37.74           C  
+ATOM    730  C   ALA A  97      10.166  26.814  14.004  1.00 64.29           C  
+ATOM    731  O   ALA A  97       9.815  27.983  14.121  1.00100.00           O  
+ATOM    732  CB  ALA A  97      10.299  26.681  16.508  1.00 35.84           C  
+TER     733      ALA A  97                                                      
+HETATM  734 FE1  FES A1602      13.398  11.548  21.999  1.00 26.97          FE  
+HETATM  735 FE2  FES A1602      12.925  10.090  19.701  1.00 26.54          FE  
+HETATM  736  S1  FES A1602      14.657   9.885  21.071  1.00 26.27           S  
+HETATM  737  S2  FES A1602      11.681  11.837  20.546  1.00 27.47           S  
+HETATM  738  O   HOH A1603      20.314   3.189  17.662  1.00 28.40           O  
+HETATM  739  O   HOH A1604      19.136  13.499  14.797  1.00 27.63           O  
+HETATM  740  O   HOH A1605      15.839  17.655  22.569  1.00 31.32           O  
+HETATM  741  O   HOH A1606      13.340  -3.911  18.366  1.00 31.87           O  
+HETATM  742  O   HOH A1607      17.589   8.577  14.886  1.00 25.57           O  
+HETATM  743  O   HOH A1608       3.158   6.964  15.663  1.00 32.70           O  
+HETATM  744  O   HOH A1609      12.607   3.196   0.028  1.00 35.81           O  
+HETATM  745  O   HOH A1610      17.941  10.294  12.971  1.00 28.21           O  
+HETATM  746  O   HOH A1611       1.926   1.370   9.724  1.00 37.77           O  
+HETATM  747  O   HOH A1612      11.412   3.410  19.732  1.00 37.42           O  
+HETATM  748  O   HOH A1613       8.807  17.793  25.373  1.00 41.85           O  
+HETATM  749  O   HOH A1614       3.590  11.528   5.863  1.00 39.49           O  
+HETATM  750  O   HOH A1615      25.052   1.593  11.348  1.00 43.97           O  
+HETATM  751  O   HOH A1616      -6.196   7.375  14.972  1.00 75.86           O  
+HETATM  752  O   HOH A1617       8.534  -0.956  17.306  1.00 37.45           O  
+HETATM  753  O   HOH A1618       6.639  15.107   8.525  1.00 36.12           O  
+HETATM  754  O   HOH A1619      22.246   2.005  21.737  1.00 36.05           O  
+HETATM  755  O   HOH A1620      14.535  -4.507  10.197  1.00 55.68           O  
+HETATM  756  O   HOH A1621       4.876   2.526  -1.355  1.00 41.58           O  
+HETATM  757  O   HOH A1622      11.330   5.913  -0.990  1.00 42.42           O  
+HETATM  758  O   HOH A1623       8.224   5.865  20.826  1.00 41.41           O  
+HETATM  759  O   HOH A1624      22.831   5.923  19.420  1.00 45.06           O  
+HETATM  760  O   HOH A1625      14.917  23.836  10.267  1.00 40.43           O  
+HETATM  761  O   HOH A1626      11.139  24.357  10.914  1.00 63.90           O  
+HETATM  762  O   HOH A1627      11.625  17.756   3.797  1.00 64.36           O  
+HETATM  763  O   HOH A1628       0.872  11.720  21.228  1.00 66.38           O  
+HETATM  764  O   HOH A1629      -0.211   4.813  15.867  1.00 63.96           O  
+HETATM  765  O   HOH A1630      20.658  -7.095   8.049  1.00 67.10           O  
+HETATM  766  O   HOH A1631      24.043   4.181  -2.687  1.00 53.06           O  
+HETATM  767  O   HOH A1632      21.936   6.378  21.945  1.00 55.43           O  
+HETATM  768  O   HOH A1633      19.025  24.652  14.863  1.00 51.35           O  
+HETATM  769  O   HOH A1634      11.308   8.680  28.143  1.00 44.39           O  
+HETATM  770  O   HOH A1635      -0.428   0.927   5.386  1.00 85.08           O  
+HETATM  771  O   HOH A1636      21.798  10.879  23.320  1.00 52.42           O  
+HETATM  772  O   HOH A1637       3.239   6.955  -0.065  1.00 55.66           O  
+HETATM  773  O   HOH A1638      22.779   2.365  18.908  1.00 43.93           O  
+HETATM  774  O   HOH A1639      24.188   5.146  11.189  1.00 45.31           O  
+HETATM  775  O   HOH A1640      -1.683  -0.913   1.878  1.00 69.36           O  
+HETATM  776  O   HOH A1641       8.696   6.563  -1.677  1.00 58.88           O  
+HETATM  777  O   HOH A1642       7.367  26.197  14.480  1.00 49.47           O  
+HETATM  778  O   HOH A1643       6.591  -1.657  -1.410  1.00 85.37           O  
+HETATM  779  O   HOH A1644       7.606  18.977   3.435  1.00 63.19           O  
+HETATM  780  O   HOH A1645      -3.822  10.414  11.859  1.00 57.70           O  
+HETATM  781  O   HOH A1646      21.749  12.594   6.625  1.00 51.80           O  
+HETATM  782  O   HOH A1647      23.131   4.812  23.785  1.00 50.20           O  
+HETATM  783  O   HOH A1648      16.610   3.001  -2.612  1.00 56.90           O  
+HETATM  784  O   HOH A1649      22.528  16.502  13.897  1.00 55.79           O  
+HETATM  785  O   HOH A1650      26.500   7.848  10.348  1.00 68.43           O  
+HETATM  786  O   HOH A1651       3.851  12.983   3.178  1.00 49.71           O  
+HETATM  787  O   HOH A1652      19.786  18.726  20.646  1.00 45.90           O  
+HETATM  788  O   HOH A1653      18.145  27.680   9.755  1.00 64.26           O  
+HETATM  789  O   HOH A1654      17.574  -8.112   7.017  1.00 76.51           O  
+HETATM  790  O   HOH A1655      22.282  13.839  15.539  1.00 60.51           O  
+HETATM  791  O   HOH A1656      21.110  -7.809  14.066  1.00 66.51           O  
+HETATM  792  O   HOH A1657      25.732  22.369  16.313  1.00 59.47           O  
+HETATM  793  O   HOH A1658      13.415   9.318  -2.947  1.00 59.85           O  
+HETATM  794  O   HOH A1659      13.899  22.771   7.168  1.00 63.98           O  
+HETATM  795  O   HOH A1660      27.481   5.665  17.885  1.00 79.40           O  
+HETATM  796  O   HOH A1661       8.580  -4.372  17.408  1.00 60.41           O  
+HETATM  797  O   HOH A1662      24.876   4.074   8.926  1.00 71.07           O  
+HETATM  798  O   HOH A1663      10.525  -6.340  15.708  1.00 53.48           O  
+HETATM  799  O   HOH A1664      -1.284   5.529  19.201  1.00 68.40           O  
+HETATM  800  O   HOH A1665      15.014  11.978  -2.461  1.00 64.00           O  
+HETATM  801  O   HOH A1666      14.106  -9.236   2.519  1.00 67.28           O  
+HETATM  802  O   HOH A1667      14.062  29.978  13.852  1.00 84.39           O  
+HETATM  803  O   HOH A1668       6.500   2.082  -3.927  1.00 73.15           O  
+HETATM  804  O   HOH A1669      -3.999  12.915  12.023  1.00 70.07           O  
+HETATM  805  O   HOH A1670      22.522  10.655  20.491  1.00 62.92           O  
+HETATM  806  O   HOH A1671       5.802  -4.428  16.828  1.00 64.57           O  
+HETATM  807  O   HOH A1672      -0.285  -5.312   2.050  1.00 83.51           O  
+HETATM  808  O   HOH A1673      -0.266   3.144  11.216  1.00 68.25           O  
+HETATM  809  O   HOH A1674      25.407  13.378  14.852  1.00 80.99           O  
+HETATM  810  O   HOH A1675      15.568   7.564  -2.586  1.00 71.16           O  
+HETATM  811  O   HOH A1676       4.787  10.976  22.962  1.00 65.51           O  
+HETATM  812  O   HOH A1677      25.854  23.790  19.080  1.00 69.96           O  
+HETATM  813  O   HOH A1678       6.047  15.849  24.673  1.00 76.93           O  
+HETATM  814  O   HOH A1679       3.270  10.385  25.458  1.00 68.03           O  
+HETATM  815  O   HOH A1680      17.147 -11.645  -0.378  1.00 76.39           O  
+HETATM  816  O   HOH A1681       3.889  11.272  28.440  1.00 57.34           O  
+HETATM  817  O   HOH A1682       0.829  10.575   6.206  1.00 61.71           O  
+HETATM  818  O   HOH A1683      -2.192  14.658  14.063  1.00 83.95           O  
+CONECT  297  734                                                                
+CONECT  329  734                                                                
+CONECT  347  735                                                                
+CONECT  578  735                                                                
+CONECT  734  297  329  736  737                                                 
+CONECT  735  347  578  736  737                                                 
+CONECT  736  734  735                                                           
+CONECT  737  734  735                                                           
+MASTER      253    0    1    4    5    0    2    6  817    1    8    8          
+END                                                                             
index c472576..62d76a2 100644 (file)
@@ -180,7 +180,7 @@ public class AnnotatedPDBFileInputTest
   /**
    * @throws java.lang.Exception
    */
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
     jalview.gui.Desktop.instance.closeAll_actionPerformed(null);
index 385e049..2f5d0c5 100644 (file)
@@ -26,14 +26,14 @@ import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.api.FeatureColourI;
+import jalview.api.FeatureRenderer;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceDummy;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
-import jalview.schemes.AnnotationColourGradient;
-import jalview.schemes.GraduatedColor;
 
 import java.awt.Color;
 import java.io.File;
@@ -53,7 +53,7 @@ public class FeaturesFileTest
     File f = new File("examples/uniref50.fa");
     AlignmentI al = readAlignmentFile(f);
     AlignFrame af = new AlignFrame(al, 500, 500);
-    Map<String, Object> colours = af.getFeatureRenderer()
+    Map<String, FeatureColourI> colours = af.getFeatureRenderer()
             .getFeatureColours();
     FeaturesFile featuresFile = new FeaturesFile(
             "examples/exampleFeatures.txt", FormatAdapter.FILE);
@@ -67,61 +67,71 @@ public class FeaturesFileTest
      */
     colours = af.getFeatureRenderer().getFeatureColours();
     assertEquals("26 feature group colours not found", 26, colours.size());
-    assertEquals(colours.get("Cath"), new Color(0x93b1d1));
-    assertEquals(colours.get("ASX-MOTIF"), new Color(0x6addbb));
+    assertEquals(colours.get("Cath").getColour(), new Color(0x93b1d1));
+    assertEquals(colours.get("ASX-MOTIF").getColour(), new Color(0x6addbb));
 
     /*
      * verify (some) features on sequences
      */
     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);
@@ -140,7 +150,7 @@ public class FeaturesFileTest
     File f = new File("examples/uniref50.fa");
     AlignmentI al = readAlignmentFile(f);
     AlignFrame af = new AlignFrame(al, 500, 500);
-    Map<String, Object> colours = af.getFeatureRenderer()
+    Map<String, FeatureColourI> colours = af.getFeatureRenderer()
             .getFeatureColours();
     // GFF2 uses space as name/value separator in column 9
     String gffData = "METAL\tcc9900\n" + "GFF\n"
@@ -154,7 +164,7 @@ public class FeaturesFileTest
     // verify colours read or synthesized
     colours = af.getFeatureRenderer().getFeatureColours();
     assertEquals("1 feature group colours not found", 1, colours.size());
-    assertEquals(colours.get("METAL"), new Color(0xcc9900));
+    assertEquals(colours.get("METAL").getColour(), new Color(0xcc9900));
 
     // verify feature on FER_CAPAA
     SequenceFeature[] sfs = al.getSequenceAt(0).getDatasetSequence()
@@ -195,45 +205,6 @@ public class FeaturesFileTest
   }
 
   /**
-   * Test various ways of describing a feature colour scheme
-   * 
-   * @throws Exception
-   */
-  @Test(groups = { "Functional" })
-  public void testParseGraduatedColourScheme() throws Exception
-  {
-    FeaturesFile ff = new FeaturesFile();
-
-    // colour by label:
-    GraduatedColor gc = ff.parseGraduatedColourScheme(
-            "BETA-TURN-IR\t9a6a94", "label");
-    assertTrue(gc.isColourByLabel());
-    assertEquals(Color.white, gc.getMinColor());
-    assertEquals(Color.black, gc.getMaxColor());
-    assertTrue(gc.isAutoScale());
-
-    // using colour name, rgb, etc:
-    String spec = "blue|255,0,255|absolute|20.0|95.0|below|66.0";
-    gc = ff.parseGraduatedColourScheme("BETA-TURN-IR\t" + spec, spec);
-    assertFalse(gc.isColourByLabel());
-    assertEquals(Color.blue, gc.getMinColor());
-    assertEquals(new Color(255, 0, 255), gc.getMaxColor());
-    assertFalse(gc.isAutoScale());
-    assertFalse(gc.getTolow());
-    assertEquals(20.0f, gc.getMin(), 0.001f);
-    assertEquals(95.0f, gc.getMax(), 0.001f);
-    assertEquals(AnnotationColourGradient.BELOW_THRESHOLD,
-            gc.getThreshType());
-    assertEquals(66.0f, gc.getThresh(), 0.001f);
-
-    // inverse gradient high to low:
-    spec = "blue|255,0,255|95.0|20.0|below|66.0";
-    gc = ff.parseGraduatedColourScheme("BETA-TURN-IR\t" + spec, spec);
-    assertTrue(gc.isAutoScale());
-    assertTrue(gc.getTolow());
-  }
-
-  /**
    * Test parsing a features file with GFF formatted content only
    * 
    * @throws Exception
@@ -244,7 +215,7 @@ public class FeaturesFileTest
     File f = new File("examples/uniref50.fa");
     AlignmentI al = readAlignmentFile(f);
     AlignFrame af = new AlignFrame(al, 500, 500);
-    Map<String, Object> colours = af.getFeatureRenderer()
+    Map<String, FeatureColourI> colours = af.getFeatureRenderer()
             .getFeatureColours();
     // GFF3 uses '=' separator for name/value pairs in colum 9
     String gffData = "##gff-version 3\n"
@@ -296,7 +267,7 @@ public class FeaturesFileTest
     File f = new File("examples/uniref50.fa");
     AlignmentI al = readAlignmentFile(f);
     AlignFrame af = new AlignFrame(al, 500, 500);
-    Map<String, Object> colours = af.getFeatureRenderer()
+    Map<String, FeatureColourI> colours = af.getFeatureRenderer()
             .getFeatureColours();
 
     /*
@@ -412,4 +383,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, FeatureColourI> 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, FeatureColourI> 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 cde1cbc..2eb3703 100644 (file)
@@ -46,7 +46,7 @@ public class FileIOTester
   /**
    * @throws java.lang.Exception
    */
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
   }
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 d327134..93fb12b 100644 (file)
@@ -262,7 +262,7 @@ public class JSONFileTest
     passedCount = 0;
   }
 
-  @AfterTest
+  @AfterTest(alwaysRun = true)
   public void tearDown() throws Exception
   {
     testJsonFile = null;
index b58a8a6..a77e10a 100644 (file)
  */
 package jalview.io;
 
+import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.ViewStyleI;
 import jalview.bin.Cache;
 import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
@@ -34,8 +38,13 @@ import jalview.gui.Desktop;
 import jalview.gui.Jalview2XML;
 import jalview.schemes.AnnotationColourGradient;
 import jalview.schemes.ColourSchemeI;
+import jalview.viewmodel.AlignmentViewport;
 
 import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import org.testng.Assert;
 import org.testng.AssertJUnit;
@@ -43,6 +52,7 @@ import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+@Test(singleThreaded = true)
 public class Jalview2xmlTests
 {
 
@@ -59,14 +69,13 @@ public class Jalview2xmlTests
   /**
    * @throws java.lang.Exception
    */
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
     jalview.gui.Desktop.instance.closeAll_actionPerformed(null);
-
   }
 
-  public int countDsAnn(jalview.viewmodel.AlignmentViewport avp)
+  int countDsAnn(jalview.viewmodel.AlignmentViewport avp)
   {
     int numdsann = 0;
     for (SequenceI sq : avp.getAlignment().getDataset().getSequences())
@@ -358,7 +367,7 @@ public class Jalview2xmlTests
    * 
    * @throws Exception
    */
-  @Test(groups = { "Functional" }, enabled = false)
+  @Test(groups = { "Functional" }, enabled = true)
   public void testStoreAndRecoverExpandedviews() throws Exception
   {
     AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
@@ -413,6 +422,123 @@ public class Jalview2xmlTests
             Desktop.getAlignmentPanels(af.getViewport().getSequenceSetId()).length);
   }
 
+  /**
+   * Test save and reload of a project with a different representative sequence
+   * in each view.
+   * 
+   * @throws Exception
+   */
+  @Test(groups = { "Functional" })
+  public void testStoreAndRecoverReferenceSeqSettings() throws Exception
+  {
+    Desktop.instance.closeAll_actionPerformed(null);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/exampleFile_2_7.jar", FormatAdapter.FILE);
+    assertTrue("Didn't read in the example file correctly.", af != null);
+    String afid = af.getViewport().getSequenceSetId();
+
+    /*
+     * remember representative and hidden sequences marked 
+     * on each panel
+     */
+    Map<String, SequenceI> refseqs = new HashMap<String, SequenceI>();
+    Map<String, List<String>> hiddenSeqNames = new HashMap<String, List<String>>();
+
+    /*
+     * mark sequence 2, 3, 4.. in panels 1, 2, 3...
+     * as reference sequence for itself and the preceding sequence
+     */
+    int n = 1;
+    for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
+    {
+      AlignViewportI av = ap.getAlignViewport();
+      AlignmentI alignment = ap.getAlignment();
+      int repIndex = n % alignment.getHeight();
+      SequenceI rep = alignment.getSequenceAt(repIndex);
+      refseqs.put(ap.getViewName(), rep);
+      List<String> hiddenNames = new ArrayList<String>();
+      hiddenSeqNames.put(ap.getViewName(), hiddenNames);
+
+      /*
+       * hide rep sequence and the one before it
+       */
+      SequenceI seqToHide = alignment.getSequenceAt(repIndex);
+      SequenceGroup sg = new SequenceGroup();
+      sg.addSequence(seqToHide, false);
+      SequenceI precedingSeq = alignment.getSequenceAt(repIndex - 1);
+      sg.addSequence(precedingSeq, false);
+      av.setSelectionGroup(sg);
+      ((AlignmentViewport) av).hideSequences(seqToHide, true);
+
+      /*
+       * record names of hidden sequences
+       */
+      HiddenSequences hs = alignment.getHiddenSequences();
+      for (SequenceI seq : hs.hiddenSequences)
+      {
+        if (seq != null)
+        {
+          hiddenNames.add(seq.getName());
+        }
+      }
+      // code from mark/unmark sequence as reference in jalview.gui.PopupMenu
+      // todo refactor this to an alignment view controller
+      av.setDisplayReferenceSeq(true);
+      av.setColourByReferenceSeq(true);
+      av.getAlignment().setSeqrep(rep);
+
+      n++;
+    }
+    File tfile = File.createTempFile("testStoreAndRecoverReferenceSeq",
+            ".jvp");
+    try
+    {
+      new Jalview2XML(false).saveState(tfile);
+    } catch (Throwable e)
+    {
+      Assert.fail("Didn't save the expanded view state", e);
+    }
+    Desktop.instance.closeAll_actionPerformed(null);
+    if (Desktop.getAlignFrames() != null)
+    {
+      Assert.assertEquals(Desktop.getAlignFrames().length, 0);
+    }
+
+    af = new FileLoader().LoadFileWaitTillLoaded(
+            tfile.getAbsolutePath(), FormatAdapter.FILE);
+    afid = af.getViewport().getSequenceSetId();
+
+    for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
+    {
+      // check representative
+      AlignmentI alignment = ap.getAlignment();
+      SequenceI rep = alignment.getSeqrep();
+      Assert.assertNotNull(rep,
+              "Couldn't restore sequence representative from project");
+      // can't use a strong equals here, because by definition, the sequence IDs
+      // will be different.
+      // could set vamsas session save/restore flag to preserve IDs across
+      // load/saves.
+      Assert.assertEquals(refseqs.get(ap.getViewName()).toString(),
+              rep.toString(),
+              "Representative wasn't the same when recovered.");
+      Assert.assertTrue(ap.getAlignViewport().isDisplayReferenceSeq(),
+              "Display reference sequence view setting not set.");
+      Assert.assertTrue(ap.getAlignViewport().isColourByReferenceSeq(),
+              "Colour By Reference Seq view setting not set.");
+
+      /*
+       * verify hidden sequences in restored panel
+       */
+      List<String> hidden = hiddenSeqNames.get(ap.getViewName());
+      HiddenSequences hs = alignment.getHiddenSequences();
+      assertEquals(
+              "wrong number of restored hidden sequences in "
+                      + ap.getViewName(),
+              hidden.size(), hs.getSize());
+    }
+  }
+
   @Test(groups = { "Functional" })
   public void testIsVersionStringLaterThan()
   {
@@ -422,6 +548,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,
index ab3d9df..164c259 100644 (file)
@@ -52,7 +52,7 @@ public class JalviewExportPropertiesTests
   /**
    * @throws java.lang.Exception
    */
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
     jalview.gui.Desktop.instance.closeAll_actionPerformed(null);
index d8e21c4..f89f58b 100644 (file)
@@ -172,7 +172,7 @@ public class NewickFileTests
   /**
    * @throws java.lang.Exception
    */
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
   }
index d41446b..c084792 100644 (file)
@@ -34,7 +34,7 @@ public class RNAMLfileTest
   {
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
   }
diff --git a/test/jalview/schemes/FeatureColourTest.java b/test/jalview/schemes/FeatureColourTest.java
new file mode 100644 (file)
index 0000000..e13f542
--- /dev/null
@@ -0,0 +1,344 @@
+package jalview.schemes;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.AssertJUnit.fail;
+
+import jalview.datamodel.SequenceFeature;
+import jalview.util.Format;
+
+import java.awt.Color;
+
+import org.testng.annotations.Test;
+
+public class FeatureColourTest
+{
+  @Test(groups = { "Functional" })
+  public void testCopyConstructor()
+  {
+    /*
+     * plain colour
+     */
+    FeatureColour fc = new FeatureColour(Color.RED);
+    FeatureColour fc1 = new FeatureColour(fc);
+    assertTrue(fc1.getColour().equals(Color.RED));
+    assertFalse(fc1.isGraduatedColour());
+    assertFalse(fc1.isColourByLabel());
+
+    /*
+     * min-max colour
+     */
+    fc = new FeatureColour(Color.gray, Color.black, 10f, 20f);
+    fc.setAboveThreshold(true);
+    fc.setThreshold(12f);
+    fc1 = new FeatureColour(fc);
+    assertTrue(fc1.isGraduatedColour());
+    assertFalse(fc1.isColourByLabel());
+    assertTrue(fc1.isAboveThreshold());
+    assertEquals(12f, fc1.getThreshold());
+    assertEquals(Color.gray, fc1.getMinColour());
+    assertEquals(Color.black, fc1.getMaxColour());
+    assertEquals(10f, fc1.getMin());
+    assertEquals(20f, fc1.getMax());
+
+    /*
+     * colour by label
+     */
+    fc = new FeatureColour();
+    fc.setColourByLabel(true);
+    fc1 = new FeatureColour(fc);
+    assertTrue(fc1.isColourByLabel());
+    assertFalse(fc1.isGraduatedColour());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testIsColored_simpleColour()
+  {
+    FeatureColour fc = new FeatureColour(Color.RED);
+    assertTrue(fc.isColored(new SequenceFeature()));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testIsColored_colourByLabel()
+  {
+    FeatureColour fc = new FeatureColour();
+    fc.setColourByLabel(true);
+    assertTrue(fc.isColored(new SequenceFeature()));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testIsColored_aboveThreshold()
+  {
+    // graduated colour range from score 20 to 100
+    FeatureColour fc = new FeatureColour(Color.WHITE, Color.BLACK, 20f,
+            100f);
+
+    // score 0 is adjusted to bottom of range
+    SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 0f,
+            null);
+    assertTrue(fc.isColored(sf));
+    assertEquals(Color.WHITE, fc.getColor(sf));
+
+    // score 120 is adjusted to top of range
+    sf.setScore(120f);
+    assertEquals(Color.BLACK, fc.getColor(sf));
+
+    // value below threshold is still rendered
+    // setting threshold has no effect yet...
+    fc.setThreshold(60f);
+    sf.setScore(36f);
+    assertTrue(fc.isColored(sf));
+    assertEquals(new Color(204, 204, 204), fc.getColor(sf));
+
+    // now apply threshold:
+    fc.setAboveThreshold(true);
+    assertFalse(fc.isColored(sf));
+    // colour is still returned though ?!?
+    assertEquals(new Color(204, 204, 204), fc.getColor(sf));
+
+    sf.setScore(84); // above threshold now
+    assertTrue(fc.isColored(sf));
+    assertEquals(new Color(51, 51, 51), fc.getColor(sf));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetColor_simpleColour()
+  {
+    FeatureColour fc = new FeatureColour(Color.RED);
+    assertEquals(Color.RED, fc.getColor(new SequenceFeature()));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetColor_colourByLabel()
+  {
+    FeatureColour fc = new FeatureColour();
+    fc.setColourByLabel(true);
+    SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 1f,
+            null);
+    Color expected = UserColourScheme.createColourFromName("desc");
+    assertEquals(expected, fc.getColor(sf));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetColor_Graduated()
+  {
+    // graduated colour from score 0 to 100, gray(128, 128, 128) to red(255, 0, 0)
+    FeatureColour fc = new FeatureColour(Color.GRAY, Color.RED, 0f, 100f);
+    // feature score is 75 which is 3/4 of the way from GRAY to RED
+    SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 75f,
+            null);
+    // the colour gradient is computed in float values from 0-1 (where 1 == 255)
+    float red = 128 / 255f + 3 / 4f * (255 - 128) / 255f;
+    float green = 128 / 255f + 3 / 4f * (0 - 128) / 255f;
+    float blue = 128 / 255f + 3 / 4f * (0 - 128) / 255f;
+    Color expected = new Color(red, green, blue);
+    assertEquals(expected, fc.getColor(sf));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetColor_belowThreshold()
+  {
+    // gradient from [50, 150] from WHITE(255, 255, 255) to BLACK(0, 0, 0)
+    FeatureColour fc = new FeatureColour(Color.WHITE, Color.BLACK, 50f,
+            150f);
+    SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 70f,
+            null);
+    fc.setThreshold(100f); // ignore for now
+    assertTrue(fc.isColored(sf));
+    assertEquals(new Color(204, 204, 204), fc.getColor(sf));
+
+    fc.setAboveThreshold(true); // feature lies below threshold
+    assertFalse(fc.isColored(sf));
+    assertEquals(new Color(204, 204, 204), fc.getColor(sf));
+  }
+
+  /**
+   * Test output of feature colours to Jalview features file format
+   */
+  @Test(groups = { "Functional" })
+  public void testToJalviewFormat()
+  {
+    /*
+     * plain colour - to RGB hex code
+     */
+    FeatureColour fc = new FeatureColour(Color.RED);
+    String redHex = Format.getHexString(Color.RED);
+    String hexColour = redHex;
+    assertEquals("domain\t" + hexColour, fc.toJalviewFormat("domain"));
+    
+    /*
+     * colour by label (no threshold)
+     */
+    fc = new FeatureColour();
+    fc.setColourByLabel(true);
+    assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
+
+    /*
+     * colour by label (autoscaled) (an odd state you can reach by selecting
+     * 'above threshold', then deselecting 'threshold is min/max' then 'colour
+     * by label')
+     */
+    fc.setAutoScaled(true);
+    assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
+
+    /*
+     * colour by label (above threshold) (min/max values are output though not
+     * used by this scheme)
+     */
+    fc.setAutoScaled(false);
+    fc.setThreshold(12.5f);
+    fc.setAboveThreshold(true);
+    assertEquals("domain\tlabel|||0.0|0.0|above|12.5",
+            fc.toJalviewFormat("domain"));
+
+    /*
+     * colour by label (below threshold)
+     */
+    fc.setBelowThreshold(true);
+    assertEquals("domain\tlabel|||0.0|0.0|below|12.5",
+            fc.toJalviewFormat("domain"));
+
+    /*
+     * graduated colour, no threshold
+     */
+    fc = new FeatureColour(Color.GREEN, Color.RED, 12f, 25f);
+    String greenHex = Format.getHexString(Color.GREEN);
+    String expected = String.format("domain\t%s|%s|abso|12.0|25.0|none",
+            greenHex, redHex);
+    assertEquals(expected, fc.toJalviewFormat("domain"));
+
+    /*
+     * colour ranges over the actual score ranges (not min/max)
+     */
+    fc.setAutoScaled(true);
+    expected = String.format("domain\t%s|%s|12.0|25.0|none", greenHex,
+            redHex);
+    assertEquals(expected, fc.toJalviewFormat("domain"));
+
+    /*
+     * graduated colour below threshold
+     */
+    fc.setThreshold(12.5f);
+    fc.setBelowThreshold(true);
+    expected = String.format("domain\t%s|%s|12.0|25.0|below|12.5",
+            greenHex, redHex);
+    assertEquals(expected, fc.toJalviewFormat("domain"));
+
+    /*
+     * graduated colour above threshold
+     */
+    fc.setThreshold(12.5f);
+    fc.setAboveThreshold(true);
+    fc.setAutoScaled(false);
+    expected = String.format("domain\t%s|%s|abso|12.0|25.0|above|12.5",
+            greenHex, redHex);
+    assertEquals(expected, fc.toJalviewFormat("domain"));
+  }
+
+  /**
+   * Test parsing of feature colours from Jalview features file format
+   */
+  @Test(groups = { "Functional" })
+  public void testParseJalviewFeatureColour()
+  {
+    /*
+     * simple colour by name
+     */
+    FeatureColour fc = FeatureColour.parseJalviewFeatureColour("red");
+    assertTrue(fc.isSimpleColour());
+    assertEquals(Color.RED, fc.getColour());
+
+    /*
+     * simple colour by hex code
+     */
+    fc = FeatureColour.parseJalviewFeatureColour(Format
+            .getHexString(Color.RED));
+    assertTrue(fc.isSimpleColour());
+    assertEquals(Color.RED, fc.getColour());
+
+    /*
+     * simple colour by rgb triplet
+     */
+    fc = FeatureColour.parseJalviewFeatureColour("255,0,0");
+    assertTrue(fc.isSimpleColour());
+    assertEquals(Color.RED, fc.getColour());
+
+    /*
+     * malformed colour
+     */
+    try
+    {
+      fc = FeatureColour.parseJalviewFeatureColour("oops");
+      fail("expected exception");
+    } catch (IllegalArgumentException e)
+    {
+      assertEquals("Invalid colour descriptor: oops", e.getMessage());
+    }
+
+    /*
+     * colour by label (no threshold)
+     */
+    fc = FeatureColour.parseJalviewFeatureColour("label");
+    assertTrue(fc.isColourByLabel());
+    assertFalse(fc.hasThreshold());
+
+    /*
+     * colour by label (with threshold)
+     */
+    fc = FeatureColour
+            .parseJalviewFeatureColour("label|||0.0|0.0|above|12.0");
+    assertTrue(fc.isColourByLabel());
+    assertTrue(fc.isAboveThreshold());
+    assertEquals(12.0f, fc.getThreshold());
+
+    /*
+     * graduated colour (by name) (no threshold)
+     */
+    fc = FeatureColour.parseJalviewFeatureColour("red|green|10.0|20.0");
+    assertTrue(fc.isGraduatedColour());
+    assertFalse(fc.hasThreshold());
+    assertEquals(Color.RED, fc.getMinColour());
+    assertEquals(Color.GREEN, fc.getMaxColour());
+    assertEquals(10f, fc.getMin());
+    assertEquals(20f, fc.getMax());
+    assertTrue(fc.isAutoScaled());
+
+    /*
+     * graduated colour (by hex code) (above threshold)
+     */
+    String descriptor = String.format("%s|%s|10.0|20.0|above|15",
+            Format.getHexString(Color.RED),
+            Format.getHexString(Color.GREEN));
+    fc = FeatureColour.parseJalviewFeatureColour(descriptor);
+    assertTrue(fc.isGraduatedColour());
+    assertTrue(fc.hasThreshold());
+    assertTrue(fc.isAboveThreshold());
+    assertEquals(15f, fc.getThreshold());
+    assertEquals(Color.RED, fc.getMinColour());
+    assertEquals(Color.GREEN, fc.getMaxColour());
+    assertEquals(10f, fc.getMin());
+    assertEquals(20f, fc.getMax());
+    assertTrue(fc.isAutoScaled());
+
+    /*
+     * graduated colour (by RGB triplet) (below threshold), absolute scale
+     */
+    descriptor = String.format("255,0,0|0,255,0|abso|10.0|20.0|below|15");
+    fc = FeatureColour.parseJalviewFeatureColour(descriptor);
+    assertTrue(fc.isGraduatedColour());
+    assertFalse(fc.isAutoScaled());
+    assertTrue(fc.hasThreshold());
+    assertTrue(fc.isBelowThreshold());
+    assertEquals(15f, fc.getThreshold());
+    assertEquals(Color.RED, fc.getMinColour());
+    assertEquals(Color.GREEN, fc.getMaxColour());
+    assertEquals(10f, fc.getMin());
+    assertEquals(20f, fc.getMax());
+
+    descriptor = String
+            .format("blue|255,0,255|absolute|20.0|95.0|below|66.0");
+    fc = FeatureColour.parseJalviewFeatureColour(descriptor);
+    assertTrue(fc.isGraduatedColour());
+  }
+}
diff --git a/test/jalview/schemes/UserColourSchemeTest.java b/test/jalview/schemes/UserColourSchemeTest.java
new file mode 100644 (file)
index 0000000..88f4331
--- /dev/null
@@ -0,0 +1,50 @@
+package jalview.schemes;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertSame;
+
+import java.awt.Color;
+
+import org.testng.annotations.Test;
+public class UserColourSchemeTest
+{
+
+  @Test(groups = "functional")
+  public void testGetColourFromString()
+  {
+    /*
+     * by colour name - if known to AWT, and included in
+     * 
+     * @see ColourSchemeProperty.getAWTColorFromName()
+     */
+    assertSame(Color.RED, UserColourScheme.getColourFromString("red"));
+    assertSame(Color.RED, UserColourScheme.getColourFromString("Red"));
+    assertSame(Color.RED, UserColourScheme.getColourFromString(" RED "));
+
+    /*
+     * by RGB hex code
+     */
+    String hexColour = Integer.toHexString(Color.RED.getRGB() & 0xffffff);
+    assertEquals(Color.RED, UserColourScheme.getColourFromString(hexColour));
+    // 'hex' prefixes _not_ wanted here
+    assertNull(UserColourScheme.getColourFromString("0x" + hexColour));
+    assertNull(UserColourScheme.getColourFromString("#" + hexColour));
+
+    /*
+     * by RGB triplet
+     */
+    String rgb = String.format("%d,%d,%d", Color.red.getRed(),
+            Color.red.getGreen(), Color.red.getBlue());
+    assertEquals(Color.RED, UserColourScheme.getColourFromString(rgb));
+
+    /*
+     * odds and ends
+     */
+    assertNull(UserColourScheme.getColourFromString(null));
+    assertNull(UserColourScheme.getColourFromString("rubbish"));
+    assertEquals(Color.WHITE, UserColourScheme.getColourFromString("-1"));
+    assertNull(UserColourScheme.getColourFromString(String
+            .valueOf(Integer.MAX_VALUE)));
+  }
+}
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/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 46feebc..4550fe8 100644 (file)
@@ -37,7 +37,7 @@ public class JalviewJabawsTestUtils
   {
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
   }
index afb24c4..9398d18 100644 (file)
@@ -84,7 +84,7 @@ public class JpredJabaStructExportImport
     assertNotNull("Couldn't load test data ('" + testseqs + "')", af);
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
     if (af != null)
index b57e5d0..fe96e07 100644 (file)
@@ -36,6 +36,7 @@ import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.params.AutoCalcSetting;
 
 import java.awt.Component;
+import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -51,6 +52,8 @@ import compbio.metadata.WrongParameterException;
 
 public class RNAStructExportImport
 {
+  private static final String JAR_FILE_NAME = "testRnalifold_param.jar";
+
   public static String testseqs = "examples/RF00031_folded.stk";
 
   public static Jws2Discoverer disc;
@@ -108,13 +111,18 @@ public class RNAStructExportImport
                                                       // public?
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
     if (af != null)
     {
       af.setVisible(false);
       af.dispose();
+      File f = new File(JAR_FILE_NAME);
+      if (f.exists())
+      {
+        f.delete();
+      }
     }
   }
 
@@ -267,10 +275,10 @@ public class RNAStructExportImport
     // write out parameters
     jalview.gui.AlignFrame nalf = null;
     assertTrue("Couldn't write out the Jar file",
-            new Jalview2XML(false).saveAlignment(af,
-                    "testRnalifold_param.jar", "trial parameter writeout"));
+            new Jalview2XML(false).saveAlignment(af, JAR_FILE_NAME,
+                    "trial parameter writeout"));
     assertTrue("Couldn't read back the Jar file", (nalf = new Jalview2XML(
-            false).loadJalviewAlign("testRnalifold_param.jar")) != null);
+            false).loadJalviewAlign(JAR_FILE_NAME)) != null);
     if (nalf != null)
     {
       AutoCalcSetting acs = af.getViewport().getCalcIdSettingsFor(
index 63b1b9c..341d9ef 100644 (file)
@@ -62,7 +62,7 @@ public class DbRefFetcherTest
   /**
    * @throws java.lang.Exception
    */
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
   }
index a1c2c9a..2a8e584 100644 (file)
  */
 package jalview.ws.sifts;
 
+import jalview.api.DBRefEntryI;
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
+import jalview.io.AppletFormatAdapter;
+import jalview.structure.StructureMapping;
 
-import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.PrintStream;
+import java.io.IOException;
+import java.util.ArrayList;
 import java.util.HashMap;
 
 import org.testng.Assert;
@@ -35,11 +39,11 @@ import org.testng.annotations.AfterTest;
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
 
+import MCview.Atom;
 import MCview.PDBfile;
 
 public class SiftsClientTest
 {
-  private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
 
   public static final String DEFAULT_SIFTS_DOWNLOAD_DIR = System
           .getProperty("user.home")
@@ -63,10 +67,103 @@ public class SiftsClientTest
   @BeforeTest(alwaysRun = true)
   public void populateExpectedMapping() throws SiftsException
    {
-    for (int x = 1; x <= 97; x++)
-    {
-      expectedMapping.put(50 + x, new int[] { x, u });
-    }
+    expectedMapping.put(51, new int[] { 1, 2 });
+    expectedMapping.put(52, new int[] { 2, 7 });
+    expectedMapping.put(53, new int[] { 3, 12 });
+    expectedMapping.put(54, new int[] { 4, 24 });
+    expectedMapping.put(55, new int[] { 5, 33 });
+    expectedMapping.put(56, new int[] { 6, 40 });
+    expectedMapping.put(57, new int[] { 7, 47 });
+    expectedMapping.put(58, new int[] { 8, 55 });
+    expectedMapping.put(59, new int[] { 9, 62 });
+    expectedMapping.put(60, new int[] { 10, 69 });
+    expectedMapping.put(61, new int[] { 11, 76 });
+    expectedMapping.put(62, new int[] { 12, 83 });
+    expectedMapping.put(63, new int[] { 13, 87 });
+    expectedMapping.put(64, new int[] { 14, 95 });
+    expectedMapping.put(65, new int[] { 15, 102 });
+    expectedMapping.put(66, new int[] { 16, 111 });
+    expectedMapping.put(67, new int[] { 17, 122 });
+    expectedMapping.put(68, new int[] { 18, 131 });
+    expectedMapping.put(69, new int[] { 19, 137 });
+    expectedMapping.put(70, new int[] { 20, 144 });
+    expectedMapping.put(71, new int[] { 21, 152 });
+    expectedMapping.put(72, new int[] { 22, 160 });
+    expectedMapping.put(73, new int[] { 23, 167 });
+    expectedMapping.put(74, new int[] { 24, 179 });
+    expectedMapping.put(75, new int[] { 25, 187 });
+    expectedMapping.put(76, new int[] { 26, 195 });
+    expectedMapping.put(77, new int[] { 27, 203 });
+    expectedMapping.put(78, new int[] { 28, 208 });
+    expectedMapping.put(79, new int[] { 29, 213 });
+    expectedMapping.put(80, new int[] { 30, 222 });
+    expectedMapping.put(81, new int[] { 31, 231 });
+    expectedMapping.put(82, new int[] { 32, 240 });
+    expectedMapping.put(83, new int[] { 33, 244 });
+    expectedMapping.put(84, new int[] { 34, 252 });
+    expectedMapping.put(85, new int[] { 35, 260 });
+    expectedMapping.put(86, new int[] { 36, 268 });
+    expectedMapping.put(87, new int[] { 37, 275 });
+    expectedMapping.put(88, new int[] { 38, 287 });
+    expectedMapping.put(89, new int[] { 39, 293 });
+    expectedMapping.put(90, new int[] { 40, 299 });
+    expectedMapping.put(91, new int[] { 41, 310 });
+    expectedMapping.put(92, new int[] { 42, 315 });
+    expectedMapping.put(93, new int[] { 43, 319 });
+    expectedMapping.put(94, new int[] { 44, 325 });
+    expectedMapping.put(95, new int[] { 45, 331 });
+    expectedMapping.put(96, new int[] { 46, 337 });
+    expectedMapping.put(97, new int[] { 47, 343 });
+    expectedMapping.put(98, new int[] { 48, 349 });
+    expectedMapping.put(99, new int[] { 49, 354 });
+    expectedMapping.put(100, new int[] { 50, 358 });
+    expectedMapping.put(101, new int[] { 51, 367 });
+    expectedMapping.put(102, new int[] { 52, 375 });
+    expectedMapping.put(103, new int[] { 53, 384 });
+    expectedMapping.put(104, new int[] { 54, 391 });
+    expectedMapping.put(105, new int[] { 55, 395 });
+    expectedMapping.put(106, new int[] { 56, 401 });
+    expectedMapping.put(107, new int[] { 57, 409 });
+    expectedMapping.put(108, new int[] { 58, 417 });
+    expectedMapping.put(109, new int[] { 59, 426 });
+    expectedMapping.put(110, new int[] { 60, 434 });
+    expectedMapping.put(111, new int[] { 61, 442 });
+    expectedMapping.put(112, new int[] { 62, 451 });
+    expectedMapping.put(113, new int[] { 63, 457 });
+    expectedMapping.put(114, new int[] { 64, 468 });
+    expectedMapping.put(115, new int[] { 65, 476 });
+    expectedMapping.put(116, new int[] { 66, 484 });
+    expectedMapping.put(117, new int[] { 67, 492 });
+    expectedMapping.put(118, new int[] { 68, 500 });
+    expectedMapping.put(119, new int[] { 69, 509 });
+    expectedMapping.put(120, new int[] { 70, 517 });
+    expectedMapping.put(121, new int[] { 71, 525 });
+    expectedMapping.put(122, new int[] { 72, 534 });
+    expectedMapping.put(123, new int[] { 73, 538 });
+    expectedMapping.put(124, new int[] { 74, 552 });
+    expectedMapping.put(125, new int[] { 75, 559 });
+    expectedMapping.put(126, new int[] { 76, 567 });
+    expectedMapping.put(127, new int[] { 77, 574 });
+    expectedMapping.put(128, new int[] { 78, 580 });
+    expectedMapping.put(129, new int[] { 79, 585 });
+    expectedMapping.put(130, new int[] { 80, 590 });
+    expectedMapping.put(131, new int[] { 81, 602 });
+    expectedMapping.put(132, new int[] { 82, 609 });
+    expectedMapping.put(133, new int[] { 83, 616 });
+    expectedMapping.put(134, new int[] { 84, 622 });
+    expectedMapping.put(135, new int[] { 85, 630 });
+    expectedMapping.put(136, new int[] { 86, 637 });
+    expectedMapping.put(137, new int[] { 87, 644 });
+    expectedMapping.put(138, new int[] { 88, 652 });
+    expectedMapping.put(139, new int[] { 89, 661 });
+    expectedMapping.put(140, new int[] { 90, 668 });
+    expectedMapping.put(141, new int[] { 91, 678 });
+    expectedMapping.put(142, new int[] { 92, 687 });
+    expectedMapping.put(143, new int[] { 93, 696 });
+    expectedMapping.put(144, new int[] { 94, 705 });
+    expectedMapping.put(145, new int[] { 95, 714 });
+    expectedMapping.put(146, new int[] { 96, 722 });
+    expectedMapping.put(147, new int[] { 97, 729 });
    }
    
   @BeforeTest(alwaysRun = true)
@@ -74,14 +171,22 @@ public class SiftsClientTest
   {
     // SIFTs entries are updated weekly - so use saved SIFTs file to enforce
     // test reproducibility
+    new SiftsSettings();
     SiftsSettings.setSiftDownloadDirectory(jalview.bin.Cache.getDefault(
             "sifts_download_dir", DEFAULT_SIFTS_DOWNLOAD_DIR));
-
-    File testSiftsFile = new File("test/jalview/io/" + testPDBId
-            + ".xml.gz");
-    PDBfile pdbFile = new PDBfile(false, false, false);
-    pdbFile.setId(testPDBId);
-    siftsClient = new SiftsClient(pdbFile, testSiftsFile);
+    SiftsSettings.setMapWithSifts(true);
+    SiftsSettings.setCacheThresholdInDays("2");
+    SiftsSettings.setFailSafePIDThreshold("70");
+    PDBfile pdbFile;
+    try
+    {
+      pdbFile = new PDBfile(false, false, false, "test/jalview/io/"
+              + testPDBId + ".pdb", AppletFormatAdapter.FILE);
+      siftsClient = new SiftsClient(pdbFile);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
   }
 
   @AfterTest(alwaysRun = true)
@@ -90,30 +195,23 @@ public class SiftsClientTest
     siftsClient = null;
   }
 
-  @BeforeTest(alwaysRun = true)
-  public void setUpStreams()
-  {
-    System.setOut(new PrintStream(outContent));
-  }
-
-  @AfterTest(alwaysRun = true)
-  public void cleanUpStreams()
-  {
-    System.setOut(null);
-  }
-
   @Test(groups = { "Functional" })
   public void getSIFTsFileTest() throws SiftsException
   {
-    Assert.assertTrue(SiftsClient.deleteSiftsFileByPDBId(testPDBId));
-    SiftsClient.getSiftsFile(testPDBId);
-    Assert.assertFalse(outContent.toString().contains(
-            ">>> SIFTS File already downloaded for " + testPDBId));
-
-    // test for SIFTs file caching
-    SiftsClient.getSiftsFile(testPDBId);
-    Assert.assertTrue(outContent.toString().contains(
-            ">>> SIFTS File already downloaded for " + testPDBId));
+    File siftsFile;
+    try
+    {
+      siftsFile = SiftsClient.downloadSiftsFile(testPDBId);
+      FileAssert.assertFile(siftsFile);
+      // test for SIFTs file caching
+      SiftsSettings.setCacheThresholdInDays("0");
+      siftsFile = SiftsClient.getSiftsFile(testPDBId);
+      FileAssert.assertFile(siftsFile);
+      SiftsSettings.setCacheThresholdInDays("2");
+    } catch (IOException e)
+    {
+      e.printStackTrace();
+    }
   }
 
   @Test(groups = { "Functional" })
@@ -122,11 +220,19 @@ 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" })
   public void getAllMappingAccessionTest()
   {
@@ -154,9 +260,9 @@ public class SiftsClientTest
       HashMap<Integer, int[]> actualMapping = siftsClient.getGreedyMapping(
               "A", testSeq,
               null);
-      Assert.assertEquals(actualMapping, expectedMapping);
       Assert.assertEquals(testSeq.getStart(), 1);
       Assert.assertEquals(testSeq.getEnd(), 147);
+      Assert.assertEquals(actualMapping, expectedMapping);
     } catch (Exception e)
     {
       e.printStackTrace();
@@ -167,8 +273,15 @@ public class SiftsClientTest
   @Test(groups = { "Functional" })
   private void getAtomIndexTest()
   {
-    // siftsClient.getAtomIndex(1, null);
-    // Assert.assertTrue(true);
+    ArrayList<Atom> atoms = new ArrayList<Atom>();
+    Atom atom = new Atom(u, u, u);
+    atom.resNumber = 43;
+    atom.atomIndex = 7;
+    atoms.add(atom);
+    int actualAtomIndex = siftsClient.getAtomIndex(1, atoms);
+    Assert.assertEquals(actualAtomIndex, -1);
+    actualAtomIndex = siftsClient.getAtomIndex(43, atoms);
+    Assert.assertEquals(actualAtomIndex, 7);
   }
 
   @Test(
@@ -185,21 +298,157 @@ public class SiftsClientTest
 
   }
 
-  @Test(groups = { "Functional" })
-  private void populateAtomPositionsTest()
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = SiftsException.class)
+  private void populateAtomPositionsNullTest1()
+          throws IllegalArgumentException, SiftsException
   {
+      siftsClient.populateAtomPositions(null, null);
+  }
 
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = SiftsException.class)
+  private void populateAtomPositionsNullTest2()
+          throws IllegalArgumentException, SiftsException
+  {
+    siftsClient.populateAtomPositions("A", null);
   }
 
   @Test(groups = { "Functional" })
   public void getValidSourceDBRefTest()
   {
+    try
+    {
+      DBRefEntryI actualValidSrcDBRef = siftsClient
+              .getValidSourceDBRef(testSeq);
+      DBRefEntryI expectedDBRef = new DBRefEntry();
+      expectedDBRef.setSource(DBRefSource.UNIPROT);
+      expectedDBRef.setAccessionId("P00221");
+      expectedDBRef.setStartRes(1);
+      expectedDBRef.setEndRes(147);
+      expectedDBRef.setVersion("");
+      Assert.assertEquals(actualValidSrcDBRef, expectedDBRef);
+    } catch (Exception e)
+    {
+    }
+  }
+
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = SiftsException.class)
+  public void getValidSourceDBRefExceptionTest() throws SiftsException
+  {
+      SequenceI invalidTestSeq = new Sequence("testSeq", "ABCDEFGH");
+    try
+    {
+      siftsClient.getValidSourceDBRef(invalidTestSeq);
+    } catch (SiftsException e)
+    {
+      throw new SiftsException(e.getMessage());
+    }
+  }
+
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = SiftsException.class)
+  public void getValidSourceDBRefExceptionXTest() throws SiftsException
+  {
+    SequenceI invalidTestSeq = new Sequence("testSeq", "ABCDEFGH");
+    DBRefEntry invalidDBRef = new DBRefEntry();
+    invalidDBRef.setAccessionId("BLAR");
+    invalidTestSeq.addDBRef(invalidDBRef);
+    try
+    {
+      siftsClient.getValidSourceDBRef(invalidTestSeq);
+    } catch (SiftsException e)
+    {
+      throw new SiftsException(e.getMessage());
+    }
 
   }
 
   @Test(groups = { "Functional" })
   public void isValidDBRefEntryTest()
   {
+    DBRefEntryI validDBRef = new DBRefEntry();
+    validDBRef.setSource(DBRefSource.UNIPROT);
+    validDBRef.setAccessionId("P00221");
+    validDBRef.setStartRes(1);
+    validDBRef.setEndRes(147);
+    validDBRef.setVersion("");
+    Assert.assertTrue(siftsClient.isValidDBRefEntry(validDBRef));
+  }
 
+  @Test(groups = { "Functional" })
+  public void getSiftsStructureMappingTest()
+  {
+    try
+    {
+      Assert.assertTrue(SiftsSettings.isMapWithSifts());
+      StructureMapping strucMapping = siftsClient.getSiftsStructureMapping(
+              testSeq, testPDBId, "A");
+      String expectedMappingOutput = "\nSequence âŸ· Structure mapping details\n"
+              + "Method: SIFTS\n\n"
+              + "P00221 :  1 - 97 Maps to \n"
+              + "1A70|A :  51 - 147\n\n"
+              + "P00221 AAYKVTLVTPTGNVEFQCPDDVYILDAAEEEGIDLPYSCRAGSCSSCAGKLKTGSLNQDDQSFLD\n"
+              + "       |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\n"
+              + "1A70|A AAYKVTLVTPTGNVEFQCPDDVYILDAAEEEGIDLPYSCRAGSCSSCAGKLKTGSLNQDDQSFLD\n\n"
+
+              + "P00221 DDQIDEGWVLTCAAYPVSDVTIETHKEEELTA\n"
+              + "       |||||||||||||||||||||||||| |||||\n"
+              + "1A70|A DDQIDEGWVLTCAAYPVSDVTIETHKKEELTA\n\n" +
+
+              "Length of alignment = 97\n" + "Percentage ID = 98.97\n";
+
+      Assert.assertEquals(strucMapping.getMappingDetailsOutput(),
+              expectedMappingOutput);
+      Assert.assertEquals(strucMapping.getMapping(), expectedMapping);
+    } catch (SiftsException e)
+    {
+      e.printStackTrace();
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void getEntityCountTest()
+  {
+    int actualEntityCount = siftsClient.getEntityCount();
+    System.out.println("actual entity count : " + actualEntityCount);
+    Assert.assertEquals(actualEntityCount, 1);
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDbAccessionIdTest()
+  {
+    String actualDbAccId = siftsClient.getDbAccessionId();
+    System.out.println("Actual Db Accession Id: " + actualDbAccId);
+    Assert.assertEquals(actualDbAccId, "1a70");
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDbCoordSysTest()
+  {
+    String actualDbCoordSys = siftsClient.getDbCoordSys();
+    System.out.println("Actual DbCoordSys: " + actualDbCoordSys);
+    Assert.assertEquals(actualDbCoordSys, "PDBe");
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDbSourceTest()
+  {
+    String actualDbSource = siftsClient.getDbSource();
+    System.out.println("Actual DbSource: " + actualDbSource);
+    Assert.assertEquals(actualDbSource, "PDBe");
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDbVersionTest()
+  {
+    String actualDbVersion = siftsClient.getDbVersion();
+    System.out.println("Actual DbVersion: " + actualDbVersion);
+    Assert.assertEquals(actualDbVersion, "2.0");
   }
 }
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);
+    }
+
+  }
+
+}