Merge branch 'feature/JAL-3205symmetricCalc' into develop
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 7 Mar 2019 09:14:33 +0000 (09:14 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 7 Mar 2019 09:14:33 +0000 (09:14 +0000)
88 files changed:
.classpath
THIRDPARTYLIBS
help/help.jhm
help/html/features/das.gif [deleted file]
help/html/features/exportannot.gif [deleted file]
help/html/features/pdbsequencefetcher.html
help/html/features/search.gif [deleted file]
help/html/features/uniprotsequencefetcher.html
lib/spring-core-3.0.5.RELEASE.jar [deleted file]
lib/spring-web-3.0.5.RELEASE.jar [deleted file]
resources/AmbiguityCodes.dat [new file with mode: 0644]
resources/GeneticCodes.dat [new file with mode: 0644]
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/analysis/Dna.java
src/jalview/analysis/Finder.java
src/jalview/analysis/GeneticCodeI.java [new file with mode: 0644]
src/jalview/analysis/GeneticCodes.java [new file with mode: 0644]
src/jalview/api/FeatureColourI.java
src/jalview/api/FinderI.java [new file with mode: 0644]
src/jalview/appletgui/AlignmentPanel.java
src/jalview/appletgui/FeatureColourChooser.java
src/jalview/appletgui/Finder.java
src/jalview/appletgui/IdCanvas.java
src/jalview/appletgui/IdPanel.java
src/jalview/appletgui/OverviewPanel.java
src/jalview/appletgui/SeqCanvas.java
src/jalview/bin/Cache.java
src/jalview/bin/Jalview.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/AlignmentI.java
src/jalview/datamodel/ColumnSelection.java
src/jalview/datamodel/SearchResultMatchI.java
src/jalview/datamodel/SearchResults.java
src/jalview/datamodel/SearchResultsI.java
src/jalview/datamodel/SequenceI.java
src/jalview/fts/core/GFTSPanel.java
src/jalview/fts/service/pdb/PDBFTSPanel.java
src/jalview/fts/service/uniprot/UniprotFTSPanel.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignmentPanel.java
src/jalview/gui/AnnotationColumnChooser.java
src/jalview/gui/AnnotationPanel.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/FeatureTypeSettings.java
src/jalview/gui/Finder.java
src/jalview/gui/Help.java
src/jalview/gui/IdCanvas.java
src/jalview/gui/IdPanel.java
src/jalview/gui/OverviewPanel.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/SeqCanvas.java
src/jalview/gui/SeqPanel.java
src/jalview/gui/SliderPanel.java
src/jalview/jbgui/GAlignFrame.java
src/jalview/jbgui/GDasSourceBrowser.java [deleted file]
src/jalview/jbgui/GFinder.java
src/jalview/jbgui/GPreferences.java
src/jalview/project/Jalview2XML.java
src/jalview/schemes/AnnotationColourGradient.java
src/jalview/schemes/FeatureColour.java
src/jalview/schemes/ResidueProperties.java
src/jalview/util/DBRefUtils.java
src/jalview/viewmodel/ViewportRanges.java
src/jalview/workers/ConsensusThread.java
src/jalview/ws/DBRefFetcher.java
src/jalview/ws/jws2/AADisorderClient.java
test/jalview/analysis/AlignSeqTest.java
test/jalview/analysis/DnaTest.java
test/jalview/analysis/FinderTest.java
test/jalview/analysis/GeneticCodesTest.java [new file with mode: 0644]
test/jalview/bin/CommandLineOperations.java
test/jalview/controller/AlignViewControllerTest.java
test/jalview/datamodel/AlignmentTest.java
test/jalview/datamodel/ColumnSelectionTest.java
test/jalview/datamodel/SearchResultsTest.java
test/jalview/gui/AlignFrameTest.java
test/jalview/gui/FeatureSettingsTest.java
test/jalview/io/FeaturesFileTest.java
test/jalview/io/SequenceAnnotationReportTest.java
test/jalview/project/Jalview2xmlTests.java
test/jalview/renderer/seqfeatures/FeatureColourFinderTest.java
test/jalview/renderer/seqfeatures/FeatureRendererTest.java
test/jalview/schemes/AnnotationColourGradientTest.java
test/jalview/schemes/DnaCodonTests.java [deleted file]
test/jalview/schemes/FeatureColourTest.java
test/jalview/util/DBRefUtilsTest.java
utils/i18nAnt.xml

index 7d02b37..4f9cb8a 100644 (file)
@@ -35,8 +35,6 @@
        <classpathentry kind="lib" path="lib/miglayout-4.0-swing.jar"/>
        <classpathentry kind="lib" path="lib/jswingreader-0.3.jar" sourcepath="/jswingreader"/>
        <classpathentry kind="lib" path="lib/commons-codec-1.3.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/jabaws-min-client-2.2.0.jar" sourcepath="/clustengine"/>
        <classpathentry kind="lib" path="lib/json_simple-1.1.jar" sourcepath="/Users/jimp/Downloads/json_simple-1.1-all.zip"/>
        <classpathentry kind="lib" path="lib/slf4j-api-1.7.7.jar"/>
index afa99d2..728711e 100644 (file)
@@ -38,8 +38,6 @@ miglayout-4.0-swing.jar       BSD http://www.migcalendar.com/miglayout/versions/4.0/li
 min-jaba-client.jar
 regex.jar
 saaj.jar
-spring-core-3.0.5.RELEASE.jar : Apache License: jdas runtime dependencies retrieved via maven - TODO: JAL-3035 remove if no longer needed ?
-spring-web-3.0.5.RELEASE.jar : Apache License: jdas runtime dependencies retrieved via maven - TODO: JAL-3035 remove if no longer needed ?
 vamsas-client.jar
 wsdl4j.jar
 xercesImpl.jar
index 78f86b6..1666cc6 100755 (executable)
    
    <mapID target="biojson" url="html/features/bioJsonFormat.html" />
    <mapID target="pdbfetcher" url="html/features/pdbsequencefetcher.html" />
+   <mapID target="pdbfts" url="html/features/pdbsequencefetcher.html#pdbfts" />
    <mapID target="siftsmapping" url="html/features/siftsmapping.html" />
    <mapID target="pdbchooser" url="html/features/structurechooser.html" />
    <mapID target="selectcolbyannot" url="html/features/columnFilterByAnnotation.html" />
    <mapID target="ensemblfetch" url="html/features/ensemblsequencefetcher.html" />
    
    <mapID target="uniprotfetcher" url="html/features/uniprotsequencefetcher.html" />
+   <mapID target="uniprotfts" url="html/features/uniprotsequencefetcher.html#uniprotfts" />
    
    <mapID target="urllinks" url="html/webServices/urllinks.html" />
    <mapID target="linksprefs" url="html/features/preferences.html#links" />
diff --git a/help/html/features/das.gif b/help/html/features/das.gif
deleted file mode 100644 (file)
index 1f884cb..0000000
Binary files a/help/html/features/das.gif and /dev/null differ
diff --git a/help/html/features/exportannot.gif b/help/html/features/exportannot.gif
deleted file mode 100644 (file)
index 2133cc1..0000000
Binary files a/help/html/features/exportannot.gif and /dev/null differ
index bb63bed..9251277 100644 (file)
@@ -43,7 +43,7 @@
     alt="PDB sequence fetcher (introduced in Jalview 2.9)" />
 
   <p>
-    <strong>Searching the PDB Database</strong>
+    <a name="pdbfts"><strong>Searching the PDB Database</strong></a>
   </p>
   <p>To search the PDB, begin typing in the text box. If the
     'autosearch' checkbox is enabled, then the results of your query
diff --git a/help/html/features/search.gif b/help/html/features/search.gif
deleted file mode 100755 (executable)
index 1c0ffb0..0000000
Binary files a/help/html/features/search.gif and /dev/null differ
index 4a64f52..72e7649 100644 (file)
@@ -44,7 +44,7 @@
   </p>
 
   <p>
-    <strong>Searching the UniProt Database</strong>
+    <a name="uniprotfts"><strong>Searching the UniProt Database</strong></a>
   </p>
   <p>To search UniProt, simply begin typing in the text box. If the
     'autosearch' check box is enabled, then after a short delay (about
diff --git a/lib/spring-core-3.0.5.RELEASE.jar b/lib/spring-core-3.0.5.RELEASE.jar
deleted file mode 100644 (file)
index ea9500d..0000000
Binary files a/lib/spring-core-3.0.5.RELEASE.jar and /dev/null differ
diff --git a/lib/spring-web-3.0.5.RELEASE.jar b/lib/spring-web-3.0.5.RELEASE.jar
deleted file mode 100644 (file)
index 5a2381a..0000000
Binary files a/lib/spring-web-3.0.5.RELEASE.jar and /dev/null differ
diff --git a/resources/AmbiguityCodes.dat b/resources/AmbiguityCodes.dat
new file mode 100644 (file)
index 0000000..9372c03
--- /dev/null
@@ -0,0 +1,13 @@
+# source: IUPAC codes as per http://www.insdc.org/documents/feature_table.html#7.4.1
+DNA
+R      AG
+Y      TC
+W      AT
+S      GC
+M      AC
+K      GT
+H      ATC
+B      GTC
+V      GAC
+D      GAT
+N      GATC
diff --git a/resources/GeneticCodes.dat b/resources/GeneticCodes.dat
new file mode 100644 (file)
index 0000000..4735cf2
--- /dev/null
@@ -0,0 +1,327 @@
+-- source: ftp://ftp.ncbi.nih.gov/entrez/misc/data/gc.prt (19th March 2018)
+-- SGC3 name edited slightly so as to fit all on one line
+--**************************************************************************
+--  This is the NCBI genetic code table
+--  Initial base data set from Andrzej Elzanowski while at PIR International
+--  Addition of Eubacterial and Alternative Yeast by J.Ostell at NCBI
+--  Base 1-3 of each codon have been added as comments to facilitate
+--    readability at the suggestion of Peter Rice, EMBL
+--  Later additions by Taxonomy Group staff at NCBI
+--
+--  Version 4.2
+--     Added Karyorelict nuclear genetic code 27
+--     Added Condylostoma nuclear genetic code 28
+--     Added Mesodinium nuclear genetic code 29
+--     Added Peritrich nuclear genetic code 30
+--     Added Blastocrithidia nuclear genetic code 31
+--
+--  Version 4.1
+--     Added Pachysolen tannophilus nuclear genetic code 26
+--
+--  Version 4.0
+--     Updated version to reflect numerous undocumented changes:
+--     Corrected start codons for genetic code 25
+--     Name of new genetic code is Candidate Division SR1 and Gracilibacteria
+--     Added candidate division SR1 nuclear genetic code 25
+--     Added GTG as start codon for genetic code 24
+--     Corrected Pterobranchia Mitochondrial genetic code (24)
+--     Added genetic code 24, Pterobranchia Mitochondrial
+--     Genetic code 11 is now Bacterial, Archaeal and Plant Plastid
+--     Fixed capitalization of mitochondrial in codes 22 and 23
+--     Added GTG, ATA, and TTG as alternative start codons to code 13
+--
+--  Version 3.9
+--     Code 14 differs from code 9 only by translating UAA to Tyr rather than
+--     STOP.  A recent study (Telford et al, 2000) has found no evidence that
+--     the codon UAA codes for Tyr in the flatworms, but other opinions exist.
+--     There are very few GenBank records that are translated with code 14,
+--     but a test translation shows that retranslating these records with code
+--     9 can cause premature terminations.  Therefore, GenBank will maintain
+--     code 14 until further information becomes available.
+--
+--  Version 3.8
+--     Added GTG start to Echinoderm mitochondrial code, code 9
+--
+--  Version 3.7
+--     Added code 23 Thraustochytrium mitochondrial code
+--        formerly OGMP code 93
+--        submitted by Gertraude Berger, Ph.D.
+--
+--  Version 3.6
+--     Added code 22 TAG-Leu, TCA-stop
+--        found in mitochondrial DNA of Scenedesmus obliquus
+--        submitted by Gertraude Berger, Ph.D.
+--        Organelle Genome Megasequencing Program, Univ Montreal
+--
+--  Version 3.5
+--     Added code 21, Trematode Mitochondrial
+--       (as deduced from: Garey & Wolstenholme,1989; Ohama et al, 1990)
+--     Added code 16, Chlorophycean Mitochondrial
+--       (TAG can translated to Leucine instaed to STOP in chlorophyceans
+--        and fungi)
+--
+--  Version 3.4
+--     Added CTG,TTG as allowed alternate start codons in Standard code.
+--        Prats et al. 1989, Hann et al. 1992
+--
+--  Version 3.3 - 10/13/95
+--     Added alternate intiation codon ATC to code 5
+--        based on complete mitochondrial genome of honeybee
+--        Crozier and Crozier (1993)
+--
+--  Version 3.2 - 6/24/95
+--  Code       Comments
+--   10        Alternative Ciliate Macronuclear renamed to Euplotid Macro...
+--   15        Blepharisma Macro.. code added
+--    5        Invertebrate Mito.. GTG allowed as alternate initiator
+--   11        Eubacterial renamed to Bacterial as most alternate starts
+--               have been found in Archea
+--
+--
+--  Version 3.1 - 1995
+--  Updated as per Andrzej Elzanowski at NCBI
+--     Complete documentation in NCBI toolkit documentation
+--  Note: 2 genetic codes have been deleted
+--
+--   Old id   Use id     - Notes
+--
+--   id 7      id 4      - Kinetoplast code now merged in code id 4
+--   id 8      id 1      - all plant chloroplast differences due to RNA edit
+--
+--*************************************************************************
+
+Genetic-code-table ::= {
+ {
+  name "Standard" ,
+  name "SGC0" ,
+  id 1 ,
+  ncbieaa  "FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "---M------**--*----M---------------M----------------------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ },
+ {
+  name "Vertebrate Mitochondrial" ,
+  name "SGC1" ,
+  id 2 ,
+  ncbieaa  "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNKKSS**VVVVAAAADDEEGGGG",
+  sncbieaa "----------**--------------------MMMM----------**---M------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ },
+ {
+  name "Yeast Mitochondrial" ,
+  name "SGC2" ,
+  id 3 ,
+  ncbieaa  "FFLLSSSSYY**CCWWTTTTPPPPHHQQRRRRIIMMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "----------**----------------------MM----------------------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ },
+ {
+    name "Mold / Protozoan / Coelenterate Mitochondrial; Mycoplasma; Spiroplasma" ,
+  name "SGC3" ,
+  id 4 ,
+  ncbieaa  "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "--MM------**-------M------------MMMM---------------M------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ },
+ {
+  name "Invertebrate Mitochondrial" ,
+  name "SGC4" ,
+  id 5 ,
+  ncbieaa  "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNKKSSSSVVVVAAAADDEEGGGG",
+  sncbieaa "---M------**--------------------MMMM---------------M------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ },
+ {
+  name "Ciliate Nuclear; Dasycladacean Nuclear; Hexamita Nuclear" ,
+  name "SGC5" ,
+  id 6 ,
+  ncbieaa  "FFLLSSSSYYQQCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "--------------*--------------------M----------------------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ },
+ {
+  name "Echinoderm Mitochondrial; Flatworm Mitochondrial" ,
+  name "SGC8" ,
+  id 9 ,
+  ncbieaa  "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNNKSSSSVVVVAAAADDEEGGGG",
+  sncbieaa "----------**-----------------------M---------------M------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ },
+ {
+  name "Euplotid Nuclear" ,
+  name "SGC9" ,
+  id 10 ,
+  ncbieaa  "FFLLSSSSYY**CCCWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "----------**-----------------------M----------------------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ },
+ {
+  name "Bacterial, Archaeal and Plant Plastid" ,
+  id 11 ,
+  ncbieaa  "FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "---M------**--*----M------------MMMM---------------M------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ },
+ {
+  name "Alternative Yeast Nuclear" ,
+  id 12 ,
+  ncbieaa  "FFLLSSSSYY**CC*WLLLSPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "----------**--*----M---------------M----------------------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ },
+ {
+  name "Ascidian Mitochondrial" ,
+  id 13 ,
+  ncbieaa  "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNKKSSGGVVVVAAAADDEEGGGG",
+  sncbieaa "---M------**----------------------MM---------------M------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ },
+ {
+  name "Alternative Flatworm Mitochondrial" ,
+  id 14 ,
+  ncbieaa  "FFLLSSSSYYY*CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNNKSSSSVVVVAAAADDEEGGGG",
+  sncbieaa "-----------*-----------------------M----------------------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ } ,
+ {
+  name "Blepharisma Macronuclear" ,
+  id 15 ,
+  ncbieaa  "FFLLSSSSYY*QCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "----------*---*--------------------M----------------------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ } ,
+ {
+  name "Chlorophycean Mitochondrial" ,
+  id 16 ,
+  ncbieaa  "FFLLSSSSYY*LCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "----------*---*--------------------M----------------------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ } ,
+ {
+  name "Trematode Mitochondrial" ,
+  id 21 ,
+  ncbieaa  "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNNKSSSSVVVVAAAADDEEGGGG",
+  sncbieaa "----------**-----------------------M---------------M------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ } ,
+ {
+  name "Scenedesmus obliquus Mitochondrial" ,
+  id 22 ,
+  ncbieaa  "FFLLSS*SYY*LCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "------*---*---*--------------------M----------------------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ } ,
+ {
+  name "Thraustochytrium Mitochondrial" ,
+  id 23 ,
+  ncbieaa  "FF*LSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "--*-------**--*-----------------M--M---------------M------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ } ,
+ {
+  name "Pterobranchia Mitochondrial" ,
+  id 24 ,
+  ncbieaa  "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSSKVVVVAAAADDEEGGGG",
+  sncbieaa "---M------**-------M---------------M---------------M------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ } ,
+ {
+  name "Candidate Division SR1 and Gracilibacteria" ,
+  id 25 ,
+  ncbieaa  "FFLLSSSSYY**CCGWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "---M------**-----------------------M---------------M------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ } ,
+ {
+  name "Pachysolen tannophilus Nuclear" ,
+  id 26 ,
+  ncbieaa  "FFLLSSSSYY**CC*WLLLAPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "----------**--*----M---------------M----------------------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ } ,
+ {
+  name "Karyorelict Nuclear" ,
+  id 27 ,
+  ncbieaa  "FFLLSSSSYYQQCCWWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "--------------*--------------------M----------------------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ } ,
+ {
+  name "Condylostoma Nuclear" ,
+  id 28 ,
+  ncbieaa  "FFLLSSSSYYQQCCWWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "----------**--*--------------------M----------------------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ } ,
+ {
+  name "Mesodinium Nuclear" ,
+  id 29 ,
+  ncbieaa  "FFLLSSSSYYYYCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "--------------*--------------------M----------------------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ } ,
+ {
+  name "Peritrich Nuclear" ,
+  id 30 ,
+  ncbieaa  "FFLLSSSSYYEECC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "--------------*--------------------M----------------------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ } ,
+ {
+  name "Blastocrithidia Nuclear" ,
+  id 31 ,
+  ncbieaa  "FFLLSSSSYYEECCWWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG",
+  sncbieaa "----------**-----------------------M----------------------------"
+  -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+  -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+  -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+ }
+}
index c430417..aabda20 100644 (file)
@@ -119,10 +119,8 @@ action.select = Select
 action.new_view = New View
 action.close = Close
 action.add = Add
-action.save_as_default = Save as default
 action.save_as = Save as...
 action.save = Save
-action.cancel_fetch = Cancel Fetch
 action.change_font = Change Font
 action.change_font_tree_panel = Change Font (Tree Panel)
 action.colour = Colour
@@ -141,7 +139,6 @@ action.fetch_db_references = Fetch DB References
 action.view_flanking_regions = Show flanking regions
 label.view_flanking_regions = Show sequence data either side of the subsequences involved in this alignment
 label.structures_manager = Structures Manager
-label.nickname = Nickname:
 label.url = URL
 label.url\: = URL:
 label.input_file_url = Enter URL or Input File
@@ -163,7 +160,6 @@ label.current_parameter_set_name = Current parameter set name:
 label.service_action = Service Action:
 label.post_url = POST URL:
 label.url_suffix = URL Suffix
-label.sequence_source = Sequence Source
 label.per_seq = per Sequence
 label.result_vertically_separable = Results are vertically separable
 label.amend = Amend
@@ -353,7 +349,6 @@ label.status = Status
 label.channels = Channels
 label.channel_title_item_count = {0} ({1})
 label.blog_item_published_on_date = {0} {1} 
-label.select_das_service_from_table = Select a DAS service from the table to read a full description here.</font></html>
 label.session_update = Session Update
 label.new_vamsas_session = New Vamsas Session
 action.load_vamsas_session = Load Vamsas Session...
@@ -371,7 +366,6 @@ label.load_colours = Load Colours
 label.save_colours = Save Colours
 label.load_colours_tooltip = Load feature colours and filters from file
 label.save_colours_tooltip = Save feature colours and filters to file
-label.fetch_das_features = Fetch DAS Features
 label.selected_database_to_fetch_from = Selected {0} database {1} to fetch from {2} 
 label.database_param = Database: {0}
 label.example = Example
@@ -409,9 +403,6 @@ label.couldnt_find_pdb_id_in_file = Couldn't find a PDB id in the file supplied.
 label.no_pdb_id_in_file = No PDB Id in File
 label.couldnt_read_pasted_text = Couldn't read the pasted text {0}
 label.error_parsing_text = Error parsing text
-label.enter_local_das_source = Enter Nickname & URL of Local DAS Source
-label.you_can_only_edit_or_remove_local_das_sources = You can only edit or remove local DAS Sources!
-label.public_das_source = Public DAS source - not editable
 label.input_alignment_from_url = Input Alignment From URL
 label.input_alignment = Input Alignment
 label.couldnt_import_as_vamsas_session = Couldn't import {0} as a new vamsas session.
@@ -428,8 +419,6 @@ label.invalid_url = Invalid URL !
 label.error_loading_file = Error loading file
 label.problems_opening_file = Encountered problems opening {0}!!
 label.file_open_error = File open error
-label.no_das_sources_selected_warn = No das sources were selected.\nPlease select some sources and\ntry again.
-label.no_das_sources_selected_title = No DAS Sources Selected
 label.colour_scheme_exists_overwrite = Colour scheme {0} exists.\nContinue saving colour scheme as {1}?"
 label.duplicate_scheme_name = Duplicate scheme name
 label.jalview_new_questionnaire = There is a new Questionnaire available. Would you like to complete it now ?\n
@@ -626,7 +615,6 @@ label.visual = Visual
 label.connections = Connections
 label.output = Output
 label.editing = Editing
-label.das_settings = DAS Settings
 label.web_services = Web Services
 label.right_click_to_edit_currently_selected_parameter = Right click to edit currently selected parameter.
 label.let_jmol_manage_structure_colours = Let Jmol manage structure colours
@@ -642,10 +630,6 @@ label.delete_service_url = Delete Service URL
 label.details = Details
 label.options = Options
 label.parameters = Parameters
-label.available_das_sources = Available DAS Sources
-label.full_details = Full Details
-label.authority = Authority
-label.type = Type
 label.proxy_server = Proxy Server
 label.file_output = File Output
 label.select_input_type = Select input type
@@ -714,9 +698,6 @@ label.sort_alignment_new_tree = Sort Alignment With New Tree
 label.add_sequences = Add Sequences
 label.new_window = New Window
 label.split_window = Split Window
-label.refresh_available_sources = Refresh Available Sources
-label.use_registry = Use Registry
-label.add_local_source = Add Local Source
 label.set_as_default = Set as Default
 label.show_labels = Show labels
 action.background_colour = Background Colour...
@@ -775,7 +756,7 @@ label.run_with_preset_params = Run {0} with preset
 label.view_and_change_parameters_before_running_calculation = View and change parameters before running calculation
 label.view_documentation = View documentation
 label.select_return_type = Select return type
-label.translation_of_params = Translation of {0}
+label.translation_of_params = Translation of {0} (Table {1})
 label.features_for_params = Features for - {0}
 label.annotations_for_params = Annotations for - {0}
 label.generating_features_for_params = Generating features for - {0}
@@ -857,7 +838,6 @@ label.multiharmony = Multi-Harmony
 label.unable_start_web_service_analysis = Unable to start web service analysis
 label.job_couldnt_be_started_check_input = The Job couldn't be started. Please check your input, and the Jalview console for any warning messages.
 label.prompt_each_time = Prompt each time
-label.use_source = Use Source
 label.couldnt_save_project = Couldn't save project
 label.error_whilst_saving_current_state_to = Error whilst saving current state to {0}
 label.error_whilst_loading_project_from = Error whilst loading project from {0}
@@ -1082,8 +1062,6 @@ exception.unable_to_create_internet_config = Unable to create an Internet Config
 exception.invocation_target_calling_url = InvocationTargetException while calling openURL: {0}
 exception.illegal_access_calling_url = IllegalAccessException while calling openURL: {0}
 exception.interrupted_launching_browser = InterruptedException while launching browser: {0}
-exception.das_source_doesnt_support_sequence_command = Source {0} does not support the sequence command.
-exception.invalid_das_source = Invalid das source: {0}
 exception.ebiembl_retrieval_failed_on = EBI EMBL XML retrieval failed on {0}:{1}
 exception.no_pdb_records_for_chain = No PDB Records for {0} chain {1}
 exception.unexpected_handling_rnaml_translation_for_pdb = Unexpected exception when handling RNAML translation of PDB data
@@ -1138,10 +1116,6 @@ status.parsing_results = Parsing results.
 status.processing = Processing...
 status.refreshing_web_service_menus = Refreshing Web Service Menus
 status.collecting_job_results = Collecting job results.
-status.fetching_das_sequence_features = Fetching DAS Sequence Features
-status.no_das_sources_active = No DAS Sources Active
-status.das_feature_fetching_cancelled = DAS Feature Fetching Cancelled
-status.das_feature_fetching_complete = DAS Feature Fetching Complete
 status.fetching_db_refs = Fetching db refs
 status.loading_cached_pdb_entries = Loading Cached PDB Entries
 status.searching_for_pdb_structures = Searching for PDB Structures
@@ -1164,8 +1138,6 @@ warn.urls_not_contacted = URLs that could not be contacted
 warn.urls_no_jaba = URLs without any JABA Services
 info.validate_jabaws_server = Validate JabaWS Server ?\n(Look in console output for results)
 label.test_server = Test Server?
-info.you_want_jalview_to_find_uniprot_accessions = Do you want Jalview to find\nUniprot Accession ids for given sequence names?
-label.find_uniprot_accession_ids = Find Uniprot Accession Ids
 label.new_sequence_fetcher = New Sequence Fetcher
 label.additional_sequence_fetcher = Additional Sequence Fetcher
 label.select_database_retrieval_source = Select Database Retrieval Source
@@ -1301,7 +1273,6 @@ label.edit_sequence_url_link = Edit sequence URL link
 warn.name_cannot_be_duplicate = User-defined URL names must be unique and cannot be MIRIAM ids
 label.output_seq_details = Output Sequence Details to list all database references
 label.urllinks = Links
-label.default_cache_size = Default Cache Size
 action.clear_cached_items = Clear Cached Items
 label.togglehidden = Show hidden regions
 label.quality_descr = Alignment Quality based on Blosum62 scores
@@ -1385,7 +1356,7 @@ label.keep_files = Deleting old backup files
 label.keep_all_backup_files = Do not delete old backup files
 label.keep_only_this_number_of_backup_files = Keep only this number of most recent backup files
 label.autodelete_old_backup_files = Autodelete old backup files:
-label.confirm_delete = Always ask
+label.always_ask = Always ask
 label.auto_delete = Automatically delete
 label.filename = filename
 label.braced_oldest = (oldest)
@@ -1412,4 +1383,11 @@ label.confirm_deletion = Confirm deletion of ''{0}''?
 label.delete = Delete
 label.rename = Rename
 label.keep = Keep
-label.file_info = (modified {0}, size {1})
\ No newline at end of file
+label.file_info = (modified {0}, size {1})
+label.annotation_name = Annotation Name
+label.annotation_description = Annotation Description 
+label.edit_annotation_name_description = Edit Annotation Name/Description
+label.alignment = alignment
+label.pca = PCA
+label.create_image_of = Create {0} image of {1}
+label.click_to_edit = Click to edit, right-click for menu
index e7b9694..b32842e 100644 (file)
@@ -116,10 +116,8 @@ action.select = Seleccionar
 action.new_view = Nueva vista
 action.close = Cerrar
 action.add = Añadir
-action.save_as_default = Guardar como por defecto
 action.save_as = Guardar como
 action.save = Guardar
-action.cancel_fetch = Cancelar búsqueda
 action.change_font = Cambiar Fuente
 action.change_font_tree_panel = Cambiar fuente (panel del Ã¡rbol)
 action.colour = Color
@@ -138,7 +136,6 @@ action.fetch_db_references = Recuperar referencias a base de datos
 action.view_flanking_regions = Mostrar flancos
 label.view_flanking_regions = Mostrar los datos de la secuencia a ambos lados de las subsecuencias implicadas en este alineamiento
 label.structures_manager = Administrar estructuras
-label.nickname = Sobrenombre:
 label.url\: = URL:
 label.url = URL 
 label.input_file_url = Introducir URL en el fichero de entrada
@@ -160,7 +157,6 @@ label.current_parameter_set_name = Nombre actual del conjunto de par
 label.service_action = Acción de servicio:
 label.post_url = POST URL: 
 label.url_suffix = URL Sufijo
-label.sequence_source = Fuente de la secuencia
 label.per_seq = por secuencia
 label.result_vertically_separable = Los resultados son separables verticalmente
 label.amend = Modificar
@@ -322,7 +318,6 @@ label.status =  [Estado]
 label.channels = Canales
 label.channel_title_item_count = {0} ({1})
 label.blog_item_published_on_date = {0} {1} 
-label.select_das_service_from_table = Seleccionar servicio DAS de la tabla para leer una descripción completa aquí.
 label.session_update = Actualizar sesión
 label.new_vamsas_session = Nueva sesión Vamsas
 action.save_vamsas_session = Guardar Sesión Vamsas
@@ -339,7 +334,6 @@ label.load_colours = Cargar colores
 label.save_colours = Guardar colores
 label.load_colours_tooltip = Cargar colores y filtros desde fichero
 label.save_colours_tooltip = Guardar colores y filtros en fichero
-label.fetch_das_features = Recuperar funciones DAS
 label.selected_database_to_fetch_from = Seleccionada {0} Base de datos {1} para buscar de {2} 
 label.database_param = Base de datos: {0}
 label.example = Ejemplo
@@ -376,9 +370,6 @@ label.couldnt_find_pdb_id_in_file = No se pudo encontrar un Id PDB en el fichero
 label.no_pdb_id_in_file = No hay un Id PDB en el fichero
 label.couldnt_read_pasted_text = No se pudo leer el texto pegado {0}
 label.error_parsing_text = Error analizando el texto
-label.enter_local_das_source = Intruduzca el Nickname & URL de la fuente DAS local
-label.you_can_only_edit_or_remove_local_das_sources = Sólo puedes editar o eliminar fuentes DAS locales!
-label.public_das_source = Fuente pública DAS - no editable
 label.input_alignment_from_url = Alineamiento de entrada desde URL
 label.input_alignment = Alineamiento de entrada
 label.couldnt_import_as_vamsas_session = No se pudo importar {0} como una nueva sesión Vamsas.
@@ -395,8 +386,6 @@ 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_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.duplicate_scheme_name = Duplicar nombre de esquema
 label.jalview_new_questionnaire = Hay un nuevo cuestionario disponible. Querr\u00EDa completarlo ahora ?\n
@@ -581,7 +570,6 @@ label.visual = Visual
 label.connections = Conexiones
 label.output = Salida
 label.editing = Edición
-label.das_settings = Configuración DAS
 label.web_services = Servicios web
 label.right_click_to_edit_currently_selected_parameter = Haga clic en el botón derecho para editar el parámetro seleccionado actualmente.
 label.let_jmol_manage_structure_colours = Permitir que Jmol gestione la estructuras cromáticas
@@ -594,10 +582,6 @@ label.delete_service_url = Borrar la URL del servicio
 label.details = Detalles
 label.options = Opciones
 label.parameters = Paramétros
-label.available_das_sources = Fuentes DAS disponibles
-label.full_details = Detalles completos
-label.authority = Autoridad
-label.type = Tipo
 label.proxy_server = Servidor proxy
 label.file_output = Fichero de salida
 label.select_input_type = Seleccionar el tipo de entrada
@@ -660,9 +644,6 @@ label.get_cross_refs = Obtener referencias cruzadas
 label.sort_alignment_new_tree = Alinear el alineamiento con el nuevo Ã¡rbol
 label.add_sequences = Añadir secuencias
 label.new_window = Nueva ventana
-label.refresh_available_sources = Refrescar las fuentes disponibles
-label.use_registry = Utilizar el registro
-label.add_local_source = Añadir fuente local
 label.set_as_default = Establecer por defecto
 label.show_labels = Mostrar etiquetas
 label.associate_nodes_with = Asociar nodos con
@@ -704,7 +685,7 @@ label.run_with_preset_params = Ejecutar {0} con preconfiguraci
 label.view_and_change_parameters_before_running_calculation = Ver y cambiar los parámetros antes de lanzar el cálculo
 label.view_documentation = Ver documentación
 label.select_return_type = Seleccionar el tipo de retorno
-label.translation_of_params = Traducción de {0}
+label.translation_of_params = Traducción de {0} (Tabla {1})
 label.features_for_params = Características de - {0}
 label.annotations_for_params = Anotaciones de - {0}
 label.generating_features_for_params = Generando características de - {0}
@@ -782,7 +763,6 @@ label.multiharmony = Multi-Harmony
 label.unable_start_web_service_analysis = No es posible iniciar el servicio web de análisis
 label.job_couldnt_be_started_check_input = El trabajo no puede arrancarse. Por favor, compruebe los parámetros de entrada y los mensajes de advertencia de la consola de Jalview.
 label.prompt_each_time = Preguntar siempre
-label.use_source = Fuente
 label.couldnt_save_project = No es posible guardar el proyecto
 label.error_whilst_saving_current_state_to = Error mientras se guardaba el estado a {0}
 label.error_whilst_loading_project_from = Error cargando el proyecto desde  {0}
@@ -1007,8 +987,6 @@ exception.unable_to_create_internet_config = Imposible crear una instancia de co
 exception.invocation_target_calling_url = InvocationTargetException mientras se invocaba openURL: {0}
 exception.illegal_access_calling_url = IllegalAccessException mientras se invocaba openURL: {0}
 exception.interrupted_launching_browser = InterruptedException mientras se lanzaba el navegador: {0}
-exception.das_source_doesnt_support_sequence_command = La fuente {0} no soporta el comando sequence.
-exception.invalid_das_source = Fuente DAS no válida: {0}
 exception.ebiembl_retrieval_failed_on = La recuperación de datos EBI EMBL XML ha fallado en {0}:{1}
 exception.no_pdb_records_for_chain = No se han encontrado registros {0} para la cadena {1}
 exception.unexpected_handling_rnaml_translation_for_pdb = Excepcion inesperada cuando se traducían a RNAML los datos PDB
@@ -1060,10 +1038,6 @@ status.parsing_results = Parseando resultados.
 status.processing = Procesando...
 status.refreshing_web_service_menus = Refrescando los menús de servicios web
 status.collecting_job_results = Recolectando los resultados de los trabajos.
-status.fetching_das_sequence_features = Recuperando las características DAS de las secuencias
-status.no_das_sources_active = No existe ninguna fuente DAS activa
-status.das_feature_fetching_cancelled = Recuperación de características DAS cancelada
-status.das_feature_fetching_complete = Recuperación de características DAS completada
 status.fetching_db_refs = Recuperando db refs
 label.font_doesnt_have_letters_defined = La fuente no tiene letras definidas\npor lo que no puede emplease\ncon datos de alineamientos
 label.font_too_small = Tamaño de la letra es demasiado pequeña
@@ -1080,8 +1054,6 @@ warn.server_didnt_pass_validation = El servicio no ha pasado la validaci\u00F3n.
 warn.url_must_contain = La URL de la secuencia debe contener $SEQUENCE_ID$, $DB_ACCESSION$ o un regex
 info.validate_jabaws_server = \u00BFValidar el servidor JabaWS?\n(Consulte la consola de salida para obtener los resultados)
 label.test_server = Â¿Probar servidor?
-info.you_want_jalview_to_find_uniprot_accessions = \u00BFDesea que Jalview encuentre\nUniprot Accession ids para los nombres de secuencias dados?
-label.find_uniprot_accession_ids = Buscar Uniprot Accession Ids
 label.new_sequence_fetcher = Añadir recuperador de secuencias
 label.additional_sequence_fetcher = Recuperador de secuencia adicional
 label.select_database_retrieval_source = Seleccionar fuente de recuperación de bases de datos
@@ -1302,7 +1274,6 @@ label.edit_sequence_url_link = Editar link de secuencia URL
 warn.name_cannot_be_duplicate = Los nombres URL definidos por el usuario deben ser Ãºnicos y no pueden ser ids de MIRIAM
 label.output_seq_details = Seleccionar Detalles de la secuencia para ver todas
 label.urllinks = Enlaces
-label.default_cache_size = Tamaño del caché por defecto
 action.clear_cached_items = Borrar elementos en caché
 label.quality_descr = Calidad de alineamiento basándose en puntuación Blosum62
 label.conservation_descr = Conservación del alineamiento total menos de {0}% huecos
@@ -1386,7 +1357,7 @@ label.keep_files = Borrando los respaldos antiguos
 label.keep_all_backup_files = No borrar respaldos antiguas
 label.keep_only_this_number_of_backup_files = Mantenga solo este número de respaldos más recientes
 label.autodelete_old_backup_files = Borrer automáticamente respaldos antiguos:
-label.confirm_delete = Pregunta siempre
+label.always_ask = Pregunta siempre
 label.auto_delete = Borrer automáticamente
 label.filename = nombre_de_archivo
 label.braced_oldest = (mas antiguo)
@@ -1407,10 +1378,17 @@ label.warning_confirm_change_reverse = 
 label.change_increment_decrement = Â¿Cambiar de incremento/decremento?
 label.was_previous = era {0}
 label.newerdelete_replacement_line = El archivo de respaldo\n''{0}''\t(modificado {2}, tamaño {4})\nserá borrado y reemplazarse por un archivo aparentemente más antiguo\n''{1}''\t(modificado {3}, tamaño {5}).
-label.confirm_delete_or_rename = Confirmar borrar ''{0}'', o cambiar el nombre a ''{1}''?
+label.confirm_deletion_or_rename = Confirmar borrar ''{0}'', o cambiar el nombre a ''{1}''?
 label.newerdelete_line = El archivo de respaldo\n''{0}''\t(modificado {2}, tamaño {4})\nserá borrado pero es mas nuevo que el archivo de respaldo restante más antiguo\n''{1}''\t(modified {3}, size {5}).
-label.confirm_delete = Confirmar eliminar ''{0}''?
+label.confirm_deletion = Confirmar eliminar ''{0}''?
 label.delete = Borrar
 label.rename = Cambiar
 label.keep = Mantener
-label.file_info = (modificado {0}, tamaño {1})
\ No newline at end of file
+label.file_info = (modificado {0}, tamaño {1})
+label.annotation_name = Nombre de la anotación
+label.annotation_description = Descripción de la anotación 
+label.edit_annotation_name_description = Editar el nombre/descripción de la anotación
+label.alignment = alineamiento
+label.pca = ACP
+label.create_image_of = Crear imagen {0} de {1}
+label.click_to_edit = Haga clic para editar, clic en el botón derecho para ver el menú  
index 2ad8487..9611a4c 100644 (file)
@@ -194,10 +194,11 @@ public class Dna
   }
 
   /**
+   * Translates cDNA using the specified code table
    * 
    * @return
    */
-  public AlignmentI translateCdna()
+  public AlignmentI translateCdna(GeneticCodeI codeTable)
   {
     AlignedCodonFrame acf = new AlignedCodonFrame();
 
@@ -209,7 +210,7 @@ public class Dna
     for (s = 0; s < sSize; s++)
     {
       SequenceI newseq = translateCodingRegion(selection.get(s),
-              seqstring[s], acf, pepseqs);
+              seqstring[s], acf, pepseqs, codeTable);
 
       if (newseq != null)
       {
@@ -429,11 +430,12 @@ public class Dna
    * @param acf
    *          Definition of global ORF alignment reference frame
    * @param proteinSeqs
+   * @param codeTable
    * @return sequence ready to be added to alignment.
    */
   protected SequenceI translateCodingRegion(SequenceI selection,
           String seqstring, AlignedCodonFrame acf,
-          List<SequenceI> proteinSeqs)
+          List<SequenceI> proteinSeqs, GeneticCodeI codeTable)
   {
     List<int[]> skip = new ArrayList<>();
     int[] skipint = null;
@@ -466,9 +468,8 @@ public class Dna
         /*
          * Filled up a reading frame...
          */
-        AlignedCodon alignedCodon = new AlignedCodon(cdp[0], cdp[1],
-                cdp[2]);
-        String aa = ResidueProperties.codonTranslate(new String(codon));
+        AlignedCodon alignedCodon = new AlignedCodon(cdp[0], cdp[1], cdp[2]);
+        String aa = codeTable.translate(new String(codon));
         rf = 0;
         final String gapString = String.valueOf(gapChar);
         if (aa == null)
index 191f6e8..3cbef6d 100644 (file)
  */
 package jalview.analysis;
 
+import jalview.api.AlignViewportI;
+import jalview.api.FinderI;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Range;
 import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.datamodel.VisibleContigsIterator;
 import jalview.util.Comparison;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Vector;
 
 import com.stevesoft.pat.Regex;
 
-public class Finder
+/**
+ * Implements the search algorithm for the Find dialog
+ */
+public class Finder implements FinderI
 {
-  /**
-   * Implements the search algorithms for the Find dialog box.
+  /*
+   * matched residue locations
    */
-  SearchResultsI searchResults;
+  private SearchResultsI searchResults;
 
-  AlignmentI alignment;
+  /*
+   * sequences matched by id or description
+   */
+  private Vector<SequenceI> idMatches;
 
-  SequenceGroup selection = null;
+  /*
+   * the viewport to search over
+   */
+  private AlignViewportI viewport;
 
-  Vector<SequenceI> idMatch = null;
+  /*
+   * sequence index in alignment to search from
+   */
+  private int sequenceIndex;
 
-  boolean caseSensitive = false;
+  /*
+   * column position in sequence to search from, base 0
+   * - absolute column number including any hidden columns
+   * (position after start of last match for a repeat search)
+   */
+  private int columnIndex;
 
-  private boolean includeDescription = false;
+  /**
+   * Constructor for searching a viewport
+   * 
+   * @param av
+   */
+  public Finder(AlignViewportI av)
+  {
+    this.viewport = av;
+    this.sequenceIndex = 0;
+    this.columnIndex = -1;
+  }
 
-  boolean findAll = false;
+  @Override
+  public void findAll(String theSearchString, boolean matchCase,
+          boolean searchDescription)
+  {
+    /*
+     * search from the start
+     */
+    sequenceIndex = 0;
+    columnIndex = -1;
 
-  Regex regex = null;
+    doFind(theSearchString, matchCase, searchDescription, true);
 
-  /**
-   * holds last-searched position between calls to find(false)
-   */
-  int seqIndex = 0, resIndex = -1;
+    /*
+     * reset to start for next search
+     */
+    sequenceIndex = 0;
+    columnIndex = -1;
+  }
 
-  public Finder(AlignmentI alignment, SequenceGroup selection)
+  @Override
+  public void findNext(String theSearchString, boolean matchCase,
+          boolean searchDescription)
   {
-    this.alignment = alignment;
-    this.selection = selection;
+    doFind(theSearchString, matchCase, searchDescription, false);
+    
+    if (searchResults.isEmpty() && idMatches.isEmpty())
+    {
+      /*
+       * search failed - reset to start for next search
+       */
+      sequenceIndex = 0;
+      columnIndex = -1;
+    }
   }
 
   /**
-   * restart search at given sequence and residue on alignment and (optionally)
-   * contained in selection
+   * Performs a 'find next' or 'find all'
    * 
-   * @param alignment
-   * @param selectionGroup
-   * @param seqIndex
-   * @param resIndex
+   * @param theSearchString
+   * @param matchCase
+   * @param searchDescription
+   * @param findAll
    */
-  public Finder(AlignmentI alignment, SequenceGroup selectionGroup,
-          int seqIndex, int resIndex)
+  protected void doFind(String theSearchString, boolean matchCase,
+          boolean searchDescription, boolean findAll)
   {
-    this(alignment, selectionGroup);
-    this.seqIndex = seqIndex;
-    this.resIndex = resIndex;
-  }
+    String searchString = matchCase ? theSearchString
+            : theSearchString.toUpperCase();
+    Regex searchPattern = new Regex(searchString);
+    searchPattern.setIgnoreCase(!matchCase);
 
-  public boolean find(String searchString)
-  {
-    boolean hasResults = false;
-    if (!caseSensitive)
-    {
-      searchString = searchString.toUpperCase();
-    }
-    regex = new Regex(searchString);
-    regex.setIgnoreCase(!caseSensitive);
     searchResults = new SearchResults();
-    idMatch = new Vector<SequenceI>();
-    String item = null;
-    boolean found = false;
-    int end = alignment.getHeight();
+    idMatches = new Vector<>();
 
-    // /////////////////////////////////////////////
-
-    if (selection != null)
+    SequenceGroup selection = viewport.getSelectionGroup();
+    if (selection != null && selection.getSize() < 1)
     {
-      if ((selection.getSize() < 1)
-              || ((selection.getEndRes() - selection.getStartRes()) < 2))
-      {
-        selection = null;
-      }
+      selection = null; // ? ignore column-only selection
     }
-    SearchResultMatchI lastm = null;
 
-    while (!found && (seqIndex < end))
-    {
-      SequenceI seq = alignment.getSequenceAt(seqIndex);
+    AlignmentI alignment = viewport.getAlignment();
+    int end = alignment.getHeight();
 
-      if ((selection != null && selection.getSize() > 0)
-              && !selection.getSequences(null).contains(seq))
+    while (sequenceIndex < end)
+    {
+      SequenceI seq = alignment.getSequenceAt(sequenceIndex);
+      boolean found = findNextMatch(seq, searchString, searchPattern,
+              searchDescription);
+      if (found && !findAll)
       {
-        seqIndex++;
-        resIndex = -1;
-
-        continue;
+        return;
       }
-      if (resIndex < 0)
+      if (!found)
       {
-        resIndex = 0;
-        // test for one off matches - sequence position and sequence ID
-        // //// is the searchString a residue number?
-        try
-        {
-          int res = Integer.parseInt(searchString);
-          // possibly a residue number - check if valid for seq
-          if (seq.getEnd() >= res)
-          {
-            searchResults.addResult(seq, res, res);
-            hasResults = true;
-            // resIndex=seq.getLength();
-            // seqIndex++;
-            if (!findAll)
-            {
-              found = true;
-              break;
-            }
-          }
-        } catch (NumberFormatException ex)
-        {
-        }
-
-        if (regex.search(seq.getName()) && !idMatch.contains(seq))
-        {
-          idMatch.addElement(seq);
-          hasResults = true;
-          if (!findAll)
-          {
-            // stop and return the match
-            found = true;
-            break;
-          }
-        }
-
-        if (isIncludeDescription() && seq.getDescription() != null
-                && regex.search(seq.getDescription())
-                && !idMatch.contains(seq))
-        {
-          idMatch.addElement(seq);
-          hasResults = true;
-          if (!findAll)
-          {
-            // stop and return the match
-            found = true;
-            break;
-          }
-        }
+        sequenceIndex++;
+        columnIndex = -1;
       }
-      item = seq.getSequenceAsString();
+    }
+  }
 
-      if ((selection != null)
-              && (selection.getEndRes() < alignment.getWidth() - 1))
-      {
-        item = item.substring(0, selection.getEndRes() + 1);
-      }
+  /**
+   * Answers the start-end column range of the visible region of
+   * <code>sequence</code> starting at or after the given <code>column</code>.
+   * If there are no hidden columns, this just returns the remaining width of
+   * the sequence. The range is restricted to the current <code>selection</code>
+   * if there is one. Answers null if there are no visible columns at or after
+   * <code>column</code>.
+   */
+  protected Range getNextVisibleSequenceRegion(SequenceI sequence,
+          int column)
+  {
+    int seqColStart = column;
+    int seqColEnd = sequence.getLength() - 1;
 
-      // /Shall we ignore gaps???? - JBPNote: Add Flag for forcing this or not
-      StringBuilder noGapsSB = new StringBuilder();
-      int insertCount = 0;
-      List<Integer> spaces = new ArrayList<Integer>();
+    /*
+     * restrict search to (next) visible column region, 
+     * in case there are hidden columns
+     */
+    AlignmentI alignment = viewport.getAlignment();
+    VisibleContigsIterator visibleRegions = alignment.getHiddenColumns()
+            .getVisContigsIterator(column, alignment.getWidth(),
+                    false);
+    int[] visible = visibleRegions.hasNext() ? visibleRegions.next() : null;
+    if (visible == null)
+    {
+      columnIndex = seqColEnd + 1;
+      return null;
+    }
+    seqColStart = Math.max(seqColStart, visible[0]);
+    seqColEnd = Math.min(seqColEnd, visible[1]);
 
-      for (int j = 0; j < item.length(); j++)
+    /*
+     * restrict search to selected region if there is one
+     */
+    SequenceGroup selection = viewport.getSelectionGroup();
+    if (selection != null)
+    {
+      int selectionStart = selection.getStartRes();
+      int selectionEnd = selection.getEndRes();
+      if (selectionStart > seqColEnd || selectionEnd < seqColStart)
       {
-        if (!Comparison.isGap(item.charAt(j)))
-        {
-          noGapsSB.append(item.charAt(j));
-          spaces.add(Integer.valueOf(insertCount));
-        }
-        else
-        {
-          insertCount++;
-        }
+        /*
+         * sequence region doesn't overlap selection region 
+         */
+        columnIndex = seqColEnd + 1;
+        return null;
       }
+      seqColStart = Math.max(seqColStart, selectionStart);
+      seqColEnd = Math.min(seqColEnd, selectionEnd);
+    }
 
-      String noGaps = noGapsSB.toString();
-      for (int r = resIndex; r < noGaps.length(); r++)
-      {
+    return new Range(seqColStart, seqColEnd);
+  }
 
-        if (regex.searchFrom(noGaps, r))
-        {
-          resIndex = regex.matchedFrom();
-
-          if ((selection != null && selection.getSize() > 0) && (resIndex
-                  + spaces.get(resIndex) < selection.getStartRes()))
-          {
-            continue;
-          }
-          // if invalid string used, then regex has no matched to/from
-          int sres = seq.findPosition(resIndex + spaces.get(resIndex));
-          int eres = seq.findPosition(regex.matchedTo() - 1
-                  + (spaces.get(regex.matchedTo() - 1)));
-          // only add result if not contained in previous result
-          if (lastm == null || (lastm.getSequence() != seq
-                  || (!(lastm.getStart() <= sres
-                          && lastm.getEnd() >= eres))))
-          {
-            lastm = searchResults.addResult(seq, sres, eres);
-          }
-          hasResults = true;
-          if (!findAll)
-          {
-            // thats enough, break and display the result
-            found = true;
-            resIndex++;
-
-            break;
-          }
-
-          r = resIndex;
-        }
-        else
-        {
-          break;
-        }
-      }
+  /**
+   * Finds the next match in the given sequence, starting at column at
+   * <code>columnIndex</code>. Answers true if a match is found, else false. If
+   * a match is found, <code>columnIndex</code> is advanced to the column after
+   * the start of the matched region, ready for a search from the next position.
+   * 
+   * @param seq
+   * @param searchString
+   * @param searchPattern
+   * @param matchDescription
+   * @return
+   */
+  protected boolean findNextMatch(SequenceI seq, String searchString,
+          Regex searchPattern, boolean matchDescription)
+  {
+    SequenceGroup selection = viewport.getSelectionGroup();
+    if (selection != null && !selection.contains(seq))
+    {
+      /*
+       * this sequence is not in the selection - advance to next sequence
+       */
+      return false;
+    }
 
-      if (!found)
+    if (columnIndex < 0)
+    {
+      /*
+       * at start of sequence; try find by residue number, in sequence id,
+       * or (optionally) in sequence description
+       */
+      if (doNonMotifSearches(seq, searchString, searchPattern,
+              matchDescription))
       {
-        seqIndex++;
-        resIndex = -1;
+        return true;
       }
     }
 
-    /**
-     * We now search the Id string in the main search loop. for (int id = 0; id
-     * < alignment.getHeight(); id++) { if
-     * (regex.search(alignment.getSequenceAt(id).getName())) {
-     * idMatch.addElement(alignment.getSequenceAt(id)); hasResults = true; } }
+    /*
+     * search for next match in sequence string
      */
-    return hasResults;
-  }
-
-  /**
-   * @return the alignment
-   */
-  public AlignmentI getAlignment()
-  {
-    return alignment;
+    int end = seq.getLength();
+    while (columnIndex < end)
+    {
+      if (searchNextVisibleRegion(seq, searchPattern))
+      {
+        return true;
+      }
+    }
+    return false;
   }
 
   /**
-   * @param alignment
-   *          the alignment to set
+   * Searches the sequence, starting from <code>columnIndex</code>, and adds the
+   * next match (if any) to <code>searchResults</code>. The search is restricted
+   * to the next visible column region, and to the <code>selection</code> region
+   * if there is one. Answers true if a match is added, else false.
+   * 
+   * @param seq
+   * @param searchPattern
+   * @return
    */
-  public void setAlignment(AlignmentI alignment)
+  protected boolean searchNextVisibleRegion(SequenceI seq, Regex searchPattern)
   {
-    this.alignment = alignment;
-  }
+    Range visible = getNextVisibleSequenceRegion(seq, columnIndex);
+    if (visible == null)
+    {
+      return false;
+    }
+    String seqString = seq.getSequenceAsString(visible.start, visible.end + 1);
+    String noGaps = AlignSeq.extractGaps(Comparison.GapChars, seqString);
 
-  /**
-   * @return the caseSensitive
-   */
-  public boolean isCaseSensitive()
-  {
-    return caseSensitive;
-  }
+    if (searchPattern.search(noGaps))
+    {
+      int sequenceStartPosition = seq.findPosition(visible.start);
+      recordMatch(seq, searchPattern, sequenceStartPosition);
+      return true;
+    }
+    else
+    {
+      /*
+       * no match - advance columnIndex past this visible region
+       * so the next visible region (if any) is searched next
+       */
+      columnIndex = visible.end + 1;
+    }
 
-  /**
-   * @param caseSensitive
-   *          the caseSensitive to set
-   */
-  public void setCaseSensitive(boolean caseSensitive)
-  {
-    this.caseSensitive = caseSensitive;
+    return false;
   }
 
   /**
-   * @return the findAll
+   * Adds the match held in the <code>searchPattern</code> Regex to the
+   * <code>searchResults</code>, unless it is a subregion of the last match
+   * recorded. <code>columnIndex</code> is advanced to the position after the
+   * start of the matched region, ready for the next search. Answers true if a
+   * match was added, else false.
+   * 
+   * @param seq
+   * @param searchPattern
+   * @param firstResiduePosition
+   * @return
    */
-  public boolean isFindAll()
+  protected boolean recordMatch(SequenceI seq, Regex searchPattern,
+          int firstResiduePosition)
   {
-    return findAll;
-  }
+    /*
+     * get start/end of the match in sequence coordinates
+     */
+    int offset = searchPattern.matchedFrom();
+    int matchStartPosition = firstResiduePosition + offset;
+    int matchEndPosition = matchStartPosition
+            + searchPattern.charsMatched() - 1;
+
+    /*
+     * update columnIndex to next column after the start of the match
+     * (findIndex returns a value base 1, columnIndex is held base 0)
+     */
+    columnIndex = seq.findIndex(matchStartPosition);
 
-  /**
-   * @param findAll
-   *          the findAll to set
-   */
-  public void setFindAll(boolean findAll)
-  {
-    this.findAll = findAll;
-  }
+    /*
+     * check that this match is not a subset of the previous one (JAL-2302)
+     */
+    List<SearchResultMatchI> matches = searchResults.getResults();
+    SearchResultMatchI lastMatch = matches.isEmpty() ? null
+            : matches.get(matches.size() - 1);
 
-  /**
-   * @return the selection
-   */
-  public jalview.datamodel.SequenceGroup getSelection()
-  {
-    return selection;
-  }
+    if (lastMatch == null || !lastMatch.contains(seq, matchStartPosition,
+            matchEndPosition))
+    {
+      searchResults.addResult(seq, matchStartPosition, matchEndPosition);
+      return true;
+    }
 
-  /**
-   * @param selection
-   *          the selection to set
-   */
-  public void setSelection(jalview.datamodel.SequenceGroup selection)
-  {
-    this.selection = selection;
+    return false;
   }
 
   /**
-   * Returns the (possibly empty) list of matching sequences (when search
-   * includes searching sequence names)
+   * Does searches other than for residue patterns. Currently this includes
+   * <ul>
+   * <li>find residue by position (if search string is a number)</li>
+   * <li>match search string to sequence id</li>
+   * <li>match search string to sequence description (optional)</li>
+   * </ul>
+   * Answers true if a match is found, else false.
    * 
+   * @param seq
+   * @param searchString
+   * @param searchPattern
+   * @param includeDescription
    * @return
    */
-  public Vector<SequenceI> getIdMatch()
+  protected boolean doNonMotifSearches(SequenceI seq, String searchString,
+          Regex searchPattern, boolean includeDescription)
   {
-    return idMatch;
-  }
+    /*
+     * position sequence search to start of sequence
+     */
+    columnIndex = 0;
 
-  /**
-   * @return the regex
-   */
-  public com.stevesoft.pat.Regex getRegex()
-  {
-    return regex;
+    if (searchForResidueNumber(seq, searchString))
+    {
+      return true;
+    }
+    if (searchSequenceName(seq, searchPattern))
+    {
+      return true;
+    }
+    if (includeDescription && searchSequenceDescription(seq, searchPattern))
+    {
+      return true;
+    }
+    return false;
   }
 
   /**
-   * @return the searchResults
+   * Searches for a match with the sequence description, and if found, adds the
+   * sequence to the list of match ids (but not as a duplicate). Answers true if
+   * a match was added, else false.
+   * 
+   * @param seq
+   * @param searchPattern
+   * @return
    */
-  public SearchResultsI getSearchResults()
+  protected boolean searchSequenceDescription(SequenceI seq, Regex searchPattern)
   {
-    return searchResults;
+    String desc = seq.getDescription();
+    if (desc != null && searchPattern.search(desc) && !idMatches.contains(seq))
+    {
+      idMatches.addElement(seq);
+      return true;
+    }
+    return false;
   }
 
   /**
-   * @return the resIndex
+   * Searches for a match with the sequence name, and if found, adds the
+   * sequence to the list of match ids (but not as a duplicate). Answers true if
+   * a match was added, else false.
+   * 
+   * @param seq
+   * @param searchPattern
+   * @return
    */
-  public int getResIndex()
+  protected boolean searchSequenceName(SequenceI seq, Regex searchPattern)
   {
-    return resIndex;
+    if (searchPattern.search(seq.getName()) && !idMatches.contains(seq))
+    {
+      idMatches.addElement(seq);
+      return true;
+    }
+    return false;
   }
 
   /**
-   * @param resIndex
-   *          the resIndex to set
+   * Tries to interpret the search string as a residue position, and if valid,
+   * adds the position to the search results and returns true, else answers
+   * false
    */
-  public void setResIndex(int resIndex)
+  protected boolean searchForResidueNumber(SequenceI seq, String searchString)
   {
-    this.resIndex = resIndex;
+    try
+    {
+      int res = Integer.parseInt(searchString);
+      if (seq.getStart() <= res && seq.getEnd() >= res)
+      {
+        searchResults.addResult(seq, res, res);
+        return true;
+      }
+    } catch (NumberFormatException ex)
+    {
+    }
+    return false;
   }
 
-  /**
-   * @return the seqIndex
+  /* (non-Javadoc)
+   * @see jalview.analysis.FinderI#getIdMatch()
    */
-  public int getSeqIndex()
+  @Override
+  public Vector<SequenceI> getIdMatches()
   {
-    return seqIndex;
+    return idMatches;
   }
 
-  /**
-   * @param seqIndex
-   *          the seqIndex to set
+  /* (non-Javadoc)
+   * @see jalview.analysis.FinderI#getSearchResults()
    */
-  public void setSeqIndex(int seqIndex)
-  {
-    this.seqIndex = seqIndex;
-  }
-
-  public boolean isIncludeDescription()
-  {
-    return includeDescription;
-  }
-
-  public void setIncludeDescription(boolean includeDescription)
+  @Override
+  public SearchResultsI getSearchResults()
   {
-    this.includeDescription = includeDescription;
+    return searchResults;
   }
 }
diff --git a/src/jalview/analysis/GeneticCodeI.java b/src/jalview/analysis/GeneticCodeI.java
new file mode 100644 (file)
index 0000000..daed0ac
--- /dev/null
@@ -0,0 +1,46 @@
+package jalview.analysis;
+
+public interface GeneticCodeI
+{
+  /**
+   * Answers the single letter amino acid code (e.g. "D") for the given codon
+   * (e.g. "GAC"), or "*" for a stop codon, or null for an unknown input. The
+   * codon is not case-sensitive, the return value is upper case.
+   * <p>
+   * If the codon includes any of the standard ambiguity codes
+   * <ul>
+   * <li>if all possible translations are the same, returns that value</li>
+   * <li>else returns null</li>
+   * </ul>
+   * 
+   * @param codon
+   * @return
+   */
+  String translate(String codon);
+
+  /**
+   * Answers the single letter amino acid code (e.g. "D") for the given codon
+   * (e.g. "GAC"), or "*" for a stop codon, or null for an unknown input. The
+   * codon is not case-sensitive, the return value is upper case. If the codon
+   * includes any of the standard ambiguity codes, this method returns null.
+   * 
+   * @param codon
+   * @return
+   */
+  String translateCanonical(String codon);
+
+  /**
+   * Answers a unique identifier for the genetic code (using the numbering
+   * system as on NCBI)
+   * 
+   * @return
+   */
+  String getId();
+
+  /**
+   * Answers a display name suitable for use in menus, reports etc
+   * 
+   * @return
+   */
+  String getName();
+}
diff --git a/src/jalview/analysis/GeneticCodes.java b/src/jalview/analysis/GeneticCodes.java
new file mode 100644 (file)
index 0000000..d07253e
--- /dev/null
@@ -0,0 +1,402 @@
+package jalview.analysis;
+
+import jalview.bin.Cache;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/**
+ * A singleton that provides instances of genetic code translation tables
+ * 
+ * @author gmcarstairs
+ * @see https://www.ncbi.nlm.nih.gov/Taxonomy/Utils/wprintgc.cgi
+ */
+public final class GeneticCodes
+{
+  private static final int CODON_LENGTH = 3;
+
+  private static final String QUOTE = "\"";
+
+  /*
+   * nucleotides as ordered in data file
+   */
+  private static final String NUCS = "TCAG";
+
+  private static final int NUCS_COUNT = NUCS.length();
+
+  private static final int NUCS_COUNT_SQUARED = NUCS_COUNT * NUCS_COUNT;
+
+  private static final int NUCS_COUNT_CUBED = NUCS_COUNT * NUCS_COUNT
+          * NUCS_COUNT;
+
+  private static final String AMBIGUITY_CODES_FILE = "/AmbiguityCodes.dat";
+
+  private static final String RESOURCE_FILE = "/GeneticCodes.dat";
+
+  private static GeneticCodes instance = new GeneticCodes();
+
+  private Map<String, String> ambiguityCodes;
+
+  /*
+   * loaded code tables, with keys in order of loading 
+   */
+  private Map<String, GeneticCodeI> codeTables;
+
+  /**
+   * Private constructor enforces singleton
+   */
+  private GeneticCodes()
+  {
+    if (instance == null)
+    {
+      ambiguityCodes = new HashMap<>();
+
+      /*
+       * LinkedHashMap preserves order of addition of entries,
+       * so we can assume the Standard Code Table is the first
+       */
+      codeTables = new LinkedHashMap<>();
+      loadAmbiguityCodes(AMBIGUITY_CODES_FILE);
+      loadCodes(RESOURCE_FILE);
+    }
+  };
+
+  /**
+   * Returns the singleton instance of this class
+   * 
+   * @return
+   */
+  public static GeneticCodes getInstance()
+  {
+    return instance;
+  }
+
+  /**
+   * Returns the known code tables, in order of loading.
+   * 
+   * @return
+   */
+  public Iterable<GeneticCodeI> getCodeTables()
+  {
+    return codeTables.values();
+  }
+
+  /**
+   * Answers the code table with the given id
+   * 
+   * @param id
+   * @return
+   */
+  public GeneticCodeI getCodeTable(String id)
+  {
+    return codeTables.get(id);
+  }
+
+  /**
+   * A convenience method that returns the standard code table (table 1). As
+   * implemented, this has to be the first table defined in the data file.
+   * 
+   * @return
+   */
+  public GeneticCodeI getStandardCodeTable()
+  {
+    return codeTables.values().iterator().next();
+  }
+
+  /**
+   * Loads the code tables from a data file
+   */
+  protected void loadCodes(String fileName)
+  {
+    try
+    {
+      InputStream is = getClass().getResourceAsStream(fileName);
+      BufferedReader dataIn = new BufferedReader(new InputStreamReader(is));
+
+      /*
+       * skip comments and start of table
+       */
+      String line = "";
+      while (line != null && !line.startsWith("Genetic-code-table"))
+      {
+        line = readLine(dataIn);
+      }
+      line = readLine(dataIn);
+
+      while (line.startsWith("{"))
+      {
+        line = loadOneTable(dataIn);
+      }
+    } catch (IOException | NullPointerException e)
+    {
+      Cache.log.error(
+              "Error reading genetic codes data file: "
+              + e.getMessage());
+    }
+  }
+
+  /**
+   * Reads and saves Nucleotide ambiguity codes from a data file. The file may
+   * include comment lines (starting with #), a header 'DNA', and one line per
+   * ambiguity code, for example:
+   * <p>
+   * R&lt;tab&gt;AG
+   * <p>
+   * means that R is an ambiguity code meaning "A or G"
+   * 
+   * @param fileName
+   */
+  protected void loadAmbiguityCodes(String fileName)
+  {
+    try
+    {
+      InputStream is = getClass().getResourceAsStream(fileName);
+      BufferedReader dataIn = new BufferedReader(new InputStreamReader(is));
+      String line = "";
+      while (line != null)
+      {
+        line = readLine(dataIn);
+        if (line != null && !"DNA".equals(line.toUpperCase()))
+        {
+          String[] tokens = line.split("\\t");
+          ambiguityCodes.put(tokens[0].toUpperCase(),
+                  tokens[1].toUpperCase());
+        }
+      }
+    } catch (IOException e)
+    {
+      Cache.log.error(
+              "Error reading nucleotide ambiguity codes data file: "
+                      + e.getMessage());
+    }
+  }
+
+  /**
+   * Reads up to and returns the next non-comment line, trimmed. Comment lines
+   * start with a #. Returns null at end of file.
+   * 
+   * @param dataIn
+   * @return
+   * @throws IOException
+   */
+  protected String readLine(BufferedReader dataIn) throws IOException
+  {
+    String line = dataIn.readLine();
+    while (line != null && line.startsWith("#"))
+    {
+      line = readLine(dataIn);
+    }
+    return line == null ? null : line.trim();
+  }
+
+  /**
+   * Reads the lines of the data file describing one translation table, and
+   * creates and stores an instance of GeneticCodeI. Returns the '{' line
+   * starting the next table, or the '}' line at end of all tables. Data format
+   * is
+   * 
+   * <pre>
+   * {
+   *   name "Vertebrate Mitochondrial" ,
+   *   name "SGC1" ,
+   *   id 2 ,
+   *   ncbieaa  "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNKKSS**VVVVAAAADDEEGGGG",
+   *   sncbieaa "----------**--------------------MMMM----------**---M------------"
+   *   -- Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
+   *   -- Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
+   *   -- Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
+   * },
+   * </pre>
+   * 
+   * of which we parse the first name, the id, and the ncbieaa translations for
+   * codons as ordered by the Base1/2/3 lines. Note Base1/2/3 are included for
+   * readability and are in a fixed order, these are not parsed. The sncbieaa
+   * line marks alternative start codons, these are not parsed.
+   * 
+   * @param dataIn
+   * @return
+   * @throws IOException
+   */
+  protected String loadOneTable(BufferedReader dataIn) throws IOException
+  {
+    String name = null;
+    String id = null;
+    Map<String, String> codons = new HashMap<>();
+
+    String line = readLine(dataIn);
+
+    while (line != null && !line.startsWith("}"))
+    {
+      if (line.startsWith("name") && name == null)
+      {
+        name = line.substring(line.indexOf(QUOTE) + 1,
+                line.lastIndexOf(QUOTE));
+      }
+      else if (line.startsWith("id"))
+      {
+        id = new StringTokenizer(line.substring(2)).nextToken();
+      }
+      else if (line.startsWith("ncbieaa"))
+      {
+        String aminos = line.substring(line.indexOf(QUOTE) + 1,
+                line.lastIndexOf(QUOTE));
+        if (aminos.length() != NUCS_COUNT_CUBED) // 4 * 4 * 4 combinations
+        {
+          Cache.log.error("wrong data length in code table: " + line);
+        }
+        else
+        {
+          for (int i = 0; i < aminos.length(); i++)
+          {
+            String peptide = String.valueOf(aminos.charAt(i));
+            char codon1 = NUCS.charAt(i / NUCS_COUNT_SQUARED);
+            char codon2 = NUCS
+                    .charAt((i % NUCS_COUNT_SQUARED) / NUCS_COUNT);
+            char codon3 = NUCS.charAt(i % NUCS_COUNT);
+            String codon = new String(
+                    new char[]
+                    { codon1, codon2, codon3 });
+            codons.put(codon, peptide);
+          }
+        }
+      }
+      line = readLine(dataIn);
+    }
+
+    registerCodeTable(id, name, codons);
+    return readLine(dataIn);
+  }
+
+  /**
+   * Constructs and registers a GeneticCodeI instance with the codon
+   * translations as defined in the data file. For all instances except the
+   * first, any undeclared translations default to those in the standard code
+   * table.
+   * 
+   * @param id
+   * @param name
+   * @param codons
+   */
+  protected void registerCodeTable(final String id, final String name,
+          final Map<String, String> codons)
+  {
+    codeTables.put(id, new GeneticCodeI()
+    {
+      /*
+       * map of ambiguous codons to their 'product'
+       * (null if not all possible translations match)
+       */
+      Map<String, String> ambiguous = new HashMap<>();
+
+      @Override
+      public String translateCanonical(String codon)
+      {
+        return codons.get(codon.toUpperCase());
+      }
+
+      @Override
+      public String translate(String codon)
+      {
+        String upper = codon.toUpperCase();
+        String peptide = translateCanonical(upper);
+
+        /*
+         * if still not translated, check for ambiguity codes
+         */
+        if (peptide == null)
+        {
+          peptide = getAmbiguousTranslation(upper, ambiguous, this);
+        }
+        return peptide;
+      }
+
+      @Override
+      public String getId()
+      {
+        return id;
+      }
+
+      @Override
+      public String getName()
+      {
+        return name;
+      }
+    });
+  }
+
+  /**
+   * Computes all possible translations of a codon including one or more
+   * ambiguity codes, and stores and returns the result (null if not all
+   * translations match). If the codon includes no ambiguity codes, simply
+   * returns null.
+   * 
+   * @param codon
+   * @param ambiguous
+   * @param codeTable
+   * @return
+   */
+  protected String getAmbiguousTranslation(String codon,
+          Map<String, String> ambiguous, GeneticCodeI codeTable)
+  {
+    if (codon.length() != CODON_LENGTH)
+    {
+      return null;
+    }
+
+    boolean isAmbiguous = false;
+
+    char[][] expanded = new char[CODON_LENGTH][];
+    for (int i = 0; i < CODON_LENGTH; i++)
+    {
+      String base = String.valueOf(codon.charAt(i));
+      if (ambiguityCodes.containsKey(base))
+      {
+        isAmbiguous = true;
+        base = ambiguityCodes.get(base);
+      }
+      expanded[i] = base.toCharArray();
+    }
+
+    if (!isAmbiguous)
+    {
+      // no ambiguity code involved here
+      return null;
+    }
+
+    /*
+     * generate and translate all permutations of the ambiguous codon
+     * only return the translation if they all agree, else null
+     */
+    String peptide = null;
+    for (char c1 : expanded[0])
+    {
+      for (char c2 : expanded[1])
+      {
+        for (char c3 : expanded[2])
+        {
+          char[] cdn = new char[] { c1, c2, c3 };
+          String possibleCodon = String.valueOf(cdn);
+          String pep = codeTable.translate(possibleCodon);
+          if (pep == null || (peptide != null && !pep.equals(peptide)))
+          {
+            ambiguous.put(codon, null);
+            return null;
+          }
+          peptide = pep;
+        }
+      }
+    }
+
+    /*
+     * all translations of ambiguous codons matched!
+     */
+    ambiguous.put(codon, peptide);
+    return peptide;
+  }
+}
index 999104c..7bfd8a8 100644 (file)
@@ -204,4 +204,12 @@ public interface FeatureColourI
    * @return
    */
   boolean isOutwithThreshold(SequenceFeature sf);
+
+  /*
+   * Answers a human-readable text description of the colour, suitable for
+   * display as a tooltip, possibly internationalised for the user's locale.
+   * 
+   * @return
+   */
+  String getDescription();
 }
diff --git a/src/jalview/api/FinderI.java b/src/jalview/api/FinderI.java
new file mode 100644 (file)
index 0000000..19f6136
--- /dev/null
@@ -0,0 +1,62 @@
+package jalview.api;
+
+import jalview.datamodel.SearchResultsI;
+import jalview.datamodel.SequenceI;
+
+import java.util.List;
+
+/**
+ * An interface for searching for a pattern in an aligment
+ */
+public interface FinderI
+{
+
+  /**
+   * Performs a find for the given search string (interpreted as a regular
+   * expression). Search may optionally be case-sensitive, and may optionally
+   * including match in sequence description (sequence id is always searched).
+   * If the viewport has an active selection, then the find is restricted to the
+   * selection region. Sequences matched by id or description can be retrieved
+   * by getIdMatches(), and matched residue patterns by getSearchResults().
+   * 
+   * @param theSearchString
+   * @param caseSensitive
+   * @param searchDescription
+   * @return
+   */
+  void findAll(String theSearchString, boolean caseSensitive,
+          boolean searchDescription);
+
+  /**
+   * Finds the next match for the given search string (interpreted as a regular
+   * expression), starting from the position after the last match found. Search
+   * may optionally be case-sensitive, and may optionally including match in
+   * sequence description (sequence id is always searched). If the viewport has
+   * an active selection, then the find is restricted to the selection region.
+   * Sequences matched by id or description can be retrieved by getIdMatches(),
+   * and matched residue patterns by getSearchResults().
+   * 
+   * @param theSearchString
+   * @param caseSensitive
+   * @param searchDescription
+   * @return
+   */
+  void findNext(String theSearchString, boolean caseSensitive,
+          boolean searchDescription);
+
+  /**
+   * Returns the (possibly empty) list of sequences matched on sequence name or
+   * description
+   * 
+   * @return
+   */
+  List<SequenceI> getIdMatches();
+
+  /**
+   * Answers the search results (possibly empty) from the last search
+   * 
+   * @return
+   */
+  SearchResultsI getSearchResults();
+
+}
\ No newline at end of file
index 83d8ade..e9081b0 100644 (file)
@@ -669,14 +669,9 @@ public class AlignmentPanel extends Panel
     }
     else
     {
-      int width = av.getAlignment().getWidth();
+      int width = av.getAlignment().getVisibleWidth();
       int height = av.getAlignment().getHeight();
 
-      if (av.hasHiddenColumns())
-      {
-        width = av.getAlignment().getHiddenColumns()
-                .absoluteToVisibleColumn(width);
-      }
       if (x < 0)
       {
         x = 0;
index d9eae11..5569ab0 100644 (file)
@@ -134,7 +134,8 @@ public class FeatureColourChooser extends Panel implements ActionListener,
     if (oldcs.isGraduatedColour())
     {
       threshline.value = oldcs.getThreshold();
-      cs = new FeatureColour((FeatureColour) oldcs, min, max);
+      cs = new FeatureColour(oldcs.getColour(), oldcs.getMinColour(),
+              oldcs.getMaxColour(), oldcs.getNoColour(), min, max);
     }
     else
     {
@@ -145,7 +146,8 @@ public class FeatureColourChooser extends Panel implements ActionListener,
         bl = oldcs.getColour();
       }
       // original colour becomes the maximum colour
-      cs = new FeatureColour(Color.white, bl, mm[0], mm[1]);
+      cs = new FeatureColour(bl, Color.white, bl, Color.white, mm[0],
+              mm[1]);
     }
     minColour.setBackground(cs.getMinColour());
     maxColour.setBackground(cs.getMaxColour());
@@ -411,8 +413,9 @@ public class FeatureColourChooser extends Panel implements ActionListener,
 
     slider.setEnabled(true);
     thresholdValue.setEnabled(true);
-    FeatureColour acg = new FeatureColour(minColour.getBackground(),
-            maxColour.getBackground(), min, max);
+    Color minc = minColour.getBackground();
+    Color maxc = maxColour.getBackground();
+    FeatureColour acg = new FeatureColour(maxc, minc, maxc, minc, min, max);
 
     acg.setColourByLabel(colourFromLabel.getState());
     maxColour.setEnabled(!colourFromLabel.getState());
@@ -448,11 +451,15 @@ public class FeatureColourChooser extends Panel implements ActionListener,
     {
       if (thresholdOption == AnnotationColourGradient.ABOVE_THRESHOLD)
       {
-        acg = new FeatureColour(acg, threshline.value, max);
+        acg = new FeatureColour(acg.getColour(), acg.getMinColour(),
+                acg.getMaxColour(), acg.getNoColour(), threshline.value,
+                max);
       }
       else
       {
-        acg = new FeatureColour(acg, min, threshline.value);
+        acg = new FeatureColour(acg.getColour(), acg.getMinColour(),
+                acg.getMaxColour(), acg.getNoColour(), min,
+                threshline.value);
       }
     }
 
index 675b862..2fc3441 100644 (file)
  */
 package jalview.appletgui;
 
+import jalview.api.AlignViewportI;
+import jalview.api.FinderI;
 import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.util.MessageManager;
-import jalview.viewmodel.AlignmentViewport;
 
 import java.awt.Button;
 import java.awt.Checkbox;
@@ -42,25 +43,39 @@ import java.awt.event.KeyEvent;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
-import java.util.Vector;
+import java.util.Map;
 
 public class Finder extends Panel implements ActionListener
 {
-  AlignmentViewport av;
+  private AlignViewportI av;
 
-  AlignmentPanel ap;
+  private AlignmentPanel ap;
 
-  Frame frame;
+  private TextField textfield = new TextField();
 
-  SearchResultsI searchResults;
+  private Button findAll = new Button();
 
-  int seqIndex = 0;
+  private Button findNext = new Button();
 
-  int resIndex = -1;
+  private Button createFeatures = new Button();
+
+  private Checkbox caseSensitive = new Checkbox();
+
+  private Checkbox searchDescription = new Checkbox();
+
+  private SearchResultsI searchResults;
+
+  /*
+   * Finder agent per viewport searched
+   */
+  Map<AlignViewportI, FinderI> finders;
 
   public Finder(final AlignmentPanel ap)
   {
+    finders = new HashMap<>();
+
     try
     {
       jbInit();
@@ -72,7 +87,7 @@ public class Finder extends Panel implements ActionListener
 
     this.av = ap.av;
     this.ap = ap;
-    frame = new Frame();
+    Frame frame = new Frame();
     frame.add(this);
     jalview.bin.JalviewLite.addFrame(frame,
             MessageManager.getString("action.find"), 340, 120);
@@ -103,20 +118,18 @@ public class Finder extends Panel implements ActionListener
 
     else if (evt.getSource() == findAll)
     {
-      resIndex = -1;
-      seqIndex = 0;
       doSearch(true);
     }
-    else if (evt.getSource() == createNewGroup)
+    else if (evt.getSource() == createFeatures)
     {
-      createNewGroup_actionPerformed();
+      createFeatures_actionPerformed();
     }
   }
 
-  public void createNewGroup_actionPerformed()
+  public void createFeatures_actionPerformed()
   {
-    List<SequenceI> seqs = new ArrayList<SequenceI>();
-    List<SequenceFeature> features = new ArrayList<SequenceFeature>();
+    List<SequenceI> seqs = new ArrayList<>();
+    List<SequenceFeature> features = new ArrayList<>();
     String searchString = textfield.getText().trim();
 
     for (SearchResultMatchI match : searchResults.getResults())
@@ -135,48 +148,48 @@ public class Finder extends Panel implements ActionListener
     }
   }
 
-  void doSearch(boolean findAll)
+  void doSearch(boolean doFindAll)
   {
     if (ap.av.applet.currentAlignFrame != null)
     {
       ap = ap.av.applet.currentAlignFrame.alignPanel;
       av = ap.av;
     }
-    createNewGroup.setEnabled(false);
-    jalview.analysis.Finder finder = new jalview.analysis.Finder(
-            av.getAlignment(), av.getSelectionGroup(), seqIndex, resIndex);
-    finder.setCaseSensitive(caseSensitive.getState());
-    finder.setIncludeDescription(searchDescription.getState());
-    finder.setFindAll(findAll);
+    createFeatures.setEnabled(false);
+    FinderI finder = finders.get(av);
+    if (finder == null)
+    {
+      /*
+       * first time we searched this viewport
+       */
+      finder = new jalview.analysis.Finder(av);
+      finders.put(av, finder);
+    }
 
     String searchString = textfield.getText();
-
-    finder.find(searchString);
-    seqIndex = finder.getSeqIndex();
-    resIndex = finder.getResIndex();
-    searchResults = finder.getSearchResults();
-    Vector<SequenceI> idMatch = finder.getIdMatch();
-    boolean haveResults = false;
-    // set or reset the GUI
-    if ((idMatch.size() > 0))
+    boolean isCaseSensitive = caseSensitive.getState();
+    boolean doSearchDescription = searchDescription.getState();
+    if (doFindAll)
     {
-      haveResults = true;
-      ap.idPanel.highlightSearchResults(idMatch);
+      finder.findAll(searchString, isCaseSensitive, doSearchDescription);
     }
     else
     {
-      ap.idPanel.highlightSearchResults(null);
+      finder.findNext(searchString, isCaseSensitive, doSearchDescription);
     }
 
-    if (searchResults.getSize() > 0)
-    {
-      haveResults = true;
-      createNewGroup.setEnabled(true);
+    searchResults = finder.getSearchResults();
+
+    List<SequenceI> idMatches = finder.getIdMatches();
+    ap.idPanel.highlightSearchResults(idMatches);
 
+    if (searchResults.isEmpty())
+    {
+      searchResults = null;
     }
     else
     {
-      searchResults = null;
+      createFeatures.setEnabled(true);
     }
 
     // if allResults is null, this effectively switches displaySearch flag in
@@ -184,20 +197,18 @@ public class Finder extends Panel implements ActionListener
     ap.highlightSearchResults(searchResults);
     // TODO: add enablers for 'SelectSequences' or 'SelectColumns' or
     // 'SelectRegion' selection
-    if (!haveResults)
+    if (idMatches.isEmpty() && searchResults == null)
     {
       ap.alignFrame.statusBar.setText(
               MessageManager.getString("label.finished_searching"));
-      resIndex = -1;
-      seqIndex = 0;
     }
     else
     {
-      if (findAll)
+      if (doFindAll)
       {
-        String message = (idMatch.size() > 0) ? "" + idMatch.size() + " IDs"
+        String message = (idMatches.size() > 0) ? "" + idMatches.size() + " IDs"
                 : "";
-        if (idMatch.size() > 0 && searchResults != null
+        if (idMatches.size() > 0 && searchResults != null
                 && searchResults.getSize() > 0)
         {
           message += " and ";
@@ -221,28 +232,10 @@ public class Finder extends Panel implements ActionListener
     }
   }
 
-  Label jLabel1 = new Label();
-
-  protected TextField textfield = new TextField();
-
-  protected Button findAll = new Button();
-
-  protected Button findNext = new Button();
-
-  Panel actionsPanel = new Panel();
-
-  GridLayout gridLayout1 = new GridLayout();
-
-  protected Button createNewGroup = new Button();
-
-  Checkbox caseSensitive = new Checkbox();
-
-  Checkbox searchDescription = new Checkbox();
-
   private void jbInit() throws Exception
   {
+    Label jLabel1 = new Label(MessageManager.getString("action.find"));
     jLabel1.setFont(new java.awt.Font("Verdana", 0, 12));
-    jLabel1.setText(MessageManager.getString("action.find"));
     jLabel1.setBounds(new Rectangle(3, 30, 34, 15));
     this.setLayout(null);
     textfield.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
@@ -253,7 +246,7 @@ public class Finder extends Panel implements ActionListener
       @Override
       public void keyTyped(KeyEvent e)
       {
-        textfield_keyTyped(e);
+        textfield_keyTyped();
       }
     });
     textfield.addActionListener(this);
@@ -264,15 +257,18 @@ public class Finder extends Panel implements ActionListener
     findNext.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
     findNext.setLabel(MessageManager.getString("action.find_next"));
     findNext.addActionListener(this);
+
+    Panel actionsPanel = new Panel();
     actionsPanel.setBounds(new Rectangle(195, 5, 141, 64));
+    GridLayout gridLayout1 = new GridLayout();
     actionsPanel.setLayout(gridLayout1);
     gridLayout1.setHgap(0);
     gridLayout1.setRows(3);
     gridLayout1.setVgap(2);
-    createNewGroup.setEnabled(false);
-    createNewGroup.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    createNewGroup.setLabel(MessageManager.getString("label.new_feature"));
-    createNewGroup.addActionListener(this);
+    createFeatures.setEnabled(false);
+    createFeatures.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
+    createFeatures.setLabel(MessageManager.getString("label.new_feature"));
+    createFeatures.addActionListener(this);
     caseSensitive.setLabel(MessageManager.getString("label.match_case"));
     caseSensitive.setBounds(new Rectangle(30, 39, 126, 23));
 
@@ -281,7 +277,7 @@ public class Finder extends Panel implements ActionListener
     searchDescription.setBounds(new Rectangle(30, 59, 170, 23));
     actionsPanel.add(findNext, null);
     actionsPanel.add(findAll, null);
-    actionsPanel.add(createNewGroup, null);
+    actionsPanel.add(createFeatures, null);
     this.add(caseSensitive);
     this.add(textfield, null);
     this.add(jLabel1, null);
@@ -289,7 +285,7 @@ public class Finder extends Panel implements ActionListener
     this.add(searchDescription);
   }
 
-  void textfield_keyTyped(KeyEvent e)
+  void textfield_keyTyped()
   {
     findNext.setEnabled(true);
   }
index 296f898..ef80616 100755 (executable)
@@ -280,15 +280,9 @@ public class IdCanvas extends Panel implements ViewportListenerI
   protected void drawIdsWrapped(int starty, final boolean doHiddenCheck,
           boolean hiddenRows)
   {
-    int maxwidth = av.getAlignment().getWidth();
+    int maxwidth = av.getAlignment().getVisibleWidth();
     int alheight = av.getAlignment().getHeight();
 
-    if (av.hasHiddenColumns())
-    {
-      maxwidth = av.getAlignment().getHiddenColumns()
-              .absoluteToVisibleColumn(maxwidth) - 1;
-    }
-
     int annotationHeight = 0;
     AnnotationLabels labels = null;
 
index 15e269c..af1c47b 100755 (executable)
@@ -395,7 +395,7 @@ public class IdPanel extends Panel
   {
     idCanvas.setHighlighted(list);
 
-    if (list == null)
+    if (list == null || list.isEmpty())
     {
       return;
     }
index 5081509..96138bf 100755 (executable)
@@ -126,13 +126,14 @@ public class OverviewPanel extends Panel implements Runnable,
   {
     if (od.isPositionInBox(evt.getX(), evt.getY()))
     {
-      // display drag cursor at mouse position
-      setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+      this.getParent()
+              .setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
     }
     else
     {
-      // reset cursor
-      setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+      this.getParent()
+              .setCursor(
+                      Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
     }
   }
 
@@ -162,6 +163,8 @@ public class OverviewPanel extends Panel implements Runnable,
         od.updateViewportFromMouse(evt.getX(), evt.getY(),
                 av.getAlignment().getHiddenSequences(),
                 av.getAlignment().getHiddenColumns());
+        getParent()
+                .setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
       }
       else
       {
index 35d73de..96eb6b9 100755 (executable)
@@ -136,13 +136,6 @@ public class SeqCanvas extends Panel implements ViewportListenerI
               .visibleToAbsoluteColumn(endx);
     }
 
-    int maxwidth = av.getAlignment().getWidth();
-    if (av.hasHiddenColumns())
-    {
-      maxwidth = av.getAlignment().getHiddenColumns()
-              .absoluteToVisibleColumn(maxwidth) - 1;
-    }
-
     // WEST SCALE
     for (int i = 0; i < av.getAlignment().getHeight(); i++)
     {
@@ -450,13 +443,7 @@ public class SeqCanvas extends Panel implements ViewportListenerI
     int endx;
     int ypos = hgap;
   
-    int maxwidth = av.getAlignment().getWidth();
-  
-    if (av.hasHiddenColumns())
-    {
-      maxwidth = av.getAlignment().getHiddenColumns()
-              .absoluteToVisibleColumn(maxwidth);
-    }
+    int maxwidth = av.getAlignment().getVisibleWidth();
   
     while ((ypos <= canvasHeight) && (startRes < maxwidth))
     {
@@ -565,7 +552,7 @@ public class SeqCanvas extends Panel implements ViewportListenerI
       int blockEnd;
 
       HiddenColumns hidden = av.getAlignment().getHiddenColumns();
-      VisibleContigsIterator regions = (VisibleContigsIterator) hidden
+      VisibleContigsIterator regions = hidden
               .getVisContigsIterator(startRes, endRes + 1, true);
 
       while (regions.hasNext())
index aa156bf..19aa800 100755 (executable)
@@ -114,7 +114,6 @@ import org.apache.log4j.SimpleLayout;
  * service</li>
  * <li>USAGESTATS (false - user prompted) Enable google analytics tracker for
  * collecting usage statistics</li>
- * <li>DAS_LOCAL_SOURCE list of local das sources</li>
  * <li>SHOW_OVERVIEW boolean for overview window display</li>
  * <li>ANTI_ALIAS boolean for smooth fonts</li>
  * <li>RIGHT_ALIGN_IDS boolean</li>
@@ -134,9 +133,7 @@ import org.apache.log4j.SimpleLayout;
  * sequence id (must be in SEQUENCE_LINKS or STORED_LINKS)
  * <li>GROUP_LINKS list of name|URL[|&lt;separator&gt;] tuples - see
  * jalview.utils.GroupURLLink for more info</li>
- * <li>DAS_REGISTRY_URL the registry to query</li>
  * <li>DEFAULT_BROWSER for unix</li>
- * <li>DAS_ACTIVE_SOURCE list of active sources</li>
  * <li>SHOW_MEMUSAGE boolean show memory usage and warning indicator on desktop
  * (false)</li>
  * <li>VERSION_CHECK (true) check for the latest release version from
@@ -226,12 +223,6 @@ public class Cache
    */
   public static final String JALVIEWLOGLEVEL = "logs.Jalview.level";
 
-  public static final String DAS_LOCAL_SOURCE = "DAS_LOCAL_SOURCE";
-
-  public static final String DAS_REGISTRY_URL = "DAS_REGISTRY_URL";
-
-  public static final String DAS_ACTIVE_SOURCE = "DAS_ACTIVE_SOURCE";
-
   /**
    * Sifts settings
    */
index 3270144..c7738da 100755 (executable)
@@ -391,10 +391,7 @@ public class Jalview
     FileFormatI format = null;
     DataSourceType protocol = null;
     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
     // completed one way or another
     // extract groovy argument and execute if necessary
@@ -625,27 +622,6 @@ public class Jalview
         // TODO - load PDB structure(s) to alignment JAL-629
         // (associate with identical sequence in alignment, or a specified
         // sequence)
-
-        getFeatures = checkDasArguments(aparser);
-        if (af != null && getFeatures != null)
-        {
-          FeatureFetcher ff = startFeatureFetching(getFeatures);
-          if (ff != null)
-          {
-            while (!ff.allFinished() || af.operationInProgress())
-            {
-              // wait around until fetching is finished.
-              try
-              {
-                Thread.sleep(100);
-              } catch (Exception e)
-              {
-
-              }
-            }
-          }
-          getFeatures = null; // have retrieved features - forget them now.
-        }
         if (groovyscript != null)
         {
           // Execute the groovy script after we've done all the rendering stuff
@@ -787,20 +763,9 @@ public class Jalview
 
       startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
               format);
-      getFeatures = checkDasArguments(aparser);
       // extract groovy arguments before anything else.
     }
-    // If the user has specified features to be retrieved,
-    // or a groovy script to be executed, do them if they
-    // haven't been done already
-    // fetch features for the default alignment
-    if (getFeatures != null)
-    {
-      if (startUpAlframe != null)
-      {
-        startFeatureFetching(getFeatures);
-      }
-    }
+
     // Once all other stuff is done, execute any groovy scripts (in order)
     if (groovyscript != null)
     {
@@ -863,9 +828,6 @@ public class Jalview
                     // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
                     // passed in correctly)"
                     + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
-                    + "-dasserver nickname=URL\tAdd and enable a das server with given nickname\n\t\t\t(alphanumeric or underscores only) for retrieval of features for all alignments.\n"
-                    + "\t\t\tSources that also support the sequence command may be specified by prepending the URL with sequence:\n"
-                    + "\t\t\t e.g. sequence:http://localdas.somewhere.org/das/source)\n"
                     + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
                     // +
                     // "-vdoc vamsas-document\tImport vamsas document into new
@@ -1024,94 +986,6 @@ public class Jalview
     }
   }
 
-  /**
-   * Check commandline for any das server definitions or any fetchfrom switches
-   * 
-   * @return vector of DAS source nicknames to retrieve from
-   */
-  private static Vector<String> checkDasArguments(ArgsParser aparser)
-  {
-    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;
-      int pos = data.indexOf('=');
-      // determine capabilities
-      if (pos > 0)
-      {
-        nickname = data.substring(0, pos);
-      }
-      url = data.substring(pos + 1);
-      if (url != null && (url.startsWith("http:")
-              || url.startsWith("sequence:http:")))
-      {
-        if (nickname == null)
-        {
-          nickname = url;
-        }
-        if (locsources == null)
-        {
-          locsources = "";
-        }
-        else
-        {
-          locsources += "\t";
-        }
-        locsources = locsources + nickname + "|" + url;
-        System.err.println(
-                "NOTE! dasserver parameter not yet really supported (got args of "
-                        + nickname + "|" + url);
-        if (source == null)
-        {
-          source = new Vector<>();
-        }
-        source.addElement(nickname);
-      }
-      System.out.println(
-              "CMD [-dasserver " + data + "] executed successfully!");
-    } // loop until no more server entries are found.
-    if (locsources != null && locsources.indexOf('|') > -1)
-    {
-      Cache.log.debug("Setting local source list in properties file to:\n"
-              + locsources);
-      Cache.setProperty(Cache.DAS_LOCAL_SOURCE, locsources);
-    }
-    while ((data = aparser.getValue("fetchfrom", true)) != null)
-    {
-      System.out.println("adding source '" + data + "'");
-      if (source == null)
-      {
-        source = new Vector<>();
-      }
-      source.addElement(data);
-    }
-    return source;
-  }
-
-  /**
-   * start a feature fetcher for every alignment frame
-   * 
-   * @param dasSources
-   */
-  private FeatureFetcher startFeatureFetching(
-          final Vector<String> dasSources)
-  {
-    FeatureFetcher ff = new FeatureFetcher();
-    AlignFrame afs[] = Desktop.getAlignFrames();
-    if (afs == null || afs.length == 0)
-    {
-      return null;
-    }
-    for (int i = 0; i < afs.length; i++)
-    {
-      ff.addFetcher(afs[i], dasSources);
-    }
-    return ff;
-  }
-
   public static boolean isHeadlessMode()
   {
     String isheadless = System.getProperty("java.awt.headless");
index 3e0856a..ac00fa2 100755 (executable)
@@ -712,39 +712,21 @@ public class Alignment implements AlignmentI
   
     for (int i = 0; i < sequences.size(); i++)
     {
-      if (getSequenceAt(i).getLength() > maxLength)
-      {
-        maxLength = getSequenceAt(i).getLength();
-      }
+      maxLength = Math.max(maxLength, getSequenceAt(i).getLength());
     }
-  
     return maxLength;
   }
-  /*
+
   @Override
-  public int getWidth()
+  public int getVisibleWidth()
   {
-    final Wrapper temp = new Wrapper();
-  
-    forEachSequence(new Consumer<SequenceI>()
+    int w = getWidth();
+    if (hiddenCols != null)
     {
-      @Override
-      public void accept(SequenceI s)
-      {
-        if (s.getLength() > temp.inner)
-        {
-          temp.inner = s.getLength();
-        }
-      }
-    }, 0, sequences.size() - 1);
-  
-    return temp.inner;
+      w -= hiddenCols.getSize();
+    }
+    return w;
   }
-  
-  public static class Wrapper
-  {
-    public int inner;
-  }*/
 
   /**
    * DOCUMENT ME!
index 9c73873..93a2456 100755 (executable)
@@ -48,15 +48,29 @@ public interface AlignmentI extends AnnotatedCollectionI
 
   /**
    * 
-   * Calculates the maximum width of the alignment, including gaps.
+   * Answers the width of the alignment, including gaps, that is, the length of
+   * the longest sequence, or -1 if there are no sequences. Avoid calling this
+   * method repeatedly where possible, as it has to perform a calculation. Note
+   * that this width includes any hidden columns.
    * 
-   * @return Greatest sequence length within alignment, or -1 if no sequences
-   *         present
+   * @return
+   * @see AlignmentI#getVisibleWidth()
    */
   @Override
   int getWidth();
 
   /**
+   * 
+   * Answers the visible width of the alignment, including gaps, that is, the
+   * length of the longest sequence, excluding any hidden columns. Answers -1 if
+   * there are no sequences. Avoid calling this method repeatedly where
+   * possible, as it has to perform a calculation.
+   * 
+   * @return
+   */
+  int getVisibleWidth();
+
+  /**
    * Calculates if this set of sequences (visible and invisible) are all the
    * same length
    * 
index 6d620b4..3ccaab8 100644 (file)
@@ -27,6 +27,7 @@ import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.Collections;
 import java.util.List;
+import java.util.regex.PatternSyntaxException;
 
 /**
  * Data class holding the selected columns and hidden column ranges for a view.
@@ -59,7 +60,7 @@ public class ColumnSelection
      */
     IntList()
     {
-      order = new ArrayList<Integer>();
+      order = new ArrayList<>();
       _uorder = Collections.unmodifiableList(order);
       selected = new BitSet();
     }
@@ -230,7 +231,7 @@ public class ColumnSelection
      */
     List<int[]> getRanges()
     {
-      List<int[]> rlist = new ArrayList<int[]>();
+      List<int[]> rlist = new ArrayList<>();
       if (selected.isEmpty())
       {
         return rlist;
@@ -263,7 +264,7 @@ public class ColumnSelection
     }
   }
 
-  IntList selection = new IntList();
+  private IntList selection = new IntList();
 
   /**
    * Add a column to the selection
@@ -533,92 +534,109 @@ public class ColumnSelection
     return (selection != null && selection.size() > 0);
   }
 
-  public boolean filterAnnotations(Annotation[] annotations,
+  /**
+   * Selects columns where the given annotation matches the provided filter
+   * condition(s). Any existing column selections are first cleared. Answers the
+   * number of columns added.
+   * 
+   * @param annotations
+   * @param filterParams
+   * @return
+   */
+  public int filterAnnotations(Annotation[] annotations,
           AnnotationFilterParameter filterParams)
   {
     // JBPNote - this method needs to be refactored to become independent of
     // viewmodel package
     this.clear();
-    int count = 0;
+    int addedCount = 0;
+    int column = 0;
     do
     {
-      if (annotations[count] != null)
+      Annotation ann = annotations[column];
+      if (ann != null)
       {
+        boolean matched = false;
 
-        boolean itemMatched = false;
-
+        /*
+         * filter may have multiple conditions - 
+         * these are or'd until a match is found
+         */
         if (filterParams
                 .getThresholdType() == AnnotationFilterParameter.ThresholdType.ABOVE_THRESHOLD
-                && annotations[count].value >= filterParams
-                        .getThresholdValue())
+                && ann.value > filterParams.getThresholdValue())
         {
-          itemMatched = true;
+          matched = true;
         }
-        if (filterParams
+
+        if (!matched && filterParams
                 .getThresholdType() == AnnotationFilterParameter.ThresholdType.BELOW_THRESHOLD
-                && annotations[count].value <= filterParams
-                        .getThresholdValue())
+                && ann.value < filterParams.getThresholdValue())
         {
-          itemMatched = true;
+          matched = true;
         }
 
-        if (filterParams.isFilterAlphaHelix()
-                && annotations[count].secondaryStructure == 'H')
+        if (!matched && filterParams.isFilterAlphaHelix()
+                && ann.secondaryStructure == 'H')
         {
-          itemMatched = true;
+          matched = true;
         }
 
-        if (filterParams.isFilterBetaSheet()
-                && annotations[count].secondaryStructure == 'E')
+        if (!matched && filterParams.isFilterBetaSheet()
+                && ann.secondaryStructure == 'E')
         {
-          itemMatched = true;
+          matched = true;
         }
 
-        if (filterParams.isFilterTurn()
-                && annotations[count].secondaryStructure == 'S')
+        if (!matched && filterParams.isFilterTurn()
+                && ann.secondaryStructure == 'S')
         {
-          itemMatched = true;
+          matched = true;
         }
 
         String regexSearchString = filterParams.getRegexString();
-        if (regexSearchString != null
-                && !filterParams.getRegexSearchFields().isEmpty())
+        if (!matched && regexSearchString != null)
         {
           List<SearchableAnnotationField> fields = filterParams
                   .getRegexSearchFields();
-          try
+          for (SearchableAnnotationField field : fields)
           {
-            if (fields.contains(SearchableAnnotationField.DISPLAY_STRING)
-                    && annotations[count].displayCharacter
-                            .matches(regexSearchString))
+            String compareTo = field == SearchableAnnotationField.DISPLAY_STRING
+                    ? ann.displayCharacter // match 'Label'
+                    : ann.description; // and/or 'Description'
+            if (compareTo != null)
             {
-              itemMatched = true;
-            }
-          } catch (java.util.regex.PatternSyntaxException pse)
-          {
-            if (annotations[count].displayCharacter
-                    .equals(regexSearchString))
-            {
-              itemMatched = true;
+              try
+              {
+                if (compareTo.matches(regexSearchString))
+                {
+                  matched = true;
+                }
+              } catch (PatternSyntaxException pse)
+              {
+                if (compareTo.equals(regexSearchString))
+                {
+                  matched = true;
+                }
+              }
+              if (matched)
+              {
+                break;
+              }
             }
           }
-          if (fields.contains(SearchableAnnotationField.DESCRIPTION)
-                  && annotations[count].description != null
-                  && annotations[count].description
-                          .matches(regexSearchString))
-          {
-            itemMatched = true;
-          }
         }
 
-        if (itemMatched)
+        if (matched)
         {
-          this.addElement(count);
+          this.addElement(column);
+          addedCount++;
         }
       }
-      count++;
-    } while (count < annotations.length);
-    return false;
+      column++;
+    } while (column < annotations.length);
+
+    return addedCount;
   }
 
   /**
index a47ca8b..661ad6c 100644 (file)
@@ -47,4 +47,14 @@ public interface SearchResultMatchI
    */
   int getEnd();
 
+  /**
+   * Answers true if this match is for the given sequence and includes (matches
+   * or encloses) the given start-end range
+   * 
+   * @param seq
+   * @param start
+   * @param end
+   * @return
+   */
+  boolean contains(SequenceI seq, int start, int end);
 }
\ No newline at end of file
index d1e3fcc..31736e5 100755 (executable)
@@ -91,27 +91,18 @@ public class SearchResults implements SearchResultsI
       }
     }
 
-    /* (non-Javadoc)
-     * @see jalview.datamodel.SearchResultMatchI#getSequence()
-     */
     @Override
     public SequenceI getSequence()
     {
       return sequence;
     }
 
-    /* (non-Javadoc)
-     * @see jalview.datamodel.SearchResultMatchI#getStart()
-     */
     @Override
     public int getStart()
     {
       return start;
     }
 
-    /* (non-Javadoc)
-     * @see jalview.datamodel.SearchResultMatchI#getEnd()
-     */
     @Override
     public int getEnd()
     {
@@ -162,22 +153,25 @@ public class SearchResults implements SearchResultsI
       return (sequence == m.getSequence() && start == m.getStart()
               && end == m.getEnd());
     }
+
+    @Override
+    public boolean contains(SequenceI seq, int from, int to)
+    {
+      return (sequence == seq && start <= from && end >= to);
+    }
   }
 
-  /* (non-Javadoc)
-   * @see jalview.datamodel.SearchResultsI#addResult(jalview.datamodel.SequenceI, int, int)
-   */
   @Override
   public SearchResultMatchI addResult(SequenceI seq, int start, int end)
   {
     Match m = new Match(seq, start, end);
-    matches.add(m);
+    if (!matches.contains(m))
+    {
+      matches.add(m);
+    }
     return m;
   }
 
-  /* (non-Javadoc)
-   * @see jalview.datamodel.SearchResultsI#involvesSequence(jalview.datamodel.SequenceI)
-   */
   @Override
   public boolean involvesSequence(SequenceI sequence)
   {
@@ -193,9 +187,6 @@ public class SearchResults implements SearchResultsI
     return false;
   }
 
-  /* (non-Javadoc)
-   * @see jalview.datamodel.SearchResultsI#getResults(jalview.datamodel.SequenceI, int, int)
-   */
   @Override
   public int[] getResults(SequenceI sequence, int start, int end)
   {
@@ -290,27 +281,18 @@ public class SearchResults implements SearchResultsI
     return count;
   }
 
-  /* (non-Javadoc)
-   * @see jalview.datamodel.SearchResultsI#getSize()
-   */
   @Override
   public int getSize()
   {
     return matches.size();
   }
 
-  /* (non-Javadoc)
-   * @see jalview.datamodel.SearchResultsI#isEmpty()
-   */
   @Override
   public boolean isEmpty()
   {
     return matches.isEmpty();
   }
 
-  /* (non-Javadoc)
-   * @see jalview.datamodel.SearchResultsI#getResults()
-   */
   @Override
   public List<SearchResultMatchI> getResults()
   {
index c3dc0e8..3c3ad4e 100644 (file)
@@ -31,14 +31,11 @@ public interface SearchResultsI
 {
 
   /**
-   * Adds one region to the results
+   * Adds one region to the results (unless already added, to avoid duplicates)
    * 
    * @param seq
-   *          Sequence
    * @param start
-   *          int
    * @param end
-   *          int
    * @return
    */
   SearchResultMatchI addResult(SequenceI seq, int start, int end);
index 84643d1..15b61d2 100755 (executable)
@@ -112,9 +112,11 @@ public interface SequenceI extends ASequenceI
    * get a range on the sequence as a string
    * 
    * @param start
-   *          position relative to start of sequence including gaps (from 0)
+   *          (inclusive) position relative to start of sequence including gaps
+   *          (from 0)
    * @param end
-   *          position relative to start of sequence including gaps (from 0)
+   *          (exclusive) position relative to start of sequence including gaps
+   *          (from 0)
    * 
    * @return String containing all gap and symbols in specified range
    */
index 86710e1..232561c 100644 (file)
@@ -34,6 +34,7 @@ import jalview.util.MessageManager;
 import java.awt.BorderLayout;
 import java.awt.CardLayout;
 import java.awt.Dimension;
+import java.awt.Font;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.FocusAdapter;
@@ -86,6 +87,8 @@ import javax.swing.text.JTextComponent;
 @SuppressWarnings("serial")
 public abstract class GFTSPanel extends JPanel implements GFTSPanelI
 {
+  private static final Font VERDANA_12 = new Font("Verdana", 0, 12);
+
   protected JInternalFrame mainFrame = new JInternalFrame(
           getFTSFrameTitle());
 
@@ -300,11 +303,11 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     Integer height = getTempUserPrefs().get("FTSPanel.height") == null ? 400
             : getTempUserPrefs().get("FTSPanel.height");
     lbl_warning.setVisible(false);
-    lbl_warning.setFont(new java.awt.Font("Verdana", 0, 12));
+    lbl_warning.setFont(VERDANA_12);
     lbl_loading.setVisible(false);
-    lbl_loading.setFont(new java.awt.Font("Verdana", 0, 12));
+    lbl_loading.setFont(VERDANA_12);
     lbl_blank.setVisible(true);
-    lbl_blank.setFont(new java.awt.Font("Verdana", 0, 12));
+    lbl_blank.setFont(VERDANA_12);
 
     tbl_summary.setAutoCreateRowSorter(true);
     tbl_summary.getTableHeader().setReorderingAllowed(false);
@@ -357,6 +360,19 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
       }
     });
 
+    JButton txt_help = new JButton("?");
+    txt_help.setFont(VERDANA_12);
+    txt_help.setPreferredSize(new Dimension(15, 15));
+    txt_help.setToolTipText(MessageManager.getString("action.help"));
+    txt_help.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        showHelp();
+      }
+    });
+
     btn_autosearch.setText(MessageManager.getString("option.autosearch"));
     btn_autosearch.setToolTipText(
             MessageManager.getString("option.enable_disable_autosearch"));
@@ -371,7 +387,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
                 Boolean.toString(btn_autosearch.isSelected()));
       }
     });
-    btn_back.setFont(new java.awt.Font("Verdana", 0, 12));
+    btn_back.setFont(VERDANA_12);
     btn_back.setText(MessageManager.getString("action.back"));
     btn_back.addActionListener(new java.awt.event.ActionListener()
     {
@@ -394,7 +410,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     });
 
     btn_ok.setEnabled(false);
-    btn_ok.setFont(new java.awt.Font("Verdana", 0, 12));
+    btn_ok.setFont(VERDANA_12);
     btn_ok.setText(MessageManager.getString("action.ok"));
     btn_ok.addActionListener(new java.awt.event.ActionListener()
     {
@@ -418,7 +434,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     btn_next_page.setEnabled(false);
     btn_next_page.setToolTipText(
             MessageManager.getString("label.next_page_tooltip"));
-    btn_next_page.setFont(new java.awt.Font("Verdana", 0, 12));
+    btn_next_page.setFont(VERDANA_12);
     btn_next_page.setText(MessageManager.getString("action.next_page"));
     btn_next_page.addActionListener(new java.awt.event.ActionListener()
     {
@@ -443,7 +459,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     btn_prev_page.setEnabled(false);
     btn_prev_page.setToolTipText(
             MessageManager.getString("label.prev_page_tooltip"));
-    btn_prev_page.setFont(new java.awt.Font("Verdana", 0, 12));
+    btn_prev_page.setFont(VERDANA_12);
     btn_prev_page.setText(MessageManager.getString("action.prev_page"));
     btn_prev_page.addActionListener(new java.awt.event.ActionListener()
     {
@@ -476,7 +492,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
       btn_next_page.setVisible(false);
     }
 
-    btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12));
+    btn_cancel.setFont(VERDANA_12);
     btn_cancel.setText(MessageManager.getString("action.cancel"));
     btn_cancel.addActionListener(new java.awt.event.ActionListener()
     {
@@ -499,7 +515,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     });
     scrl_searchResult.setPreferredSize(new Dimension(width, height));
 
-    cmb_searchTarget.setFont(new java.awt.Font("Verdana", 0, 12));
+    cmb_searchTarget.setFont(VERDANA_12);
     cmb_searchTarget.addItemListener(new ItemListener()
     {
       @Override
@@ -532,7 +548,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
       }
     });
 
-    txt_search.setFont(new java.awt.Font("Verdana", 0, 12));
+    txt_search.setFont(VERDANA_12);
 
     txt_search.getEditor().getEditorComponent()
             .addKeyListener(new KeyAdapter()
@@ -666,6 +682,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     pnl_results.add(tabbedPane);
     pnl_inputs.add(cmb_searchTarget);
     pnl_inputs.add(txt_search);
+    pnl_inputs.add(txt_help);
     pnl_inputs.add(btn_autosearch);
     pnl_inputs.add(lbl_loading);
     pnl_inputs.add(lbl_warning);
@@ -710,6 +727,8 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     Desktop.addInternalFrame(mainFrame, getFTSFrameTitle(), width, height);
   }
 
+  abstract protected void showHelp();
+
   protected void closeAction()
   {
     getTempUserPrefs().put("FTSPanel.width", this.getWidth());
index 053d91b..da164f0 100644 (file)
@@ -26,6 +26,8 @@ import jalview.fts.api.FTSRestClientI;
 import jalview.fts.core.FTSRestRequest;
 import jalview.fts.core.FTSRestResponse;
 import jalview.fts.core.GFTSPanel;
+import jalview.gui.Help;
+import jalview.gui.Help.HelpId;
 import jalview.gui.SequenceFetcher;
 import jalview.util.MessageManager;
 
@@ -33,13 +35,15 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 
+import javax.help.HelpSetException;
+
 @SuppressWarnings("serial")
 public class PDBFTSPanel extends GFTSPanel
 {
   private static String defaultFTSFrameTitle = MessageManager
           .getString("label.pdb_sequence_fetcher");
 
-  private static Map<String, Integer> tempUserPrefs = new HashMap<String, Integer>();
+  private static Map<String, Integer> tempUserPrefs = new HashMap<>();
 
   private static final String PDB_FTS_CACHE_KEY = "CACHE.PDB_FTS";
 
@@ -190,7 +194,7 @@ public class PDBFTSPanel extends GFTSPanel
     // mainFrame.dispose();
     disableActionButtons();
     StringBuilder selectedIds = new StringBuilder();
-    HashSet<String> selectedIdsSet = new HashSet<String>();
+    HashSet<String> selectedIdsSet = new HashSet<>();
     int primaryKeyColIndex = 0;
     try
     {
@@ -288,4 +292,16 @@ public class PDBFTSPanel extends GFTSPanel
   {
     return PDB_AUTOSEARCH;
   }
+
+  @Override
+  protected void showHelp()
+  {
+    try
+    {
+      Help.showHelpWindow(HelpId.PdbFts);
+    } catch (HelpSetException e1)
+    {
+      e1.printStackTrace();
+    }
+ }
 }
\ No newline at end of file
index df54dea..977abfa 100644 (file)
@@ -26,6 +26,8 @@ import jalview.fts.api.FTSRestClientI;
 import jalview.fts.core.FTSRestRequest;
 import jalview.fts.core.FTSRestResponse;
 import jalview.fts.core.GFTSPanel;
+import jalview.gui.Help;
+import jalview.gui.Help.HelpId;
 import jalview.gui.SequenceFetcher;
 import jalview.util.MessageManager;
 
@@ -33,6 +35,8 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 
+import javax.help.HelpSetException;
+
 @SuppressWarnings("serial")
 public class UniprotFTSPanel extends GFTSPanel
 {
@@ -245,4 +249,16 @@ public class UniprotFTSPanel extends GFTSPanel
   {
     return UNIPROT_AUTOSEARCH;
   }
+
+  @Override
+  protected void showHelp()
+  {
+    try
+    {
+      Help.showHelpWindow(HelpId.UniprotFts);
+    } catch (HelpSetException e1)
+    {
+      e1.printStackTrace();
+    }
+  }
 }
index 606e2e7..25c6dd4 100644 (file)
@@ -24,6 +24,7 @@ import jalview.analysis.AlignmentSorter;
 import jalview.analysis.AlignmentUtils;
 import jalview.analysis.CrossRef;
 import jalview.analysis.Dna;
+import jalview.analysis.GeneticCodeI;
 import jalview.analysis.ParseProperties;
 import jalview.analysis.SequenceIdMatcher;
 import jalview.api.AlignExportSettingI;
@@ -3049,6 +3050,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.expandColSelection(sg, false);
     viewport.hideAllSelectedSeqs();
     viewport.hideSelectedColumns();
+    alignPanel.updateLayout();
     alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
@@ -3073,6 +3075,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void hideSelColumns_actionPerformed(ActionEvent e)
   {
     viewport.hideSelectedColumns();
+    alignPanel.updateLayout();
     alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
@@ -4274,14 +4277,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * frame's DNA sequences to their aligned protein (amino acid) equivalents.
    */
   @Override
-  public void showTranslation_actionPerformed(ActionEvent e)
+  public void showTranslation_actionPerformed(GeneticCodeI codeTable)
   {
     AlignmentI al = null;
     try
     {
       Dna dna = new Dna(viewport, viewport.getViewAsVisibleContigs(true));
 
-      al = dna.translateCdna();
+      al = dna.translateCdna(codeTable);
     } catch (Exception ex)
     {
       jalview.bin.Cache.log.error(
@@ -4310,7 +4313,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       af.setFileFormat(this.currentFileFormat);
       final String newTitle = MessageManager
               .formatMessage("label.translation_of_params", new Object[]
-              { this.getTitle() });
+              { this.getTitle(), codeTable.getId() });
       af.setTitle(newTitle);
       if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true))
       {
index 82e2113..51e703d 100644 (file)
@@ -637,16 +637,9 @@ public class AlignmentPanel extends GAlignmentPanel implements
     }
     else
     {
-      int width = av.getAlignment().getWidth();
+      int width = av.getAlignment().getVisibleWidth();
       int height = av.getAlignment().getHeight();
 
-      if (av.hasHiddenColumns())
-      {
-        // reset the width to exclude hidden columns
-        width = av.getAlignment().getHiddenColumns()
-                .absoluteToVisibleColumn(width);
-      }
-
       hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
       vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight();
 
@@ -958,8 +951,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
     final int totalSeq = (pageHeight - scaleHeight) / charHeight - 1;
 
-    final int alignmentWidth = av.getAlignment().getWidth();
-    final int pagesWide = (alignmentWidth / totalRes) + 1;
+    final int alignmentWidth = av.getAlignment().getVisibleWidth();
+    int pagesWide = (alignmentWidth / totalRes) + 1;
 
     final int startRes = (pageIndex % pagesWide) * totalRes;
     final int endRes = Math.min(startRes + totalRes - 1,
@@ -1076,12 +1069,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
     int idWidth = getVisibleIdWidth(false);
 
-    int maxwidth = av.getAlignment().getWidth();
-    if (av.hasHiddenColumns())
-    {
-      maxwidth = av.getAlignment().getHiddenColumns()
-              .absoluteToVisibleColumn(maxwidth) - 1;
-    }
+    int maxwidth = av.getAlignment().getVisibleWidth();
 
     int resWidth = getSeqPanel().seqCanvas
             .getWrappedCanvasWidth(pageWidth - idWidth);
@@ -1243,12 +1231,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
   public AlignmentDimension getAlignmentDimension()
   {
-    int maxwidth = av.getAlignment().getWidth();
-    if (av.hasHiddenColumns())
-    {
-      maxwidth = av.getAlignment().getHiddenColumns()
-              .absoluteToVisibleColumn(maxwidth);
-    }
+    int maxwidth = av.getAlignment().getVisibleWidth();
 
     int height = ((av.getAlignment().getHeight() + 1) * av.getCharHeight())
             + getScalePanel().getHeight();
index 6924b63..5adecad 100644 (file)
@@ -33,6 +33,8 @@ import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
 import java.awt.event.KeyEvent;
@@ -744,6 +746,15 @@ public class AnnotationColumnChooser extends AnnotationRowFilter
                   }
                 }
               });
+      searchBox.getEditor().getEditorComponent()
+              .addFocusListener(new FocusAdapter()
+      {
+        @Override
+        public void focusLost(FocusEvent e)
+        {
+          searchStringAction();
+        }
+      });
 
       JvSwingUtils.jvInitComponent(displayName, "label.label");
       displayName.addActionListener(new ActionListener()
@@ -761,7 +772,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter
         @Override
         public void actionPerformed(ActionEvent actionEvent)
         {
-          discriptionCheckboxAction();
+          descriptionCheckboxAction();
         }
       });
 
@@ -777,7 +788,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter
       aColChooser.updateView();
     }
 
-    public void discriptionCheckboxAction()
+    public void descriptionCheckboxAction()
     {
       aColChooser.setCurrentSearchPanel(this);
       aColChooser.updateView();
index ab86707..16db94c 100755 (executable)
@@ -77,6 +77,11 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         MouseListener, MouseWheelListener, MouseMotionListener,
         ActionListener, AdjustmentListener, Scrollable, ViewportListenerI
 {
+  enum DragMode
+  {
+    Select, Resize, Undefined
+  };
+
   String HELIX = MessageManager.getString("label.helix");
 
   String SHEET = MessageManager.getString("label.sheet");
@@ -120,11 +125,11 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
   // Used For mouse Dragging and resizing graphs
   int graphStretch = -1;
 
-  int graphStretchY = -1;
+  int mouseDragLastX = -1;
 
-  int min; // used by mouseDragged to see if user
+  int mouseDragLastY = -1;
 
-  int max; // used by mouseDragged to see if user
+  DragMode dragMode = DragMode.Undefined;
 
   boolean mouseDragging = false;
 
@@ -500,10 +505,11 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
   }
 
   /**
-   * DOCUMENT ME!
+   * Action on right mouse pressed on Mac is to show a pop-up menu for the
+   * annotation. Action on left mouse pressed is to find which annotation is
+   * pressed and mark the start of a column selection or graph resize operation.
    * 
    * @param evt
-   *          DOCUMENT ME!
    */
   @Override
   public void mousePressed(MouseEvent evt)
@@ -514,7 +520,13 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     {
       return;
     }
+    mouseDragLastX = evt.getX();
+    mouseDragLastY = evt.getY();
 
+    /*
+     * add visible annotation heights until we reach the y
+     * position, to find which annotation it is in
+     */
     int height = 0;
     activeRow = -1;
 
@@ -534,11 +546,11 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         }
         else if (aa[i].graph > 0)
         {
-          // Stretch Graph
+          /*
+           * we have clicked on a resizable graph annotation
+           */
           graphStretch = i;
-          graphStretchY = y;
         }
-
         break;
       }
     }
@@ -604,17 +616,20 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
   }
 
   /**
-   * DOCUMENT ME!
+   * Action on mouse up is to clear mouse drag data and call mouseReleased on
+   * ScalePanel, to deal with defining the selection group (if any) defined by
+   * the mouse drag
    * 
    * @param evt
-   *          DOCUMENT ME!
    */
   @Override
   public void mouseReleased(MouseEvent evt)
   {
     graphStretch = -1;
-    graphStretchY = -1;
+    mouseDragLastX = -1;
+    mouseDragLastY = -1;
     mouseDragging = false;
+    dragMode = DragMode.Undefined;
     ap.getScalePanel().mouseReleased(evt);
 
     /*
@@ -661,24 +676,73 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
   @Override
   public void mouseDragged(MouseEvent evt)
   {
-    if (graphStretch > -1)
+    /*
+     * todo: if dragMode is Undefined:
+     * - set to Select if dx > dy
+     * - set to Resize if dy > dx
+     * - do nothing if dx == dy
+     */
+    final int x = evt.getX();
+    final int y = evt.getY();
+    if (dragMode == DragMode.Undefined)
     {
-      av.getAlignment()
-              .getAlignmentAnnotation()[graphStretch].graphHeight += graphStretchY
-                      - evt.getY();
-      if (av.getAlignment()
-              .getAlignmentAnnotation()[graphStretch].graphHeight < 0)
+      int dx = Math.abs(x - mouseDragLastX);
+      int dy = Math.abs(y - mouseDragLastY);
+      if (graphStretch == -1 || dx > dy)
       {
-        av.getAlignment()
-                .getAlignmentAnnotation()[graphStretch].graphHeight = 0;
+        /*
+         * mostly horizontal drag, or not a graph annotation
+         */
+        dragMode = DragMode.Select;
+      }
+      else if (dy > dx)
+      {
+        /*
+         * mostly vertical drag
+         */
+        dragMode = DragMode.Resize;
       }
-      graphStretchY = evt.getY();
-      adjustPanelHeight();
-      ap.paintAlignment(false, false);
     }
-    else
+
+    if (dragMode == DragMode.Undefined)
+    {
+      /*
+       * drag is diagonal - defer deciding whether to
+       * treat as up/down or left/right
+       */
+      return;
+    }
+
+    try
+    {
+      if (dragMode == DragMode.Resize)
+      {
+        /*
+         * resize graph annotation if mouse was dragged up or down
+         */
+        int deltaY = mouseDragLastY - evt.getY();
+        if (deltaY != 0)
+        {
+          AlignmentAnnotation graphAnnotation = av.getAlignment()
+                  .getAlignmentAnnotation()[graphStretch];
+          int newHeight = Math.max(0, graphAnnotation.graphHeight + deltaY);
+          graphAnnotation.graphHeight = newHeight;
+          adjustPanelHeight();
+          ap.paintAlignment(false, false);
+        }
+      }
+      else
+      {
+        /*
+         * for mouse drag left or right, delegate to 
+         * ScalePanel to adjust the column selection
+         */
+        ap.getScalePanel().mouseDragged(evt);
+      }
+    } finally
     {
-      ap.getScalePanel().mouseDragged(evt);
+      mouseDragLastX = x;
+      mouseDragLastY = y;
     }
   }
 
index b676c9d..4526517 100644 (file)
@@ -24,6 +24,7 @@ import jalview.api.FeatureColourI;
 import jalview.api.FeatureSettingsControllerI;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcher;
 import jalview.datamodel.features.FeatureMatcherI;
 import jalview.datamodel.features.FeatureMatcherSet;
 import jalview.datamodel.features.FeatureMatcherSetI;
@@ -92,6 +93,7 @@ import javax.swing.JSlider;
 import javax.swing.JTable;
 import javax.swing.ListSelectionModel;
 import javax.swing.SwingConstants;
+import javax.swing.border.Border;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 import javax.swing.table.AbstractTableModel;
@@ -128,6 +130,8 @@ public class FeatureSettings extends JPanel
 
   private static final int MIN_HEIGHT = 400;
 
+  private final static String BASE_TOOLTIP = MessageManager.getString("label.click_to_edit");
+
   final FeatureRenderer fr;
 
   public final AlignFrame af;
@@ -158,12 +162,6 @@ public class FeatureSettings extends JPanel
 
   int selectedRow = -1;
 
-  JButton fetchDAS = new JButton();
-
-  JButton saveDAS = new JButton();
-
-  JButton cancelDAS = new JButton();
-
   boolean resettingTable = false;
 
   /*
@@ -208,14 +206,20 @@ public class FeatureSettings extends JPanel
       {
         String tip = null;
         int column = table.columnAtPoint(e.getPoint());
+        int row = table.rowAtPoint(e.getPoint());
+
         switch (column)
         {
         case TYPE_COLUMN:
           tip = JvSwingUtils.wrapTooltip(true, MessageManager
                   .getString("label.feature_settings_click_drag"));
           break;
+        case COLOUR_COLUMN:
+          FeatureColourI colour = (FeatureColourI) table.getValueAt(row,
+                  column);
+          tip = getColorTooltip(colour, true);
+          break;
         case FILTER_COLUMN:
-          int row = table.rowAtPoint(e.getPoint());
           FeatureMatcherSet o = (FeatureMatcherSet) table.getValueAt(row,
                   column);
           tip = o.isEmpty()
@@ -226,17 +230,30 @@ public class FeatureSettings extends JPanel
         default:
           break;
         }
+        
         return tip;
       }
+
+      /**
+       * Position the tooltip near the bottom edge of, and half way across, the
+       * current cell
+       */
+      @Override
+      public Point getToolTipLocation(MouseEvent e)
+      {
+        Point point = e.getPoint();
+        int column = table.columnAtPoint(point);
+        int row = table.rowAtPoint(point);
+        Rectangle r = getCellRect(row, column, false);
+        Point loc = new Point(r.x + r.width / 2, r.y + r.height - 3);
+        return loc;
+      }
     };
     JTableHeader tableHeader = table.getTableHeader();
     tableHeader.setFont(new Font("Verdana", Font.PLAIN, 12));
     tableHeader.setReorderingAllowed(false);
     table.setFont(new Font("Verdana", Font.PLAIN, 12));
 
-    // table.setDefaultRenderer(Color.class, new ColorRenderer());
-    // table.setDefaultEditor(Color.class, new ColorEditor(this));
-    //
     table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
     table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
 
@@ -1177,22 +1194,6 @@ public class FeatureSettings extends JPanel
         }
       }
     });
-    help.setFont(JvSwingUtils.getLabelFont());
-    help.setText(MessageManager.getString("action.help"));
-    help.addActionListener(new ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        try
-        {
-          Help.showHelpWindow(HelpId.SequenceFeatureSettings);
-        } catch (HelpSetException e1)
-        {
-          e1.printStackTrace();
-        }
-      }
-    });
 
     JButton cancel = new JButton(MessageManager.getString("action.cancel"));
     cancel.setFont(JvSwingUtils.getLabelFont());
@@ -1286,6 +1287,90 @@ public class FeatureSettings extends JPanel
     this.add(settingsPane);
   }
 
+  /**
+   * Answers a suitable tooltip to show on the colour cell of the table
+   * 
+   * @param fcol
+   * @param withHint
+   *          if true include 'click to edit' and similar text
+   * @return
+   */
+  public static String getColorTooltip(FeatureColourI fcol,
+          boolean withHint)
+  {
+    if (fcol == null)
+    {
+      return null;
+    }
+    if (fcol.isSimpleColour())
+    {
+      return withHint ? BASE_TOOLTIP : null;
+    }
+    String description = fcol.getDescription();
+    description = description.replaceAll("<", "&lt;");
+    description = description.replaceAll(">", "&gt;");
+    StringBuilder tt = new StringBuilder(description);
+    if (withHint)
+    {
+      tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
+    }
+    return JvSwingUtils.wrapTooltip(true, tt.toString());
+  }
+
+  public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
+          int w, int h)
+  {
+    boolean thr = false;
+    StringBuilder tx = new StringBuilder();
+  
+    if (gcol.isColourByAttribute())
+    {
+      tx.append(FeatureMatcher
+              .toAttributeDisplayName(gcol.getAttributeName()));
+    }
+    else if (!gcol.isColourByLabel())
+    {
+      tx.append(MessageManager.getString("label.score"));
+    }
+    tx.append(" ");
+    if (gcol.isAboveThreshold())
+    {
+      thr = true;
+      tx.append(">");
+    }
+    if (gcol.isBelowThreshold())
+    {
+      thr = true;
+      tx.append("<");
+    }
+    if (gcol.isColourByLabel())
+    {
+      if (thr)
+      {
+        tx.append(" ");
+      }
+      if (!gcol.isColourByAttribute())
+      {
+        tx.append("Label");
+      }
+      comp.setIcon(null);
+    }
+    else
+    {
+      Color newColor = gcol.getMaxColour();
+      comp.setBackground(newColor);
+      // System.err.println("Width is " + w / 2);
+      Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
+      comp.setIcon(ficon);
+      // tt+="RGB value: Max (" + newColor.getRed() + ", "
+      // + newColor.getGreen() + ", " + newColor.getBlue()
+      // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
+      // + ", " + minCol.getBlue() + ")");
+    }
+    comp.setHorizontalAlignment(SwingConstants.CENTER);
+    comp.setText(tx.toString());
+  }
+
   // ///////////////////////////////////////////////////////////////////////
   // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
   // ///////////////////////////////////////////////////////////////////////
@@ -1371,11 +1456,9 @@ public class FeatureSettings extends JPanel
 
   class ColorRenderer extends JLabel implements TableCellRenderer
   {
-    javax.swing.border.Border unselectedBorder = null;
+    Border unselectedBorder = null;
 
-    javax.swing.border.Border selectedBorder = null;
-
-    final String baseTT = "Click to edit, right/apple click for menu.";
+    Border selectedBorder = null;
 
     public ColorRenderer()
     {
@@ -1390,7 +1473,6 @@ public class FeatureSettings extends JPanel
     {
       FeatureColourI cellColour = (FeatureColourI) color;
       setOpaque(true);
-      setToolTipText(baseTT);
       setBackground(tbl.getBackground());
       if (!cellColour.isSimpleColour())
       {
@@ -1497,77 +1579,6 @@ public class FeatureSettings extends JPanel
     renderGraduatedColor(comp, gcol, w, h);
   }
 
-  public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
-          int w, int h)
-  {
-    boolean thr = false;
-    StringBuilder tt = new StringBuilder();
-    StringBuilder tx = new StringBuilder();
-
-    if (gcol.isColourByAttribute())
-    {
-      tx.append(String.join(":", gcol.getAttributeName()));
-    }
-    else if (!gcol.isColourByLabel())
-    {
-      tx.append(MessageManager.getString("label.score"));
-    }
-    tx.append(" ");
-    if (gcol.isAboveThreshold())
-    {
-      thr = true;
-      tx.append(">");
-      tt.append("Thresholded (Above ").append(gcol.getThreshold())
-              .append(") ");
-    }
-    if (gcol.isBelowThreshold())
-    {
-      thr = true;
-      tx.append("<");
-      tt.append("Thresholded (Below ").append(gcol.getThreshold())
-              .append(") ");
-    }
-    if (gcol.isColourByLabel())
-    {
-      tt.append("Coloured by label text. ").append(tt);
-      if (thr)
-      {
-        tx.append(" ");
-      }
-      if (!gcol.isColourByAttribute())
-      {
-        tx.append("Label");
-      }
-      comp.setIcon(null);
-    }
-    else
-    {
-      Color newColor = gcol.getMaxColour();
-      comp.setBackground(newColor);
-      // System.err.println("Width is " + w / 2);
-      Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
-      comp.setIcon(ficon);
-      // tt+="RGB value: Max (" + newColor.getRed() + ", "
-      // + newColor.getGreen() + ", " + newColor.getBlue()
-      // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
-      // + ", " + minCol.getBlue() + ")");
-    }
-    comp.setHorizontalAlignment(SwingConstants.CENTER);
-    comp.setText(tx.toString());
-    if (tt.length() > 0)
-    {
-      if (comp.getToolTipText() == null)
-      {
-        comp.setToolTipText(tt.toString());
-      }
-      else
-      {
-        comp.setToolTipText(
-                tt.append(" ").append(comp.getToolTipText()).toString());
-      }
-    }
-  }
-
   class ColorEditor extends AbstractCellEditor
           implements TableCellEditor, ActionListener
   {
@@ -1803,7 +1814,6 @@ public class FeatureSettings extends JPanel
       button.setOpaque(true);
       button.setBackground(me.getBackground());
       button.setText(currentFilter.toString());
-      button.setToolTipText(currentFilter.toString());
       button.setIcon(null);
       return button;
     }
index 58bbbe8..82e826f 100644 (file)
@@ -562,13 +562,20 @@ public class FeatureTypeSettings extends JalviewDialog
     maxColour.setBorder(new LineBorder(Color.black));
 
     /*
-     * default max colour to last plain colour;
-     * make min colour a pale version of max colour
+     * if not set, default max colour to last plain colour,
+     * and make min colour a pale version of max colour
      */
-    FeatureColourI fc = fr.getFeatureColours().get(featureType);
-    Color bg = fc.getColour() == null ? Color.BLACK : fc.getColour();
-    maxColour.setBackground(bg);
-    minColour.setBackground(ColorUtils.bleachColour(bg, 0.9f));
+    Color max = originalColour.getMaxColour();
+    if (max == null)
+    {
+      max = originalColour.getColour();
+      minColour.setBackground(ColorUtils.bleachColour(max, 0.9f));
+    }
+    else
+    {
+      maxColour.setBackground(max);
+      minColour.setBackground(originalColour.getMinColour());
+    }
 
     noValueCombo = new JComboBox<>();
     noValueCombo.addItem(MessageManager.getString("label.no_colour"));
@@ -747,16 +754,16 @@ public class FeatureTypeSettings extends JalviewDialog
     singleColour.setFont(JvSwingUtils.getLabelFont());
     singleColour.setBorder(BorderFactory.createLineBorder(Color.black));
     singleColour.setPreferredSize(new Dimension(40, 20));
-    if (originalColour.isGraduatedColour())
-    {
-      singleColour.setBackground(originalColour.getMaxColour());
-      singleColour.setForeground(originalColour.getMaxColour());
-    }
-    else
-    {
+    // if (originalColour.isGraduatedColour())
+    // {
+    // singleColour.setBackground(originalColour.getMaxColour());
+    // singleColour.setForeground(originalColour.getMaxColour());
+    // }
+    // else
+    // {
       singleColour.setBackground(originalColour.getColour());
       singleColour.setForeground(originalColour.getColour());
-    }
+    // }
     singleColour.addMouseListener(new MouseAdapter()
     {
       @Override
@@ -881,42 +888,9 @@ public class FeatureTypeSettings extends JalviewDialog
   private FeatureColourI makeColourFromInputs()
   {
     /*
-     * easiest case - a single colour
+     * min-max range is to (or from) threshold value if 
+     * 'threshold is min/max' is selected 
      */
-    if (simpleColour.isSelected())
-    {
-      return new FeatureColour(singleColour.getBackground());
-    }
-
-    /*
-     * next easiest case - colour by Label, or attribute text
-     */
-    if (byCategory.isSelected())
-    {
-      Color c = singleColour.getBackground();
-      FeatureColourI fc = new FeatureColour(c);
-      fc.setColourByLabel(true);
-      String byWhat = (String) colourByTextCombo.getSelectedItem();
-      if (!LABEL_18N.equals(byWhat))
-      {
-        fc.setAttributeName(
-                FeatureMatcher.fromAttributeDisplayName(byWhat));
-      }
-      return fc;
-    }
-
-    /*
-     * remaining case - graduated colour by score, or attribute value
-     */
-    Color noColour = null;
-    if (noValueCombo.getSelectedIndex() == MIN_COLOUR_OPTION)
-    {
-      noColour = minColour.getBackground();
-    }
-    else if (noValueCombo.getSelectedIndex() == MAX_COLOUR_OPTION)
-    {
-      noColour = maxColour.getBackground();
-    }
 
     float thresh = 0f;
     try
@@ -926,11 +900,6 @@ public class FeatureTypeSettings extends JalviewDialog
     {
       // invalid inputs are already handled on entry
     }
-
-    /*
-     * min-max range is to (or from) threshold value if 
-     * 'threshold is min/max' is selected 
-     */
     float minValue = min;
     float maxValue = max;
     final int thresholdOption = threshold.getSelectedIndex();
@@ -944,14 +913,50 @@ public class FeatureTypeSettings extends JalviewDialog
     {
       maxValue = thresh;
     }
+    Color noColour = null;
+    if (noValueCombo.getSelectedIndex() == MIN_COLOUR_OPTION)
+    {
+      noColour = minColour.getBackground();
+    }
+    else if (noValueCombo.getSelectedIndex() == MAX_COLOUR_OPTION)
+    {
+      noColour = maxColour.getBackground();
+    }
+
+    /*
+     * construct a colour that 'remembers' all the options, including
+     * those not currently selected
+     */
+    FeatureColourI fc = new FeatureColour(singleColour.getBackground(),
+            minColour.getBackground(), maxColour.getBackground(), noColour,
+            minValue, maxValue);
+
+    /*
+     * easiest case - a single colour
+     */
+    if (simpleColour.isSelected())
+    {
+      ((FeatureColour) fc).setGraduatedColour(false);
+      return fc;
+    }
 
     /*
-     * make the graduated colour
+     * next easiest case - colour by Label, or attribute text
      */
-    FeatureColourI fc = new FeatureColour(minColour.getBackground(),
-            maxColour.getBackground(), noColour, minValue, maxValue);
+    if (byCategory.isSelected())
+    {
+      fc.setColourByLabel(true);
+      String byWhat = (String) colourByTextCombo.getSelectedItem();
+      if (!LABEL_18N.equals(byWhat))
+      {
+        fc.setAttributeName(
+                FeatureMatcher.fromAttributeDisplayName(byWhat));
+      }
+      return fc;
+    }
 
     /*
+     * remaining case - graduated colour by score, or attribute value;
      * set attribute to colour by if selected
      */
     String byWhat = (String) colourByRangeCombo.getSelectedItem();
index 84540f4..a4d7ad0 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.gui;
 
+import jalview.api.AlignViewportI;
+import jalview.api.FinderI;
 import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceFeature;
@@ -32,8 +34,9 @@ import java.awt.Dimension;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
-import java.util.Vector;
+import java.util.Map;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
 
@@ -42,6 +45,7 @@ import javax.swing.JComponent;
 import javax.swing.JInternalFrame;
 import javax.swing.JLayeredPane;
 import javax.swing.KeyStroke;
+import javax.swing.event.InternalFrameAdapter;
 import javax.swing.event.InternalFrameEvent;
 
 /**
@@ -57,33 +61,39 @@ import javax.swing.event.InternalFrameEvent;
  */
 public class Finder extends GFinder
 {
-  private static final int MY_HEIGHT = 120;
+  private static final int MIN_WIDTH = 350;
 
-  private static final int MY_WIDTH = 400;
+  private static final int MIN_HEIGHT = 120;
 
-  AlignmentViewport av;
+  private static final int MY_HEIGHT = 120;
 
-  AlignmentPanel ap;
+  private static final int MY_WIDTH = 400;
 
-  private static final int MIN_WIDTH = 350;
+  private AlignViewportI av;
 
-  private static final int MIN_HEIGHT = 120;
+  private AlignmentPanel ap;
 
-  JInternalFrame frame;
+  private JInternalFrame frame;
 
-  int seqIndex = 0;
+  /*
+   * Finder agent per viewport searched
+   */
+  private Map<AlignViewportI, FinderI> finders;
 
-  int resIndex = -1;
+  private SearchResultsI searchResults;
 
-  SearchResultsI searchResults;
+  /*
+   * true if we only search a given alignment view
+   */
+  private boolean focusfixed;
 
   /**
-   * Creates a new Finder object with no associated viewport or panel.
+   * Creates a new Finder object with no associated viewport or panel. Each Find
+   * or Find Next action will act on whichever viewport has focus at the time.
    */
   public Finder()
   {
     this(null, null);
-    focusfixed = false;
   }
 
   /**
@@ -97,12 +107,13 @@ public class Finder extends GFinder
   {
     av = viewport;
     ap = alignPanel;
-    focusfixed = true;
+    finders = new HashMap<>();
+    focusfixed = viewport != null;
     frame = new JInternalFrame();
     frame.setContentPane(this);
     frame.setLayer(JLayeredPane.PALETTE_LAYER);
     frame.addInternalFrameListener(
-            new javax.swing.event.InternalFrameAdapter()
+            new InternalFrameAdapter()
             {
               @Override
               public void internalFrameClosing(InternalFrameEvent e)
@@ -135,12 +146,10 @@ public class Finder extends GFinder
   }
 
   /**
-   * Performs the 'Find Next' action.
-   * 
-   * @param e
+   * Performs the 'Find Next' action on the alignment panel with focus
    */
   @Override
-  public void findNext_actionPerformed(ActionEvent e)
+  public void findNext_actionPerformed()
   {
     if (getFocusedViewport())
     {
@@ -149,27 +158,18 @@ public class Finder extends GFinder
   }
 
   /**
-   * Performs the 'Find All' action.
-   * 
-   * @param e
+   * Performs the 'Find All' action on the alignment panel with focus
    */
   @Override
-  public void findAll_actionPerformed(ActionEvent e)
+  public void findAll_actionPerformed()
   {
     if (getFocusedViewport())
     {
-      resIndex = -1;
-      seqIndex = 0;
       doSearch(true);
     }
   }
 
   /**
-   * do we only search a given alignment view ?
-   */
-  private boolean focusfixed;
-
-  /**
    * if !focusfixed and not in a desktop environment, checks that av and ap are
    * valid. Otherwise, gets the topmost alignment window and sets av and ap
    * accordingly
@@ -193,7 +193,8 @@ public class Finder extends GFinder
     for (int f = 0; f < frames.length; f++)
     {
       JInternalFrame alignFrame = frames[f];
-      if (alignFrame != null && alignFrame instanceof AlignFrame)
+      if (alignFrame != null && alignFrame instanceof AlignFrame
+              && !alignFrame.isIcon())
       {
         av = ((AlignFrame) alignFrame).viewport;
         ap = ((AlignFrame) alignFrame).alignPanel;
@@ -210,8 +211,8 @@ public class Finder extends GFinder
   @Override
   public void createFeatures_actionPerformed()
   {
-    List<SequenceI> seqs = new ArrayList<SequenceI>();
-    List<SequenceFeature> features = new ArrayList<SequenceFeature>();
+    List<SequenceI> seqs = new ArrayList<>();
+    List<SequenceFeature> features = new ArrayList<>();
 
     String searchString = searchBox.getEditor().getItem().toString().trim();
     String desc = "Search Results";
@@ -261,55 +262,48 @@ public class Finder extends GFinder
     // other stuff
     // TODO: add switches to control what is searched - sequences, IDS,
     // descriptions, features
-    jalview.analysis.Finder finder = new jalview.analysis.Finder(
-            av.getAlignment(), av.getSelectionGroup(), seqIndex, resIndex);
-    finder.setCaseSensitive(caseSensitive.isSelected());
-    finder.setIncludeDescription(searchDescription.isSelected());
-
-    finder.setFindAll(doFindAll);
-
-    finder.find(searchString); // returns true if anything was actually found
-
-    seqIndex = finder.getSeqIndex();
-    resIndex = finder.getResIndex();
+    FinderI finder = finders.get(av);
+    if (finder == null)
+    {
+      /*
+       * first time we've searched this viewport
+       */
+      finder = new jalview.analysis.Finder(av);
+      finders.put(av, finder);
+    }
 
-    searchResults = finder.getSearchResults(); // find(regex,
-    // caseSensitive.isSelected(), )
-    Vector<SequenceI> idMatch = finder.getIdMatch();
-    boolean haveResults = false;
-    // set or reset the GUI
-    if ((idMatch.size() > 0))
+    boolean isCaseSensitive = caseSensitive.isSelected();
+    boolean doSearchDescription = searchDescription.isSelected();
+    if (doFindAll)
     {
-      haveResults = true;
-      ap.getIdPanel().highlightSearchResults(idMatch);
+      finder.findAll(searchString, isCaseSensitive, doSearchDescription);
     }
     else
     {
-      ap.getIdPanel().highlightSearchResults(null);
+      finder.findNext(searchString, isCaseSensitive, doSearchDescription);
     }
 
-    if (searchResults.getSize() > 0)
+    searchResults = finder.getSearchResults();
+    List<SequenceI> idMatch = finder.getIdMatches();
+    ap.getIdPanel().highlightSearchResults(idMatch);
+
+    if (searchResults.isEmpty())
     {
-      haveResults = true;
-      createFeatures.setEnabled(true);
+      searchResults = null;
     }
     else
     {
-      searchResults = null;
+      createFeatures.setEnabled(true);
     }
 
-    // if allResults is null, this effectively switches displaySearch flag in
-    // seqCanvas
     ap.highlightSearchResults(searchResults);
     // TODO: add enablers for 'SelectSequences' or 'SelectColumns' or
     // 'SelectRegion' selection
-    if (!haveResults)
+    if (idMatch.isEmpty() && searchResults == null)
     {
       JvOptionPane.showInternalMessageDialog(this,
               MessageManager.getString("label.finished_searching"), null,
               JvOptionPane.INFORMATION_MESSAGE);
-      resIndex = -1;
-      seqIndex = 0;
     }
     else
     {
@@ -329,8 +323,6 @@ public class Finder extends GFinder
         }
         JvOptionPane.showInternalMessageDialog(this, message, null,
                 JvOptionPane.INFORMATION_MESSAGE);
-        resIndex = -1;
-        seqIndex = 0;
       }
     }
     searchBox.updateCache();
index f2d8113..810fc92 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import java.awt.Point;
 import java.net.URL;
 
 import javax.help.BadIDException;
@@ -28,17 +29,17 @@ import javax.help.HelpSet;
 import javax.help.HelpSetException;
 
 /**
- * Utility class to show the help documentation window.
+ * Utility class to show the help documentation window
  * 
  * @author gmcarstairs
- *
  */
 public class Help
 {
   public enum HelpId
   {
     Home("home"), SequenceFeatureSettings("seqfeatures.settings"),
-    StructureViewer("viewingpdbs");
+    StructureViewer("viewingpdbs"), PdbFts("pdbfts"),
+    UniprotFts("uniprotfts");
 
     private String id;
 
@@ -54,9 +55,7 @@ public class Help
     }
   }
 
-  private static final long HALF_A_MO = 500; // half a second
-
-  private static long lastOpenedTime = 0L;
+  private static HelpBroker hb;
 
   /**
    * Not instantiable
@@ -67,42 +66,50 @@ public class Help
   }
 
   /**
-   * Show help text in a new window. But do nothing if within half a second of
-   * the last invocation.
-   * 
-   * This is a workaround for issue JAL-914 - both Desktop and AlignFrame
-   * responding to F1 key, resulting in duplicate help windows opened.
+   * Shows the help window, at the entry specified by the given helpId
    * 
    * @param id
-   *          TODO
    * 
    * @throws HelpSetException
    */
   public static void showHelpWindow(HelpId id) throws HelpSetException
   {
-    long timeNow = System.currentTimeMillis();
+    ClassLoader cl = Desktop.class.getClassLoader();
+    URL url = HelpSet.findHelpSet(cl, "help/help"); // $NON-NLS-$
+    HelpSet hs = new HelpSet(cl, url);
 
-    if (timeNow - lastOpenedTime > HALF_A_MO)
+    if (hb == null)
     {
-      lastOpenedTime = timeNow;
-      ClassLoader cl = Desktop.class.getClassLoader();
-      URL url = HelpSet.findHelpSet(cl, "help/help"); // $NON-NLS-$
-      HelpSet hs = new HelpSet(cl, url);
+      /*
+       * create help broker first time (only)
+       */
+      hb = hs.createHelpBroker();
+    }
 
-      HelpBroker hb = hs.createHelpBroker();
-      try
-      {
-        hb.setCurrentID(id.toString());
-      } catch (BadIDException bad)
-      {
-        System.out.println("Bad help link: " + id.toString()
-                + ": must match a target in help.jhm");
-        throw bad;
-      }
-      hb.setDisplayed(true);
+    try
+    {
+      hb.setCurrentID(id.toString());
+    } catch (BadIDException bad)
+    {
+      System.out.println("Bad help link: " + id.toString()
+              + ": must match a target in help.jhm");
+      throw bad;
     }
+
+    /*
+     * set Help visible - at its current location if it is already shown,
+     * else at a location as determined by the window manager
+     */
+    Point p = hb.getLocation();
+    hb.setLocation(p);
+    hb.setDisplayed(true);
   }
 
+  /**
+   * Show the Help window at the root entry
+   * 
+   * @throws HelpSetException
+   */
   public static void showHelpWindow() throws HelpSetException
   {
     showHelpWindow(HelpId.Home);
index cf88c90..951db78 100755 (executable)
@@ -380,12 +380,6 @@ public class IdCanvas extends JPanel implements ViewportListenerI
     int alignmentWidth = alignViewport.getAlignment().getWidth();
     final int alheight = alignViewport.getAlignment().getHeight();
 
-    if (alignViewport.hasHiddenColumns())
-    {
-      alignmentWidth = alignViewport.getAlignment().getHiddenColumns()
-              .absoluteToVisibleColumn(alignmentWidth) - 1;
-    }
-
     int annotationHeight = 0;
 
     AnnotationLabels labels = null;
index 1fd9e49..d11d7a1 100755 (executable)
@@ -30,6 +30,7 @@ import jalview.io.SequenceAnnotationReport;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BorderLayout;
 import java.awt.event.MouseEvent;
@@ -261,7 +262,7 @@ public class IdPanel extends JPanel
   {
     if (scrollThread != null)
     {
-      scrollThread.running = false;
+      scrollThread.stopScrolling();
     }
   }
 
@@ -484,7 +485,7 @@ public class IdPanel extends JPanel
   {
     if (scrollThread != null)
     {
-      scrollThread.running = false;
+      scrollThread.stopScrolling();
     }
     MousePos pos = alignPanel.getSeqPanel().findMousePosition(e);
 
@@ -509,7 +510,7 @@ public class IdPanel extends JPanel
   {
     getIdCanvas().setHighlighted(list);
 
-    if (list == null)
+    if (list == null || list.isEmpty())
     {
       return;
     }
@@ -534,24 +535,42 @@ public class IdPanel extends JPanel
     this.idCanvas = idCanvas;
   }
 
-  // this class allows scrolling off the bottom of the visible alignment
+  /**
+   * Performs scrolling of the visible alignment up or down, adding newly
+   * visible sequences to the current selection
+   */
   class ScrollThread extends Thread
   {
-    boolean running = false;
+    private boolean running = false;
 
-    boolean up = true;
+    private boolean up;
 
+    /**
+     * Constructor for a thread that scrolls either up or down
+     * 
+     * @param up
+     */
     public ScrollThread(boolean up)
     {
       this.up = up;
+      setName("IdPanel$ScrollThread$" + String.valueOf(up));
       start();
     }
 
+    /**
+     * Sets a flag to stop the scrolling
+     */
     public void stopScrolling()
     {
       running = false;
     }
 
+    /**
+     * Scrolls the alignment either up or down, one row at a time, adding newly
+     * visible sequences to the current selection. Speed is limited to a maximum
+     * of ten rows per second. The thread exits when the end of the alignment is
+     * reached or a flag is set to stop it.
+     */
     @Override
     public void run()
     {
@@ -559,29 +578,20 @@ public class IdPanel extends JPanel
 
       while (running)
       {
-        if (av.getRanges().scrollUp(up))
+        ViewportRanges ranges = IdPanel.this.av.getRanges();
+        if (ranges.scrollUp(up))
         {
-          // scroll was ok, so add new sequence to selection
-          int seq = av.getRanges().getStartSeq();
-
-          if (!up)
-          {
-            seq = av.getRanges().getEndSeq();
-          }
-
-          if (seq < lastid)
-          {
-            selectSeqs(lastid - 1, seq);
-          }
-          else if (seq > lastid)
-          {
-            selectSeqs(lastid + 1, seq);
-          }
-
-          lastid = seq;
+          int toSeq = up ? ranges.getStartSeq() : ranges.getEndSeq();
+          int fromSeq = toSeq < lastid ? lastid - 1 : lastid + 1;
+          IdPanel.this.selectSeqs(fromSeq, toSeq);
+
+          lastid = toSeq;
         }
         else
         {
+          /*
+           * scroll did nothing - reached limit of visible alignment
+           */
           running = false;
         }
 
index a73a06a..9d0a55d 100755 (executable)
@@ -112,7 +112,7 @@ public class OverviewPanel extends JPanel
 
     // without this the overview window does not size to fit the overview canvas
     setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
-
+    
     addComponentListener(new ComponentAdapter()
     {
       @Override
@@ -170,22 +170,23 @@ public class OverviewPanel extends JPanel
       @Override
       public void mouseMoved(MouseEvent evt)
       {
-        if (!draggingBox)
-        // don't bother changing the cursor if we're dragging the box
-        // as we can't have moved inside or out of the box in that case
+        if (od.isPositionInBox(evt.getX(), evt.getY()))
         {
-          if (od.isPositionInBox(evt.getX(), evt.getY()))
-          {
-            // display drag cursor at mouse position
-            setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
-          }
-          else
-          {
-            // reset cursor
-            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
-          }
+          /*
+           * using HAND_CURSOR rather than DRAG_CURSOR 
+           * as the latter is not supported on Mac
+           */
+          getParent().setCursor(
+                  Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+        }
+        else
+        {
+          // reset cursor
+          getParent().setCursor(
+                  Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
         }
       }
+
     });
 
     addMouseListener(new MouseAdapter()
@@ -215,6 +216,8 @@ public class OverviewPanel extends JPanel
             od.updateViewportFromMouse(evt.getX(), evt.getY(),
                     av.getAlignment().getHiddenSequences(),
                     av.getAlignment().getHiddenColumns());
+            getParent().setCursor(
+                    Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
           }
           else
           {
index d181804..0f2b765 100755 (executable)
@@ -34,6 +34,7 @@ import java.awt.Color;
 import java.awt.FontMetrics;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
+import java.awt.Point;
 import java.awt.RenderingHints;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
@@ -157,7 +158,12 @@ public class ScalePanel extends JPanel
   protected void rightMouseButtonPressed(MouseEvent evt, final int res)
   {
     JPopupMenu pop = new JPopupMenu();
-    if (reveal != null)
+
+    /*
+     * grab the hidden range in case mouseMoved nulls it
+     */
+    final int[] hiddenRange = reveal;
+    if (hiddenRange != null)
     {
       JMenuItem item = new JMenuItem(
               MessageManager.getString("label.reveal"));
@@ -166,8 +172,9 @@ public class ScalePanel extends JPanel
         @Override
         public void actionPerformed(ActionEvent e)
         {
-          av.showColumn(reveal[0]);
+          av.showColumn(hiddenRange[0]);
           reveal = null;
+          ap.updateLayout();
           ap.paintAlignment(true, true);
           av.sendSelection();
         }
@@ -184,6 +191,7 @@ public class ScalePanel extends JPanel
           {
             av.showAllHiddenColumns();
             reveal = null;
+            ap.updateLayout();
             ap.paintAlignment(true, true);
             av.sendSelection();
           }
@@ -208,6 +216,7 @@ public class ScalePanel extends JPanel
             av.setSelectionGroup(null);
           }
 
+          ap.updateLayout();
           ap.paintAlignment(true, true);
           av.sendSelection();
         }
@@ -257,31 +266,26 @@ public class ScalePanel extends JPanel
   }
 
   /**
-   * DOCUMENT ME!
+   * Action on mouseUp is to set the limit of the current selection group (if
+   * there is one) and broadcast the selection
    * 
    * @param evt
-   *          DOCUMENT ME!
    */
   @Override
   public void mouseReleased(MouseEvent evt)
   {
     mouseDragging = false;
+    ap.getSeqPanel().stopScrolling();
 
     int xCords = Math.max(0, evt.getX()); // prevent negative X coordinates
-
     int res = (xCords / av.getCharWidth())
             + av.getRanges().getStartRes();
-
     if (av.hasHiddenColumns())
     {
       res = av.getAlignment().getHiddenColumns()
               .visibleToAbsoluteColumn(res);
     }
-
-    if (res >= av.getAlignment().getWidth())
-    {
-      res = av.getAlignment().getWidth() - 1;
-    }
+    res = Math.min(res, av.getAlignment().getWidth() - 1);
 
     if (!stretchingGroup)
     {
@@ -354,16 +358,22 @@ public class ScalePanel extends JPanel
   {
     if (mouseDragging)
     {
-      ap.getSeqPanel().scrollCanvas(null);
+      ap.getSeqPanel().stopScrolling();
     }
   }
 
+  /**
+   * Action on leaving the panel bounds with mouse drag in progress is to start
+   * scrolling the alignment in the direction of the mouse. To restrict
+   * scrolling to left-right (not up-down), the y-value of the mouse position is
+   * replaced with zero.
+   */
   @Override
   public void mouseExited(MouseEvent evt)
   {
     if (mouseDragging)
     {
-      ap.getSeqPanel().scrollCanvas(evt);
+      ap.getSeqPanel().startScrolling(new Point(evt.getX(), 0));
     }
   }
 
index dc87eba..b3fcc54 100755 (executable)
@@ -870,13 +870,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     int startx = startRes;
     int endx;
     int ypos = hgap; // vertical offset
-    int maxwidth = av.getAlignment().getWidth();
-
-    if (av.hasHiddenColumns())
-    {
-      maxwidth = av.getAlignment().getHiddenColumns()
-              .absoluteToVisibleColumn(maxwidth);
-    }
+    int maxwidth = av.getAlignment().getVisibleWidth();
 
     // chop the wrapped alignment extent up into panel-sized blocks and treat
     // each block as if it were a block from an unwrapped alignment
@@ -1661,7 +1655,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       }
       ViewportRanges vpRanges = av.getRanges();
 
-      int range = vpRanges.getEndRes() - vpRanges.getStartRes();
+      int range = vpRanges.getEndRes() - vpRanges.getStartRes() + 1;
       if (scrollX > range)
       {
         scrollX = range;
@@ -1730,10 +1724,10 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   {
     ViewportRanges ranges = av.getRanges();
 
-    if (Math.abs(scrollX) > ranges.getViewportWidth())
+    if (Math.abs(scrollX) >= ranges.getViewportWidth())
     {
       /*
-       * shift of more than one view width is 
+       * shift of one view width or more is 
        * overcomplicated to handle in this method
        */
       fastPaint = false;
@@ -1924,10 +1918,17 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
       while (y >= 0)
       {
+        /*
+         * shift 'widthToCopy' residues by 'positions' places to the right
+         */
         gg.copyArea(copyFromLeftStart, y, widthToCopy, heightToCopy,
                 positions * charWidth, 0);
         if (y > 0)
         {
+          /*
+           * copy 'positions' residue from the row above (right hand end)
+           * to this row's left hand end
+           */
           gg.copyArea(copyFromRightStart, y - wrappedRepeatHeightPx,
                   positions * charWidth, heightToCopy, -widthToCopy,
                   wrappedRepeatHeightPx);
index 7abbd7d..4a1a9ee 100644 (file)
@@ -49,6 +49,7 @@ import jalview.util.MappingUtils;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BorderLayout;
 import java.awt.Color;
@@ -742,13 +743,14 @@ public class SeqPanel extends JPanel
       return;
     }
 
-    if (!editingSeqs)
+    if (editingSeqs)
+    {
+      endEditing();
+    }
+    else
     {
       doMouseReleasedDefineMode(evt, didDrag);
-      return;
     }
-
-    endEditing();
   }
 
   /**
@@ -1325,9 +1327,9 @@ public class SeqPanel extends JPanel
     }
 
     mouseDragging = true;
-    if ((scrollThread != null) && (scrollThread.isRunning()))
+    if (scrollThread != null)
     {
-      scrollThread.setEvent(evt);
+      scrollThread.setMousePosition(evt.getPoint());
     }
   }
 
@@ -1898,10 +1900,10 @@ public class SeqPanel extends JPanel
   }
 
   /**
-   * DOCUMENT ME!
+   * On reentering the panel, stops any scrolling that was started on dragging
+   * out of the panel
    * 
    * @param e
-   *          DOCUMENT ME!
    */
   @Override
   public void mouseEntered(MouseEvent e)
@@ -1910,19 +1912,14 @@ public class SeqPanel extends JPanel
     {
       oldSeq = 0;
     }
-
-    if ((scrollThread != null) && (scrollThread.isRunning()))
-    {
-      scrollThread.stopScrolling();
-      scrollThread = null;
-    }
+    stopScrolling();
   }
 
   /**
-   * DOCUMENT ME!
+   * On leaving the panel, if the mouse is being dragged, starts a thread to
+   * scroll it until the mouse is released (in unwrapped mode only)
    * 
    * @param e
-   *          DOCUMENT ME!
    */
   @Override
   public void mouseExited(MouseEvent e)
@@ -2248,10 +2245,7 @@ public class SeqPanel extends JPanel
       return;
     }
 
-    if (res >= av.getAlignment().getWidth())
-    {
-      res = av.getAlignment().getWidth() - 1;
-    }
+    res = Math.min(res, av.getAlignment().getWidth()-1);
 
     if (stretchGroup.getEndRes() == res)
     {
@@ -2337,9 +2331,9 @@ public class SeqPanel extends JPanel
 
     mouseDragging = true;
 
-    if ((scrollThread != null) && (scrollThread.isRunning()))
+    if (scrollThread != null)
     {
-      scrollThread.setEvent(evt);
+      scrollThread.setMousePosition(evt.getPoint());
     }
 
     /*
@@ -2369,83 +2363,120 @@ public class SeqPanel extends JPanel
     ap.alignFrame.setStatus(status.toString());
   }
 
-  void scrollCanvas(MouseEvent evt)
+  /**
+   * Stops the scroll thread if it is running
+   */
+  void stopScrolling()
   {
-    if (evt == null)
+    if (scrollThread != null)
     {
-      if ((scrollThread != null) && (scrollThread.isRunning()))
-      {
-        scrollThread.stopScrolling();
-        scrollThread = null;
-      }
-      mouseDragging = false;
+      scrollThread.stopScrolling();
+      scrollThread = null;
     }
-    else
-    {
-      if (scrollThread == null)
-      {
-        scrollThread = new ScrollThread();
-      }
+    mouseDragging = false;
+  }
 
-      mouseDragging = true;
-      scrollThread.setEvent(evt);
+  /**
+   * Starts a thread to scroll the alignment, towards a given mouse position
+   * outside the panel bounds
+   * 
+   * @param mousePos
+   */
+  void startScrolling(Point mousePos)
+  {
+    if (scrollThread == null)
+    {
+      scrollThread = new ScrollThread();
     }
 
+    mouseDragging = true;
+    scrollThread.setMousePosition(mousePos);
   }
 
-  // this class allows scrolling off the bottom of the visible alignment
+  /**
+   * Performs scrolling of the visible alignment left, right, up or down
+   */
   class ScrollThread extends Thread
   {
-    MouseEvent evt;
+    private Point mousePos;
 
     private volatile boolean threadRunning = true;
 
+    /**
+     * Constructor
+     */
     public ScrollThread()
     {
+      setName("SeqPanel$ScrollThread");
       start();
     }
 
-    public void setEvent(MouseEvent e)
+    /**
+     * Sets the position of the mouse that determines the direction of the
+     * scroll to perform
+     * 
+     * @param p
+     */
+    public void setMousePosition(Point p)
     {
-      evt = e;
+      mousePos = p;
     }
 
+    /**
+     * Sets a flag that will cause the thread to exit
+     */
     public void stopScrolling()
     {
       threadRunning = false;
     }
 
-    public boolean isRunning()
-    {
-      return threadRunning;
-    }
-
+    /**
+     * Scrolls the alignment left or right, and/or up or down, depending on the
+     * last notified mouse position, until the limit of the alignment is
+     * reached, or a flag is set to stop the scroll
+     */
     @Override
     public void run()
     {
-      while (threadRunning)
+      while (threadRunning && mouseDragging)
       {
-        if (evt != null)
+        if (mousePos != null)
         {
-          if (mouseDragging && (evt.getY() < 0)
-                  && (av.getRanges().getStartSeq() > 0))
+          boolean scrolled = false;
+          ViewportRanges ranges = SeqPanel.this.av.getRanges();
+
+          /*
+           * scroll up or down
+           */
+          if (mousePos.y < 0)
           {
-            av.getRanges().scrollUp(true);
+            // mouse is above this panel - try scroll up
+            scrolled = ranges.scrollUp(true);
           }
-
-          if (mouseDragging && (evt.getY() >= getHeight()) && (av
-                  .getAlignment().getHeight() > av.getRanges().getEndSeq()))
+          else if (mousePos.y >= getHeight())
           {
-            av.getRanges().scrollUp(false);
+            // mouse is below this panel - try scroll down
+            scrolled = ranges.scrollUp(false);
           }
 
-          if (mouseDragging && (evt.getX() < 0))
+          /*
+           * scroll left or right
+           */
+          if (mousePos.x < 0)
           {
-            av.getRanges().scrollRight(false);
+            scrolled |= ranges.scrollRight(false);
           }
-          else if (mouseDragging && (evt.getX() >= getWidth()))
+          else if (mousePos.x >= getWidth())
           {
-            av.getRanges().scrollRight(true);
+            scrolled |= ranges.scrollRight(true);
+          }
+          if (!scrolled)
+          {
+            /*
+             * we have reached the limit of the visible alignment - quit
+             */
+            threadRunning = false;
+            SeqPanel.this.ap.repaint();
           }
         }
 
index 93a2457..f98139b 100755 (executable)
@@ -26,6 +26,7 @@ import jalview.jbgui.GSliderPanel;
 import jalview.renderer.ResidueShaderI;
 import jalview.util.MessageManager;
 
+import java.awt.event.ActionEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.beans.PropertyVetoException;
@@ -396,7 +397,6 @@ public class SliderPanel extends GSliderPanel
   public void setAllGroupsCheckEnabled(boolean b)
   {
     allGroupsCheck.setEnabled(b);
-    allGroupsCheck.setSelected(ap.av.getColourAppliesToAllGroups());
   }
 
   /**
@@ -497,4 +497,13 @@ public class SliderPanel extends GSliderPanel
     }
     return title;
   }
+
+  @Override
+  protected void allGroupsCheck_actionPerformed(ActionEvent e)
+  {
+    if (allGroupsCheck.isSelected())
+    {
+      valueChanged(slider.getValue());
+    }
+  }
 }
index d5c8c01..0ee03bc 100755 (executable)
@@ -21,6 +21,8 @@
 package jalview.jbgui;
 
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
+import jalview.analysis.GeneticCodeI;
+import jalview.analysis.GeneticCodes;
 import jalview.api.SplitContainerI;
 import jalview.bin.Cache;
 import jalview.gui.JvSwingUtils;
@@ -137,7 +139,7 @@ public class GAlignFrame extends JInternalFrame
 
   protected JCheckBoxMenuItem showDbRefsMenuitem = new JCheckBoxMenuItem();
 
-  protected JMenuItem showTranslation = new JMenuItem();
+  protected JMenu showTranslation = new JMenu();
 
   protected JMenuItem showReverse = new JMenuItem();
 
@@ -1221,16 +1223,33 @@ public class GAlignFrame extends JInternalFrame
         vamsasStore_actionPerformed(e);
       }
     });
-    showTranslation
-            .setText(MessageManager.getString("label.translate_cDNA"));
-    showTranslation.addActionListener(new ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent e)
+
+    /*
+     * Translate as cDNA with sub-menu of translation tables
+     */
+    showTranslation.setText(MessageManager
+            .getString("label.translate_cDNA"));
+    boolean first = true;
+    for (final GeneticCodeI table : GeneticCodes.getInstance()
+            .getCodeTables())
+    {
+      JMenuItem item = new JMenuItem(table.getId() + " " + table.getName());
+      showTranslation.add(item);
+      item.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          showTranslation_actionPerformed(table);
+        }
+      });
+      if (first)
       {
-        showTranslation_actionPerformed(e);
+        showTranslation.addSeparator();
       }
-    });
+      first = false;
+    }
+
     showReverse.setText(MessageManager.getString("label.reverse"));
     showReverse.addActionListener(new ActionListener()
     {
@@ -2440,7 +2459,7 @@ public class GAlignFrame extends JInternalFrame
 
   }
 
-  public void showTranslation_actionPerformed(ActionEvent e)
+  public void showTranslation_actionPerformed(GeneticCodeI codeTable)
   {
 
   }
diff --git a/src/jalview/jbgui/GDasSourceBrowser.java b/src/jalview/jbgui/GDasSourceBrowser.java
deleted file mode 100755 (executable)
index a91769a..0000000
+++ /dev/null
@@ -1,256 +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.jbgui;
-
-import jalview.util.MessageManager;
-
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.Font;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-import javax.swing.BorderFactory;
-import javax.swing.JButton;
-import javax.swing.JEditorPane;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JPanel;
-import javax.swing.JProgressBar;
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.JTextField;
-import javax.swing.SwingConstants;
-import javax.swing.border.TitledBorder;
-import javax.swing.event.HyperlinkEvent;
-import javax.swing.event.HyperlinkListener;
-
-public class GDasSourceBrowser extends JPanel
-{
-  public GDasSourceBrowser()
-  {
-    try
-    {
-      jbInit();
-    } catch (Exception ex)
-    {
-      ex.printStackTrace();
-    }
-  }
-
-  private void jbInit() throws Exception
-  {
-    this.setLayout(gridBagLayout1);
-    refresh.setText(
-            MessageManager.getString("label.refresh_available_sources"));
-    refresh.addActionListener(new ActionListener()
-    {
-      public void actionPerformed(ActionEvent e)
-      {
-        refresh_actionPerformed(e);
-      }
-    });
-    progressBar.setPreferredSize(new Dimension(450, 20));
-    progressBar.setString("");
-    scrollPane.setBorder(titledBorder1);
-    scrollPane.setBorder(BorderFactory.createEtchedBorder());
-    fullDetailsScrollpane.setBorder(BorderFactory.createEtchedBorder());
-    fullDetails.addHyperlinkListener(new HyperlinkListener()
-    {
-      public void hyperlinkUpdate(HyperlinkEvent e)
-      {
-        fullDetails_hyperlinkUpdate(e);
-      }
-    });
-    fullDetails.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    fullDetails.setEditable(false);
-    registryLabel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    registryLabel.setHorizontalAlignment(SwingConstants.TRAILING);
-    registryLabel.setText(MessageManager.getString("label.use_registry"));
-    addLocal.setText(MessageManager.getString("label.add_local_source"));
-    addLocal.addActionListener(new ActionListener()
-    {
-      public void actionPerformed(ActionEvent e)
-      {
-        amendLocal(true);
-      }
-    });
-    jPanel1.setLayout(flowLayout1);
-    jPanel1.setMinimumSize(new Dimension(596, 30));
-    jPanel1.setPreferredSize(new Dimension(596, 30));
-    jScrollPane2.setBorder(titledBorder3);
-    jScrollPane3.setBorder(titledBorder4);
-    jScrollPane4.setBorder(titledBorder5);
-    titledBorder2
-            .setTitleFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    titledBorder3
-            .setTitleFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    titledBorder4
-            .setTitleFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    filter1.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    filter2.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    filter3.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    table.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    reset.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    reset.setMargin(new Insets(2, 2, 2, 2));
-    reset.setText(MessageManager.getString("action.reset"));
-    reset.addActionListener(new ActionListener()
-    {
-      public void actionPerformed(ActionEvent e)
-      {
-        reset_actionPerformed(e);
-      }
-    });
-    jPanel2.setLayout(borderLayout1);
-    borderLayout1.setHgap(5);
-    registryURL.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    scrollPane.getViewport().add(table);
-    fullDetailsScrollpane.getViewport().add(fullDetails);
-    jScrollPane3.getViewport().add(filter2);
-    jScrollPane4.getViewport().add(filter3);
-    jPanel1.add(refresh, null);
-    jPanel1.add(addLocal, null);
-    jPanel1.add(progressBar, null);
-    jScrollPane2.getViewport().add(filter1);
-    this.add(jPanel1, new GridBagConstraints(0, 3, 3, 1, 1.0, 1.0,
-            GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
-            new Insets(0, 0, 0, 0), 0, 0));
-    this.add(fullDetailsScrollpane,
-            new GridBagConstraints(1, 0, 2, 1, 1.0, 1.0,
-                    GridBagConstraints.CENTER, GridBagConstraints.BOTH,
-                    new Insets(3, 0, 0, 3), 240, 130));
-    this.add(scrollPane,
-            new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0,
-                    GridBagConstraints.CENTER, GridBagConstraints.BOTH,
-                    new Insets(3, 2, 0, 0), 150, 130));
-    jPanel2.add(registryLabel, java.awt.BorderLayout.WEST);
-    jPanel2.add(registryURL, java.awt.BorderLayout.CENTER);
-    jPanel2.add(reset, java.awt.BorderLayout.EAST);
-    this.add(jPanel2, new GridBagConstraints(0, 2, 3, 1, 0.0, 0.0,
-            GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
-            new Insets(5, 10, 0, 10), 339, 0));
-    this.add(jScrollPane2,
-            new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0,
-                    GridBagConstraints.CENTER, GridBagConstraints.BOTH,
-                    new Insets(0, 0, 0, 60), 80, 60));
-    this.add(jScrollPane4,
-            new GridBagConstraints(2, 1, 1, 1, 1.0, 1.0,
-                    GridBagConstraints.CENTER, GridBagConstraints.BOTH,
-                    new Insets(0, -80, 0, 0), 80, 60));
-    this.add(jScrollPane3,
-            new GridBagConstraints(1, 1, 1, 1, 1.0, 1.0,
-                    GridBagConstraints.CENTER, GridBagConstraints.BOTH,
-                    new Insets(0, -60, 0, 80), 80, 60));
-  }
-
-  protected JTable table = new JTable();
-
-  protected JEditorPane fullDetails = new JEditorPane("text/html", "");
-
-  TitledBorder titledBorder1 = new TitledBorder(
-          MessageManager.getString("label.available_das_sources"));
-
-  protected JButton refresh = new JButton();
-
-  protected JProgressBar progressBar = new JProgressBar();
-
-  protected JScrollPane scrollPane = new JScrollPane();
-
-  TitledBorder titledBorder2 = new TitledBorder(
-          MessageManager.getString("label.full_details"));
-
-  protected JScrollPane fullDetailsScrollpane = new JScrollPane();
-
-  protected JList filter1 = new JList();
-
-  protected JList filter2 = new JList();
-
-  protected JList filter3 = new JList();
-
-  JScrollPane jScrollPane2 = new JScrollPane();
-
-  JScrollPane jScrollPane3 = new JScrollPane();
-
-  JScrollPane jScrollPane4 = new JScrollPane();
-
-  protected JTextField registryURL = new JTextField();
-
-  protected JLabel registryLabel = new JLabel();
-
-  protected JButton addLocal = new JButton();
-
-  JPanel jPanel1 = new JPanel();
-
-  FlowLayout flowLayout1 = new FlowLayout();
-
-  GridBagLayout gridBagLayout1 = new GridBagLayout();
-
-  TitledBorder titledBorder3 = new TitledBorder(
-          MessageManager.getString("label.authority") + ":");
-
-  TitledBorder titledBorder4 = new TitledBorder(
-          MessageManager.getString("label.type") + ":");
-
-  TitledBorder titledBorder5 = new TitledBorder(
-          MessageManager.getString("label.label") + ":");
-
-  JButton reset = new JButton();
-
-  JPanel jPanel2 = new JPanel();
-
-  BorderLayout borderLayout1 = new BorderLayout();
-
-  public void refresh_actionPerformed(ActionEvent e)
-  {
-
-  }
-
-  public void fullDetails_hyperlinkUpdate(HyperlinkEvent e)
-  {
-    try
-    {
-
-      if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
-      {
-        jalview.util.BrowserLauncher.openURL(e.getURL().toString());
-      }
-    } catch (Exception ex)
-    {
-      System.out.println(e.getURL());
-      ex.printStackTrace();
-    }
-  }
-
-  public void amendLocal(boolean newSource)
-  {
-
-  }
-
-  public void reset_actionPerformed(ActionEvent e)
-  {
-
-  }
-
-}
index 1ea4ab5..b433570 100755 (executable)
@@ -47,41 +47,20 @@ import javax.swing.text.JTextComponent;
 
 public class GFinder extends JPanel
 {
-  JLabel jLabelFind = new JLabel();
+  private static final java.awt.Font VERDANA_12 = new java.awt.Font("Verdana", 0,
+          12);
 
-  protected JButton findAll = new JButton();
-
-  protected JButton findNext = new JButton();
-
-  JPanel actionsPanel = new JPanel();
-
-  GridLayout gridLayout1 = new GridLayout();
+  private static final String FINDER_CACHE_KEY = "CACHE.FINDER";
 
   protected JButton createFeatures = new JButton();
 
-  protected JvCacheableInputBox<String> searchBox = new JvCacheableInputBox<String>(
+  protected JvCacheableInputBox<String> searchBox = new JvCacheableInputBox<>(
           getCacheKey());
 
-  BorderLayout mainBorderLayout = new BorderLayout();
-
-  JPanel jPanel2 = new JPanel();
-
-  JPanel jPanel3 = new JPanel();
-
-  JPanel jPanel4 = new JPanel();
-
-  BorderLayout borderLayout2 = new BorderLayout();
-
-  JPanel jPanel6 = new JPanel();
-
   protected JCheckBox caseSensitive = new JCheckBox();
 
   protected JCheckBox searchDescription = new JCheckBox();
 
-  GridLayout optionsGridLayout = new GridLayout();
-
-  private static final String FINDER_CACHE_KEY = "CACHE.FINDER";
-
   public GFinder()
   {
     try
@@ -95,35 +74,47 @@ public class GFinder extends JPanel
 
   private void jbInit() throws Exception
   {
-    jLabelFind.setFont(new java.awt.Font("Verdana", 0, 12));
-    jLabelFind.setText(MessageManager.getString("label.find"));
+    BorderLayout mainBorderLayout = new BorderLayout();
     this.setLayout(mainBorderLayout);
-    findAll.setFont(new java.awt.Font("Verdana", 0, 12));
-    findAll.setText(MessageManager.getString("action.find_all"));
+    mainBorderLayout.setHgap(5);
+    mainBorderLayout.setVgap(5);
+
+    JLabel jLabelFind = new JLabel(MessageManager.getString("label.find"));
+    jLabelFind.setFont(VERDANA_12);
+
+    JButton findAll = new JButton(
+            MessageManager.getString("action.find_all"));
+    findAll.setFont(VERDANA_12);
     findAll.addActionListener(new java.awt.event.ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        findAll_actionPerformed(e);
+        findAll_actionPerformed();
       }
     });
-    findNext.setFont(new java.awt.Font("Verdana", 0, 12));
-    findNext.setText(MessageManager.getString("action.find_next"));
+
+    JButton findNext = new JButton(
+            MessageManager.getString("action.find_next"));
+    findNext.setFont(VERDANA_12);
     findNext.addActionListener(new java.awt.event.ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        findNext_actionPerformed(e);
+        findNext_actionPerformed();
       }
     });
+
+    JPanel actionsPanel = new JPanel();
+    GridLayout gridLayout1 = new GridLayout();
     actionsPanel.setLayout(gridLayout1);
     gridLayout1.setHgap(0);
     gridLayout1.setRows(3);
     gridLayout1.setVgap(2);
+
     createFeatures.setEnabled(false);
-    createFeatures.setFont(new java.awt.Font("Verdana", 0, 12));
+    createFeatures.setFont(VERDANA_12);
     createFeatures.setMargin(new Insets(0, 0, 0, 0));
     createFeatures.setText(MessageManager.getString("label.new_feature"));
     createFeatures.addActionListener(new java.awt.event.ActionListener()
@@ -141,7 +132,7 @@ public class GFinder extends JPanel
               @Override
               public void caretUpdate(CaretEvent e)
               {
-                textfield_caretUpdate(e);
+                textfield_caretUpdate();
               }
             });
     searchBox.getEditor().getEditorComponent()
@@ -153,11 +144,7 @@ public class GFinder extends JPanel
                 textfield_keyPressed(e);
               }
             });
-    mainBorderLayout.setHgap(5);
-    mainBorderLayout.setVgap(5);
-    jPanel4.setLayout(borderLayout2);
-    jPanel2.setPreferredSize(new Dimension(10, 1));
-    jPanel3.setPreferredSize(new Dimension(10, 1));
+
     caseSensitive.setHorizontalAlignment(SwingConstants.LEFT);
     caseSensitive.setText(MessageManager.getString("label.match_case"));
 
@@ -169,6 +156,13 @@ public class GFinder extends JPanel
     actionsPanel.add(createFeatures, null);
     this.add(jLabelFind, java.awt.BorderLayout.WEST);
     this.add(actionsPanel, java.awt.BorderLayout.EAST);
+
+    JPanel jPanel2 = new JPanel();
+    jPanel2.setPreferredSize(new Dimension(10, 1));
+    JPanel jPanel3 = new JPanel();
+    jPanel3.setPreferredSize(new Dimension(10, 1));
+    JPanel jPanel4 = new JPanel();
+    jPanel4.setLayout(new BorderLayout());
     this.add(jPanel2, java.awt.BorderLayout.SOUTH);
     this.add(jPanel3, java.awt.BorderLayout.NORTH);
     this.add(jPanel4, java.awt.BorderLayout.CENTER);
@@ -176,6 +170,7 @@ public class GFinder extends JPanel
 
     JPanel optionsPanel = new JPanel();
 
+    GridLayout optionsGridLayout = new GridLayout();
     optionsGridLayout.setHgap(0);
     optionsGridLayout.setRows(2);
     optionsGridLayout.setVgap(2);
@@ -193,16 +188,16 @@ public class GFinder extends JPanel
       if (!searchBox.isPopupVisible())
       {
         e.consume();
-        findNext_actionPerformed(null);
+        findNext_actionPerformed();
       }
     }
   }
 
-  protected void findNext_actionPerformed(ActionEvent e)
+  protected void findNext_actionPerformed()
   {
   }
 
-  protected void findAll_actionPerformed(ActionEvent e)
+  protected void findAll_actionPerformed()
   {
   }
 
@@ -210,9 +205,10 @@ public class GFinder extends JPanel
   {
   }
 
-  public void textfield_caretUpdate(CaretEvent e)
+  public void textfield_caretUpdate()
   {
-    if (searchBox.getUserInput().indexOf(">") > -1)
+    // disabled as appears to be running a non-functional
+    if (false && searchBox.getUserInput().indexOf(">") > -1)
     {
       SwingUtilities.invokeLater(new Runnable()
       {
@@ -233,7 +229,7 @@ public class GFinder extends JPanel
             str = jalview.analysis.AlignSeq.extractGaps(
                     jalview.util.Comparison.GapChars,
                     al.getSequenceAt(0).getSequenceAsString());
-
+            // todo and what? set str as searchBox text?
           }
         }
       });
index 5058d29..87cc87b 100755 (executable)
@@ -2186,7 +2186,7 @@ public class GPreferences extends JPanel
     setIntegerSpinner(backupfilesRollMaxSpinner, 1, 999, 4, true, c);
 
     backupfilesConfirmDelete.setLabels(
-            MessageManager.getString("label.confirm_delete"),
+            MessageManager.getString("label.always_ask"),
             MessageManager.getString("label.auto_delete"));
     // update the enabled section
     keepRollMaxOptionsEnabled();
@@ -2796,4 +2796,4 @@ class BackupFilesPresetsComboBoxRenderer extends DefaultListCellRenderer
 
     return this;
   }
-}
\ No newline at end of file
+}
index f772cf5..53e9a83 100644 (file)
@@ -5067,7 +5067,8 @@ public class Jalview2XML
           float min = safeFloat(safeFloat(setting.getMin()));
           float max = setting.getMax() == null ? 1f
                   : setting.getMax().floatValue();
-          FeatureColourI gc = new FeatureColour(minColour, maxColour,
+          FeatureColourI gc = new FeatureColour(maxColour, minColour,
+                  maxColour,
                   noValueColour, min, max);
           if (setting.getAttributeName().size() > 0)
           {
@@ -6562,7 +6563,7 @@ public class Jalview2XML
         noValueColour = maxcol;
       }
   
-      colour = new FeatureColour(mincol, maxcol, noValueColour,
+      colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
               safeFloat(colourModel.getMin()),
               safeFloat(colourModel.getMax()));
       final List<String> attributeName = colourModel.getAttributeName();
index c28ea5f..c74fdbc 100755 (executable)
@@ -185,7 +185,7 @@ public class AnnotationColourGradient extends FollowerColourScheme
       }
       else
       {
-        seqannot = new IdentityHashMap<SequenceI, AlignmentAnnotation>();
+        seqannot = new IdentityHashMap<>();
       }
       // resolve the context containing all the annotation for the sequence
       AnnotatedCollectionI alcontext = alignment instanceof AlignmentI
@@ -414,14 +414,17 @@ public class AnnotationColourGradient extends FollowerColourScheme
             && aboveAnnotationThreshold == ABOVE_THRESHOLD
             && value >= ann.threshold.value)
     {
-      range = (value - ann.threshold.value)
+      range = ann.graphMax == ann.threshold.value ? 1f
+              : (value - ann.threshold.value)
               / (ann.graphMax - ann.threshold.value);
     }
     else if (thresholdIsMinMax && ann.threshold != null
             && aboveAnnotationThreshold == BELOW_THRESHOLD
             && value <= ann.threshold.value)
     {
-      range = (value - ann.graphMin) / (ann.threshold.value - ann.graphMin);
+      range = ann.graphMin == ann.threshold.value ? 0f
+              : (value - ann.graphMin)
+                      / (ann.threshold.value - ann.graphMin);
     }
     else
     {
index f34478c..6483b85 100644 (file)
@@ -25,6 +25,7 @@ import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.features.FeatureMatcher;
 import jalview.util.ColorUtils;
 import jalview.util.Format;
+import jalview.util.MessageManager;
 
 import java.awt.Color;
 import java.util.StringTokenizer;
@@ -50,6 +51,12 @@ import java.util.StringTokenizer;
  */
 public class FeatureColour implements FeatureColourI
 {
+  private static final String I18N_LABEL = MessageManager
+          .getString("label.label");
+
+  private static final String I18N_SCORE = MessageManager
+          .getString("label.score");
+
   private static final String ABSOLUTE = "abso";
 
   private static final String ABOVE = "above";
@@ -358,8 +365,8 @@ public class FeatureColour implements FeatureColourI
       Color maxColour = ColorUtils.parseColourString(maxcol);
       Color noColour = noValueColour.equals(NO_VALUE_MAX) ? maxColour
               : (noValueColour.equals(NO_VALUE_NONE) ? null : minColour);
-      featureColour = new FeatureColour(minColour, maxColour, noColour, min,
-              max);
+      featureColour = new FeatureColour(maxColour, minColour, maxColour,
+              noColour, min, max);
       featureColour.setColourByLabel(minColour == null);
       featureColour.setAutoScaled(autoScaled);
       if (byAttribute)
@@ -429,36 +436,25 @@ public class FeatureColour implements FeatureColourI
   }
 
   /**
-   * Constructor given a simple colour
+   * Constructor given a simple colour. This also 'primes' a graduated colour
+   * range, where the maximum colour is the given simple colour, and the minimum
+   * colour a paler shade of it. This is for convenience when switching from a
+   * simple colour to a graduated colour scheme.
    * 
    * @param c
    */
   public FeatureColour(Color c)
   {
-    minColour = Color.WHITE;
-    maxColour = Color.BLACK;
-    noColour = DEFAULT_NO_COLOUR;
-    minRed = 0f;
-    minGreen = 0f;
-    minBlue = 0f;
-    deltaRed = 0f;
-    deltaGreen = 0f;
-    deltaBlue = 0f;
-    colour = c;
-  }
+    /*
+     * set max colour to the simple colour, min colour to a paler shade of it
+     */
+    this(c, c == null ? Color.white : ColorUtils.bleachColour(c, 0.9f),
+            c == null ? Color.black : c, DEFAULT_NO_COLOUR, 0, 0);
 
-  /**
-   * Constructor given a colour range and a score range, defaulting 'no value
-   * colour' to be the same as minimum colour
-   * 
-   * @param low
-   * @param high
-   * @param min
-   * @param max
-   */
-  public FeatureColour(Color low, Color high, float min, float max)
-  {
-    this(low, high, low, min, max);
+    /*
+     * but enforce simple colour for now!
+     */
+    setGraduatedColour(false);
   }
 
   /**
@@ -491,29 +487,23 @@ public class FeatureColour implements FeatureColourI
   }
 
   /**
-   * Copy constructor with new min/max ranges
-   * 
-   * @param fc
-   * @param min
-   * @param max
-   */
-  public FeatureColour(FeatureColour fc, float min, float max)
-  {
-    this(fc);
-    updateBounds(min, max);
-  }
-
-  /**
-   * Constructor for a graduated colour
+   * Constructor that sets both simple and graduated colour values. This allows
+   * alternative colour schemes to be 'preserved' while switching between them
+   * to explore their effects on the visualisation.
+   * <p>
+   * This sets the colour scheme to 'graduated' by default. Override this if
+   * wanted by calling <code>setGraduatedColour(false)</code> for a simple
+   * colour, or <code>setColourByLabel(true)</code> for colour by label.
    * 
+   * @param myColour
    * @param low
    * @param high
    * @param noValueColour
    * @param min
    * @param max
    */
-  public FeatureColour(Color low, Color high, Color noValueColour,
-          float min, float max)
+  public FeatureColour(Color myColour, Color low, Color high,
+          Color noValueColour, float min, float max)
   {
     if (low == null)
     {
@@ -523,10 +513,10 @@ public class FeatureColour implements FeatureColourI
     {
       high = Color.black;
     }
-    graduatedColour = true;
-    colour = null;
+    colour = myColour;
     minColour = low;
     maxColour = high;
+    setGraduatedColour(true);
     noColour = noValueColour;
     threshold = Float.NaN;
     isHighToLow = min >= max;
@@ -558,7 +548,7 @@ public class FeatureColour implements FeatureColourI
    * Sets the 'graduated colour' flag. If true, also sets 'colour by label' to
    * false.
    */
-  void setGraduatedColour(boolean b)
+  public void setGraduatedColour(boolean b)
   {
     graduatedColour = b;
     if (b)
@@ -833,9 +823,20 @@ public class FeatureColour implements FeatureColourI
         sb.append(BAR).append(Format.getHexString(getMinColour()))
                 .append(BAR);
         sb.append(Format.getHexString(getMaxColour())).append(BAR);
-        String noValue = minColour.equals(noColour) ? NO_VALUE_MIN
-                : (maxColour.equals(noColour) ? NO_VALUE_MAX
-                        : NO_VALUE_NONE);
+        
+        /*
+         * 'no value' colour should be null, min or max colour;
+         * if none of these, coerce to minColour
+         */
+        String noValue = NO_VALUE_MIN;
+        if (maxColour.equals(noColour))
+        {
+          noValue = NO_VALUE_MAX;
+        }
+        if (noColour == null)
+        {
+          noValue = NO_VALUE_NONE;
+        }
         sb.append(noValue).append(BAR);
         if (!isAutoScaled())
         {
@@ -921,4 +922,50 @@ public class FeatureColour implements FeatureColourI
             || (isBelowThreshold() && scr >= threshold));
   }
 
+  @Override
+  public String getDescription()
+  {
+    if (isSimpleColour())
+    {
+      return "r=" + colour.getRed() + ",g=" + colour.getGreen() + ",b="
+              + colour.getBlue();
+    }
+    StringBuilder tt = new StringBuilder();
+    String by = null;
+
+    if (getAttributeName() != null)
+    {
+      by = FeatureMatcher.toAttributeDisplayName(getAttributeName());
+    }
+    else if (isColourByLabel())
+    {
+      by = I18N_LABEL;
+    }
+    else
+    {
+      by = I18N_SCORE;
+    }
+    tt.append(MessageManager.formatMessage("action.by_title_param", by));
+
+    /*
+     * add threshold if any
+     */
+    if (isAboveThreshold() || isBelowThreshold())
+    {
+      tt.append(" (");
+      if (isColourByLabel())
+      {
+        /*
+         * Jalview features file supports the combination of 
+         * colour by label or attribute text with score threshold
+         */
+        tt.append(I18N_SCORE).append(" ");
+      }
+      tt.append(isAboveThreshold() ? "> " : "< ");
+      tt.append(getThreshold()).append(")");
+    }
+
+    return tt.toString();
+  }
+
 }
index 18b11c1..d435065 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.schemes;
 
+import jalview.analysis.GeneticCodes;
+
 import java.awt.Color;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -502,260 +504,6 @@ public class ResidueProperties
 
   public static String START = "ATG";
 
-  /**
-   * Nucleotide Ambiguity Codes
-   */
-  public static final Map<String, String[]> ambiguityCodes = new Hashtable<>();
-
-  /**
-   * Codon triplets with additional symbols for unambiguous codons that include
-   * ambiguity codes
-   */
-  public static final Hashtable<String, String> codonHash2 = new Hashtable<>();
-
-  /**
-   * all ambiguity codes for a given base
-   */
-  public final static Hashtable<String, List<String>> _ambiguityCodes = new Hashtable<>();
-
-  static
-  {
-    /*
-     * Ambiguity codes as per http://www.chem.qmul.ac.uk/iubmb/misc/naseq.html
-     */
-    ambiguityCodes.put("R", new String[] { "A", "G" });
-    ambiguityCodes.put("Y", new String[] { "T", "C" });
-    ambiguityCodes.put("W", new String[] { "A", "T" });
-    ambiguityCodes.put("S", new String[] { "G", "C" });
-    ambiguityCodes.put("M", new String[] { "A", "C" });
-    ambiguityCodes.put("K", new String[] { "G", "T" });
-    ambiguityCodes.put("H", new String[] { "A", "T", "C" });
-    ambiguityCodes.put("B", new String[] { "G", "T", "C" });
-    ambiguityCodes.put("V", new String[] { "G", "A", "C" });
-    ambiguityCodes.put("D", new String[] { "G", "A", "T" });
-    ambiguityCodes.put("N", new String[] { "G", "A", "T", "C" });
-
-    // Now build codon translation table
-    codonHash2.put("AAA", "K");
-    codonHash2.put("AAG", "K");
-    codonHash2.put("AAC", "N");
-    codonHash2.put("AAT", "N");
-
-    codonHash2.put("CAA", "Q");
-    codonHash2.put("CAG", "Q");
-    codonHash2.put("CAC", "H");
-    codonHash2.put("CAT", "H");
-
-    codonHash2.put("GAA", "E");
-    codonHash2.put("GAG", "E");
-    codonHash2.put("GAC", "D");
-    codonHash2.put("GAT", "D");
-
-    codonHash2.put("TAC", "Y");
-    codonHash2.put("TAT", "Y");
-
-    codonHash2.put("ACA", "T");
-    codonHash2.put("ACC", "T");
-    codonHash2.put("ACT", "T");
-    codonHash2.put("ACG", "T");
-
-    codonHash2.put("CCA", "P");
-    codonHash2.put("CCG", "P");
-    codonHash2.put("CCC", "P");
-    codonHash2.put("CCT", "P");
-
-    codonHash2.put("GCA", "A");
-    codonHash2.put("GCG", "A");
-    codonHash2.put("GCC", "A");
-    codonHash2.put("GCT", "A");
-
-    codonHash2.put("TCA", "S");
-    codonHash2.put("TCG", "S");
-    codonHash2.put("TCC", "S");
-    codonHash2.put("TCT", "S");
-    codonHash2.put("AGC", "S");
-    codonHash2.put("AGT", "S");
-
-    codonHash2.put("AGA", "R");
-    codonHash2.put("AGG", "R");
-    codonHash2.put("CGA", "R");
-    codonHash2.put("CGG", "R");
-    codonHash2.put("CGC", "R");
-    codonHash2.put("CGT", "R");
-
-    codonHash2.put("GGA", "G");
-    codonHash2.put("GGG", "G");
-    codonHash2.put("GGC", "G");
-    codonHash2.put("GGT", "G");
-
-    codonHash2.put("TGA", "*");
-    codonHash2.put("TAA", "*");
-    codonHash2.put("TAG", "*");
-
-    codonHash2.put("TGG", "W");
-
-    codonHash2.put("TGC", "C");
-    codonHash2.put("TGT", "C");
-
-    codonHash2.put("ATA", "I");
-    codonHash2.put("ATC", "I");
-    codonHash2.put("ATT", "I");
-
-    codonHash2.put("ATG", "M");
-
-    codonHash2.put("CTA", "L");
-    codonHash2.put("CTG", "L");
-    codonHash2.put("CTC", "L");
-    codonHash2.put("CTT", "L");
-    codonHash2.put("TTA", "L");
-    codonHash2.put("TTG", "L");
-
-    codonHash2.put("GTA", "V");
-    codonHash2.put("GTG", "V");
-    codonHash2.put("GTC", "V");
-    codonHash2.put("GTT", "V");
-
-    codonHash2.put("TTC", "F");
-    codonHash2.put("TTT", "F");
-
-    buildAmbiguityCodonSet();
-  }
-
-  /**
-   * programmatic generation of codons including ambiguity codes
-   */
-  public static void buildAmbiguityCodonSet()
-  {
-    if (_ambiguityCodes.size() > 0)
-    {
-      System.err
-              .println("Ignoring multiple calls to buildAmbiguityCodonSet");
-      return;
-    }
-    // Invert the ambiguity code set
-    for (Map.Entry<String, String[]> acode : ambiguityCodes.entrySet())
-    {
-      for (String r : acode.getValue())
-      {
-        List<String> codesfor = _ambiguityCodes.get(r);
-        if (codesfor == null)
-        {
-          _ambiguityCodes.put(r, codesfor = new ArrayList<>());
-        }
-        if (!codesfor.contains(acode.getKey()))
-        {
-          codesfor.add(acode.getKey());
-        }
-        else
-        {
-          System.err.println(
-                  "Inconsistency in the IUBMB ambiguity code nomenclature table: collision for "
-                          + acode.getKey() + " in residue " + r);
-        }
-      }
-    }
-    // and programmatically add in the ambiguity codes that yield the same amino
-    // acid
-    String[] unambcodons = codonHash2.keySet()
-            .toArray(new String[codonHash2.size()]);
-    for (String codon : unambcodons)
-    {
-      String residue = codonHash2.get(codon);
-      String acodon[][] = new String[codon.length()][];
-      for (int i = 0, iSize = codon.length(); i < iSize; i++)
-      {
-        String _ac = "" + codon.charAt(i);
-        List<String> acodes = _ambiguityCodes.get(_ac);
-        if (acodes != null)
-        {
-          acodon[i] = acodes.toArray(new String[acodes.size()]);
-        }
-        else
-        {
-          acodon[i] = new String[] {};
-        }
-      }
-      // enumerate all combinations and test for veracity of translation
-      int tpos[] = new int[codon.length()],
-              cpos[] = new int[codon.length()];
-      for (int i = 0; i < tpos.length; i++)
-      {
-        tpos[i] = -1;
-      }
-      tpos[acodon.length - 1] = 0;
-      int ipos, j;
-      while (tpos[0] < acodon[0].length)
-      {
-        // make all codons for this combination
-        char allres[][] = new char[tpos.length][];
-        String _acodon = "";
-        for (ipos = 0; ipos < tpos.length; ipos++)
-        {
-          if (acodon[ipos].length == 0 || tpos[ipos] < 0)
-          {
-            _acodon += codon.charAt(ipos);
-            allres[ipos] = new char[] { codon.charAt(ipos) };
-          }
-          else
-          {
-            _acodon += acodon[ipos][tpos[ipos]];
-            String[] altbase = ambiguityCodes.get(acodon[ipos][tpos[ipos]]);
-            allres[ipos] = new char[altbase.length];
-            j = 0;
-            for (String ab : altbase)
-            {
-              allres[ipos][j++] = ab.charAt(0);
-            }
-          }
-        }
-        // test all codons for this combination
-        for (ipos = 0; ipos < cpos.length; ipos++)
-        {
-          cpos[ipos] = 0;
-        }
-        boolean valid = true;
-        do
-        {
-          String _codon = "";
-          for (j = 0; j < cpos.length; j++)
-          {
-            _codon += allres[j][cpos[j]];
-          }
-          String tr = codonHash2.get(_codon);
-          if (valid = (tr != null && tr.equals(residue)))
-          {
-            // advance to next combination
-            ipos = acodon.length - 1;
-            while (++cpos[ipos] >= allres[ipos].length && ipos > 0)
-            {
-              cpos[ipos] = 0;
-              ipos--;
-            }
-          }
-        } while (valid && cpos[0] < allres[0].length);
-        if (valid)
-        {
-          // Add this to the set of codons we will translate
-          // System.out.println("Adding ambiguity codon: " + _acodon + " for "
-          // + residue);
-          codonHash2.put(_acodon, residue);
-        }
-        else
-        {
-          // System.err.println("Rejecting ambiguity codon: " + _acodon
-          // + " for " + residue);
-        }
-        // next combination
-        ipos = acodon.length - 1;
-        while (++tpos[ipos] >= acodon[ipos].length && ipos > 0)
-        {
-          tpos[ipos] = -1;
-          ipos--;
-        }
-      }
-    }
-  }
-
   // Stores residue codes/names and colours and other things
   public static Map<String, Map<String, Integer>> propHash = new Hashtable<>();
 
@@ -1148,12 +896,13 @@ public class ResidueProperties
 
   public static String codonTranslate(String lccodon)
   {
-    String cdn = codonHash2.get(lccodon.toUpperCase());
-    if ("*".equals(cdn))
+    String peptide = GeneticCodes.getInstance().getStandardCodeTable()
+            .translate(lccodon);
+    if ("*".equals(peptide))
     {
-      return STOP;
+      return "STOP";
     }
-    return cdn;
+    return peptide;
   }
 
   /*
index 50a34fc..5afbca5 100755 (executable)
@@ -43,9 +43,8 @@ public class DBRefUtils
   /*
    * lookup from lower-case form of a name to its canonical (standardised) form
    */
-  private static Map<String, String> canonicalSourceNameLookup = new HashMap<String, String>();
+  private static Map<String, String> canonicalSourceNameLookup = new HashMap<>();
 
-  private static Map<String, String> dasCoordinateSystemsLookup = new HashMap<String, String>();
 
   static
   {
@@ -73,10 +72,6 @@ public class DBRefUtils
               canonicalSourceNameLookup.get(k));
     }
 
-    dasCoordinateSystemsLookup.put("pdbresnum", DBRefSource.PDB);
-    dasCoordinateSystemsLookup.put("uniprot", DBRefSource.UNIPROT);
-    dasCoordinateSystemsLookup.put("embl", DBRefSource.EMBL);
-    // dasCoordinateSystemsLookup.put("embl", DBRefSource.EMBLCDS);
   }
 
   /**
@@ -97,13 +92,13 @@ public class DBRefUtils
     {
       return dbrefs;
     }
-    HashSet<String> srcs = new HashSet<String>();
+    HashSet<String> srcs = new HashSet<>();
     for (String src : sources)
     {
       srcs.add(src.toUpperCase());
     }
 
-    List<DBRefEntry> res = new ArrayList<DBRefEntry>();
+    List<DBRefEntry> res = new ArrayList<>();
     for (DBRefEntry dbr : dbrefs)
     {
       String source = getCanonicalName(dbr.getSource());
@@ -122,29 +117,6 @@ public class DBRefUtils
   }
 
   /**
-   * isDasCoordinateSystem
-   * 
-   * @param string
-   *          String
-   * @param dBRefEntry
-   *          DBRefEntry
-   * @return boolean true if Source DBRefEntry is compatible with DAS
-   *         CoordinateSystem name
-   */
-
-  public static boolean isDasCoordinateSystem(String string,
-          DBRefEntry dBRefEntry)
-  {
-    if (string == null || dBRefEntry == null)
-    {
-      return false;
-    }
-    String coordsys = dasCoordinateSystemsLookup.get(string.toLowerCase());
-    return coordsys == null ? false
-            : coordsys.equals(dBRefEntry.getSource());
-  }
-
-  /**
    * look up source in an internal list of database reference sources and return
    * the canonical jalview name for the source, or the original string if it has
    * no canonical form.
@@ -218,7 +190,7 @@ public class DBRefUtils
   static List<DBRefEntry> searchRefs(DBRefEntry[] refs, DBRefEntry entry,
           DbRefComp comparator)
   {
-    List<DBRefEntry> rfs = new ArrayList<DBRefEntry>();
+    List<DBRefEntry> rfs = new ArrayList<>();
     if (refs == null || entry == null)
     {
       return rfs;
@@ -594,7 +566,7 @@ public class DBRefUtils
   public static List<DBRefEntry> searchRefsForSource(DBRefEntry[] dbRefs,
           String source)
   {
-    List<DBRefEntry> matches = new ArrayList<DBRefEntry>();
+    List<DBRefEntry> matches = new ArrayList<>();
     if (dbRefs != null && source != null)
     {
       for (DBRefEntry dbref : dbRefs)
@@ -644,7 +616,7 @@ public class DBRefUtils
       // nothing to do
       return;
     }
-    List<DBRefEntry> selfs = new ArrayList<DBRefEntry>();
+    List<DBRefEntry> selfs = new ArrayList<>();
     {
       DBRefEntry[] selfArray = selectDbRefs(!sequence.isProtein(),
               sequence.getDBRefs());
@@ -664,11 +636,11 @@ public class DBRefUtils
         selfs.remove(p);
       }
     }
-    List<DBRefEntry> toPromote = new ArrayList<DBRefEntry>();
+    List<DBRefEntry> toPromote = new ArrayList<>();
 
     for (DBRefEntry p : pr)
     {
-      List<String> promType = new ArrayList<String>();
+      List<String> promType = new ArrayList<>();
       if (sequence.isProtein())
       {
         switch (getCanonicalName(p.getSource()))
index 691e492..6f817bb 100644 (file)
@@ -97,7 +97,7 @@ public class ViewportRanges extends ViewportProperties
    */
   public int getVisibleAlignmentWidth()
   {
-    return al.getWidth() - al.getHiddenColumns().getSize();
+    return al.getVisibleWidth();
   }
 
   /**
index 335529c..78c6da2 100644 (file)
@@ -118,7 +118,10 @@ public class ConsensusThread extends AlignCalcWorker
   protected void eraseConsensus(int aWidth)
   {
     AlignmentAnnotation consensus = getConsensusAnnotation();
-    consensus.annotations = new Annotation[aWidth];
+    if (consensus != null)
+    {
+      consensus.annotations = new Annotation[aWidth];
+    }
     AlignmentAnnotation gap = getGapAnnotation();
     if (gap != null)
     {
index 41e4d0d..ae4207b 100644 (file)
@@ -755,8 +755,6 @@ public class DBRefFetcher implements Runnable
         // and remove it from the rest
         // TODO: decide if we should remove annotated sequence from set
         sdataset.remove(sequence);
-        // TODO: should we make a note of sequences that have received new DB
-        // ids, so we can query all enabled DAS servers for them ?
       }
     }
     return modified;
index 9a2316c..a1b8e7a 100644 (file)
@@ -344,8 +344,9 @@ public class AADisorderClient extends JabawsCalcWorker
             {
               // set graduated color as fading to white for minimum, and
               // autoscaling to values on alignment
-              FeatureColourI ggc = new FeatureColour(Color.white,
-                      gc.getColour(), Float.MIN_VALUE, Float.MAX_VALUE);
+              FeatureColourI ggc = new FeatureColour(gc.getColour(),
+                      Color.white, gc.getColour(), Color.white,
+                      Float.MIN_VALUE, Float.MAX_VALUE);
               ggc.setAutoScaled(true);
               fr.setColour(ft, ggc);
             }
index 837e970..bd827f9 100644 (file)
@@ -52,6 +52,7 @@ public class AlignSeqTest
     assertEquals(AlignSeq.extractGaps(" -", " AC-G.T"), "ACG.T");
     assertEquals(AlignSeq.extractGaps(" -.", " AC-G.T ."), "ACGT");
     assertEquals(AlignSeq.extractGaps("-", " AC-G.T"), " ACG.T");
+    assertEquals(AlignSeq.extractGaps("-. ", " -. .-"), "");
   }
 
   @Test(groups = { "Functional" })
index 6a31b31..27ae8cd 100644 (file)
@@ -139,7 +139,8 @@ public class DnaTest
     Iterator<int[]> contigs = cs.getVisContigsIterator(0, alf.getWidth(),
             false);
     Dna dna = new Dna(av, contigs);
-    AlignmentI translated = dna.translateCdna();
+    AlignmentI translated = dna.translateCdna(GeneticCodes.getInstance()
+            .getStandardCodeTable());
     assertNotNull("Couldn't do a full width translation of test data.",
             translated);
   }
@@ -170,7 +171,8 @@ public class DnaTest
               alf.getWidth(), false);
       AlignViewportI av = new AlignViewport(alf, cs);
       Dna dna = new Dna(av, vcontigs);
-      AlignmentI transAlf = dna.translateCdna();
+      AlignmentI transAlf = dna.translateCdna(GeneticCodes.getInstance()
+              .getStandardCodeTable());
 
       assertTrue("Translation failed (ipos=" + ipos
               + ") No alignment data.", transAlf != null);
@@ -197,7 +199,8 @@ public class DnaTest
     Iterator<int[]> contigs = cs.getVisContigsIterator(0, alf.getWidth(),
             false);
     Dna dna = new Dna(av, contigs);
-    AlignmentI translated = dna.translateCdna();
+    AlignmentI translated = dna.translateCdna(GeneticCodes.getInstance()
+            .getStandardCodeTable());
     String aa = translated.getSequenceAt(0).getSequenceAsString();
     assertEquals(
             "AAAACCDDEEFFGGGGHHIIIKKLLLLLLMNNPPPPQQRRRRRRSSSSSSTTTTVVVVWYY***",
@@ -222,7 +225,8 @@ public class DnaTest
     Iterator<int[]> contigs = cs.getVisContigsIterator(0, alf.getWidth(),
             false);
     Dna dna = new Dna(av, contigs);
-    AlignmentI translated = dna.translateCdna();
+    AlignmentI translated = dna.translateCdna(GeneticCodes.getInstance()
+            .getStandardCodeTable());
     String aa = translated.getSequenceAt(0).getSequenceAsString();
     assertEquals("AACDDGGGGHHIIIKKLLLLLLMNNPPPPQQRRRRRRSSSSSSTTTTVVVVW", aa);
   }
@@ -309,7 +313,8 @@ public class DnaTest
     Iterator<int[]> contigs = cs.getVisContigsIterator(0, cdna.getWidth(),
             false);
     Dna dna = new Dna(av, contigs);
-    AlignmentI translated = dna.translateCdna();
+    AlignmentI translated = dna.translateCdna(GeneticCodes.getInstance()
+            .getStandardCodeTable());
 
     /*
      * Jumble the cDNA sequences and translate.
@@ -325,7 +330,8 @@ public class DnaTest
     av = new AlignViewport(cdnaReordered, cs);
     contigs = cs.getVisContigsIterator(0, cdna.getWidth(), false);
     dna = new Dna(av, contigs);
-    AlignmentI translated2 = dna.translateCdna();
+    AlignmentI translated2 = dna.translateCdna(GeneticCodes.getInstance()
+            .getStandardCodeTable());
 
     /*
      * Check translated sequences are the same in both alignments.
index d7a509f..e2a94ef 100644 (file)
@@ -24,21 +24,31 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertSame;
 import static org.testng.Assert.assertTrue;
 
+import jalview.api.AlignViewportI;
+import jalview.api.FinderI;
+import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceGroup;
 import jalview.gui.AlignFrame;
+import jalview.gui.AlignViewport;
 import jalview.gui.JvOptionPane;
 import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
 
 import java.util.List;
 
+import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import junit.extensions.PA;
+
 public class FinderTest
 {
   @BeforeClass(alwaysRun = true)
@@ -52,32 +62,56 @@ public class FinderTest
 
   private AlignmentI al;
 
+  private AlignViewportI av;
+
   @BeforeClass(groups = "Functional")
   public void setUp()
   {
-    String seqData = "seq1 ABCD--EF-GHI\n" + "seq2 A--BCDefHI\n"
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
+    Cache.applicationProperties.setProperty("PAD_GAPS",
+            Boolean.FALSE.toString());
+
+    String seqData = "seq1seq1/8-18 ABCD--EF-GHIJI\n" + "seq2 A--BCDefHI\n"
             + "seq3 --bcdEFH\n" + "seq4 aa---aMMMMMaaa\n";
     af = new FileLoader().LoadFileWaitTillLoaded(seqData,
             DataSourceType.PASTE);
-    al = af.getViewport().getAlignment();
+    av = af.getViewport();
+    al = av.getAlignment();
+  }
+
+  @AfterMethod
+  public void tearDownAfterTest()
+  {
+    av.setSelectionGroup(null);
   }
 
   /**
-   * Test for find all matches of a regular expression
+   * Test for find matches of a regular expression
    */
   @Test(groups = "Functional")
-  public void testFindAll_regex()
+  public void testFind_regex()
   {
-    Finder f = new Finder(al, null);
-    f.setFindAll(true);
-    f.find("E.H"); // 'E, any character, H'
+    /*
+     * find next match only
+     */
+    Finder f = new Finder(av);
+    f.findNext("E.H", false, false); // 'E, any character, H'
+    // should match seq2 efH only
+    SearchResultsI sr = f.getSearchResults();
+    assertEquals(sr.getSize(), 1);
+    List<SearchResultMatchI> matches = sr.getResults();
+    assertSame(matches.get(0).getSequence(), al.getSequenceAt(1));
+    assertEquals(matches.get(0).getStart(), 5);
+    assertEquals(matches.get(0).getEnd(), 7);
 
+    f = new Finder(av);
+    f.findAll("E.H", false, false); // 'E, any character, H'
     // should match seq2 efH and seq3 EFH
-    SearchResultsI sr = f.getSearchResults();
+    sr = f.getSearchResults();
     assertEquals(sr.getSize(), 2);
-    List<SearchResultMatchI> matches = sr.getResults();
-    assertSame(al.getSequenceAt(1), matches.get(0).getSequence());
-    assertSame(al.getSequenceAt(2), matches.get(1).getSequence());
+    matches = sr.getResults();
+    assertSame(matches.get(0).getSequence(), al.getSequenceAt(1));
+    assertSame(matches.get(1).getSequence(), al.getSequenceAt(2));
     assertEquals(matches.get(0).getStart(), 5);
     assertEquals(matches.get(0).getEnd(), 7);
     assertEquals(matches.get(1).getStart(), 4);
@@ -90,20 +124,40 @@ public class FinderTest
   @Test(groups = "Functional")
   public void testFind_residueNumber()
   {
-    Finder f = new Finder(al, null);
-    f.setFindAll(true);
-    f.find("9");
+    Finder f = new Finder(av);
 
-    // seq1 and seq4 have 9 residues; no match in other sequences
+    /*
+     * find first match should return seq1 residue 9
+     */
+    f.findNext("9", false, false);
     SearchResultsI sr = f.getSearchResults();
-    assertEquals(sr.getSize(), 2);
+    assertEquals(sr.getSize(), 1);
     List<SearchResultMatchI> matches = sr.getResults();
-    assertSame(al.getSequenceAt(0), matches.get(0).getSequence());
-    assertSame(al.getSequenceAt(3), matches.get(1).getSequence());
+    assertSame(matches.get(0).getSequence(), al.getSequenceAt(0));
+    assertEquals(matches.get(0).getStart(), 9);
+    assertEquals(matches.get(0).getEnd(), 9);
+
+    /*
+     * find all matches should return seq1 and seq4 (others are too short)
+     */
+    f = new Finder(av);
+    f.findAll("9", false, false);
+    sr = f.getSearchResults();
+    assertEquals(sr.getSize(), 2);
+    matches = sr.getResults();
+    assertSame(matches.get(0).getSequence(), al.getSequenceAt(0));
+    assertSame(matches.get(1).getSequence(), al.getSequenceAt(3));
     assertEquals(matches.get(0).getStart(), 9);
     assertEquals(matches.get(0).getEnd(), 9);
     assertEquals(matches.get(1).getStart(), 9);
     assertEquals(matches.get(1).getEnd(), 9);
+
+    /*
+     * parsing of search string as integer is strict
+     */
+    f = new Finder(av);
+    f.findNext(" 9", false, false);
+    assertTrue(f.getSearchResults().isEmpty());
   }
 
   /**
@@ -113,69 +167,84 @@ public class FinderTest
   public void testFindNext()
   {
     /*
-     * start at second sequence; resIndex of -1
+     * start at second sequence; colIndex of -1
      * means sequence id / description is searched
      */
-    Finder f = new Finder(al, null, 1, -1);
-    f.find("e"); // matches id
+    Finder f = new Finder(av);
+    PA.setValue(f, "sequenceIndex", 1);
+    PA.setValue(f, "columnIndex", -1);
+    f.findNext("e", false, false); // matches id
 
     assertTrue(f.getSearchResults().isEmpty());
-    assertEquals(f.getIdMatch().size(), 1);
-    assertSame(f.getIdMatch().get(0), al.getSequenceAt(1));
-
-    // resIndex is now 0 - for use in next find next
-    assertEquals(f.getResIndex(), 0);
-    f = new Finder(al, null, 1, 0);
-    f.find("e"); // matches in sequence
-    assertTrue(f.getIdMatch().isEmpty());
+    assertEquals(f.getIdMatches().size(), 1);
+    assertSame(f.getIdMatches().get(0), al.getSequenceAt(1));
+
+    // colIndex is now 0 - for use in next find next
+    // searching A--BCDefHI
+    assertEquals(PA.getValue(f, "columnIndex"), 0);
+    f = new Finder(av);
+    PA.setValue(f, "sequenceIndex", 1);
+    PA.setValue(f, "columnIndex", 0);
+    f.findNext("e", false, false); // matches in sequence
+    assertTrue(f.getIdMatches().isEmpty());
     assertEquals(f.getSearchResults().getSize(), 1);
     List<SearchResultMatchI> matches = f.getSearchResults().getResults();
     assertEquals(matches.get(0).getStart(), 5);
     assertEquals(matches.get(0).getEnd(), 5);
     assertSame(matches.get(0).getSequence(), al.getSequenceAt(1));
     // still in the second sequence
-    assertEquals(f.getSeqIndex(), 1);
-    // next residue position to search from is 5
-    // (used as base 0 by RegEx so the same as 6 if base 1)
-    assertEquals(f.getResIndex(), 5);
+    assertEquals(PA.getValue(f, "sequenceIndex"), 1);
+    // next column position to search from is 7
+    assertEquals(PA.getValue(f, "columnIndex"), 7);
 
     // find next from end of sequence - finds next sequence id
-    f = new Finder(al, null, 1, 5);
-    f.find("e");
-    assertEquals(f.getIdMatch().size(), 1);
-    assertSame(f.getIdMatch().get(0), al.getSequenceAt(2));
+    f = new Finder(av);
+    PA.setValue(f, "sequenceIndex", 1);
+    PA.setValue(f, "columnIndex", 7);
+    f.findNext("e", false, false);
+    assertEquals(f.getIdMatches().size(), 1);
+    assertSame(f.getIdMatches().get(0), al.getSequenceAt(2));
+    assertTrue(f.getSearchResults().isEmpty());
   }
 
   /**
    * Test for matching within sequence descriptions
    */
   @Test(groups = "Functional")
-  public void testFindAll_inDescription()
+  public void testFind_inDescription()
   {
     AlignmentI al2 = new Alignment(al);
     al2.getSequenceAt(0).setDescription("BRAF");
     al2.getSequenceAt(1).setDescription("braf");
-    Finder f = new Finder(al2, null);
-    f.setFindAll(true);
-    f.setIncludeDescription(true);
-
-    f.find("rAF");
-    assertEquals(f.getIdMatch().size(), 2);
-    assertSame(f.getIdMatch().get(0), al2.getSequenceAt(0));
-    assertSame(f.getIdMatch().get(1), al2.getSequenceAt(1));
+
+    AlignViewportI av2 = new AlignViewport(al2);
+
+    /*
+     * find first match only
+     */
+    Finder f = new Finder(av2);
+    f.findNext("rAF", false, true);
+    assertEquals(f.getIdMatches().size(), 1);
+    assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
     assertTrue(f.getSearchResults().isEmpty());
 
     /*
-     * case sensitive
+     * find all matches
      */
-    f = new Finder(al2, null);
-    f.setFindAll(true);
-    f.setCaseSensitive(true);
-    f.setIncludeDescription(true);
+    f = new Finder(av2);
+    f.findAll("rAF", false, true);
+    assertEquals(f.getIdMatches().size(), 2);
+    assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
+    assertSame(f.getIdMatches().get(1), al2.getSequenceAt(1));
+    assertTrue(f.getSearchResults().isEmpty());
 
-    f.find("RAF");
-    assertEquals(f.getIdMatch().size(), 1);
-    assertSame(f.getIdMatch().get(0), al2.getSequenceAt(0));
+    /*
+     * case sensitive
+     */
+    f = new Finder(av2);
+    f.findAll("RAF", true, true);
+    assertEquals(f.getIdMatches().size(), 1);
+    assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
     assertTrue(f.getSearchResults().isEmpty());
 
     /*
@@ -184,27 +253,25 @@ public class FinderTest
     al2.getSequenceAt(0).setDescription("the efh sequence");
     al2.getSequenceAt(0).setName("mouseEFHkinase");
     al2.getSequenceAt(1).setName("humanEFHkinase");
-    f = new Finder(al2, null);
-    f.setFindAll(true);
-    f.setIncludeDescription(true);
+    f = new Finder(av2);
 
     /*
      * sequence matches should have no duplicates
      */
-    f.find("EFH");
-    assertEquals(f.getIdMatch().size(), 2);
-    assertSame(f.getIdMatch().get(0), al2.getSequenceAt(0));
-    assertSame(f.getIdMatch().get(1), al2.getSequenceAt(1));
+    f.findAll("EFH", false, true);
+    assertEquals(f.getIdMatches().size(), 2);
+    assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
+    assertSame(f.getIdMatches().get(1), al2.getSequenceAt(1));
 
     assertEquals(f.getSearchResults().getSize(), 2);
     SearchResultMatchI match = f.getSearchResults().getResults().get(0);
-    assertSame(al2.getSequenceAt(1), match.getSequence());
-    assertEquals(5, match.getStart());
-    assertEquals(7, match.getEnd());
+    assertSame(match.getSequence(), al2.getSequenceAt(1));
+    assertEquals(match.getStart(), 5);
+    assertEquals(match.getEnd(), 7);
     match = f.getSearchResults().getResults().get(1);
-    assertSame(al2.getSequenceAt(2), match.getSequence());
-    assertEquals(4, match.getStart());
-    assertEquals(6, match.getEnd());
+    assertSame(match.getSequence(), al2.getSequenceAt(2));
+    assertEquals(match.getStart(), 4);
+    assertEquals(match.getEnd(), 6);
   }
 
   /**
@@ -213,105 +280,454 @@ public class FinderTest
   @Test(groups = "Functional")
   public void testFindAll_sequenceIds()
   {
-    Finder f = new Finder(al, null);
-    f.setFindAll(true);
+    Finder f = new Finder(av);
 
     /*
-     * case insensitive
+     * case insensitive; seq1 occurs twice in sequence id but
+     * only one match should be returned
      */
-    f.find("SEQ1");
-    assertEquals(f.getIdMatch().size(), 1);
-    assertSame(f.getIdMatch().get(0), al.getSequenceAt(0));
-    assertTrue(f.getSearchResults().isEmpty());
+    f.findAll("SEQ1", false, false);
+    assertEquals(f.getIdMatches().size(), 1);
+    assertSame(f.getIdMatches().get(0), al.getSequenceAt(0));
+    SearchResultsI searchResults = f.getSearchResults();
+    assertTrue(searchResults.isEmpty());
 
     /*
      * case sensitive
      */
-    f = new Finder(al, null);
-    f.setFindAll(true);
-    f.setCaseSensitive(true);
-    f.find("SEQ1");
-    assertTrue(f.getSearchResults().isEmpty());
+    f = new Finder(av);
+    f.findAll("SEQ1", true, false);
+    searchResults = f.getSearchResults();
+    assertTrue(searchResults.isEmpty());
 
     /*
      * match both sequence id and sequence
      */
     AlignmentI al2 = new Alignment(al);
+    AlignViewportI av2 = new AlignViewport(al2);
     al2.addSequence(new Sequence("aBz", "xyzabZpqrAbZ"));
-    f = new Finder(al2, null);
-    f.setFindAll(true);
-    f.find("ABZ");
-    assertEquals(f.getIdMatch().size(), 1);
-    assertSame(f.getIdMatch().get(0), al2.getSequenceAt(4));
-    assertEquals(f.getSearchResults().getSize(), 2);
-    SearchResultMatchI match = f.getSearchResults().getResults().get(0);
-    assertSame(al2.getSequenceAt(4), match.getSequence());
-    assertEquals(4, match.getStart());
-    assertEquals(6, match.getEnd());
-    match = f.getSearchResults().getResults().get(1);
-    assertSame(al2.getSequenceAt(4), match.getSequence());
-    assertEquals(10, match.getStart());
-    assertEquals(12, match.getEnd());
+    f = new Finder(av2);
+    f.findAll("ABZ", false, false);
+    assertEquals(f.getIdMatches().size(), 1);
+    assertSame(f.getIdMatches().get(0), al2.getSequenceAt(4));
+    searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 2);
+    SearchResultMatchI match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al2.getSequenceAt(4));
+    assertEquals(match.getStart(), 4);
+    assertEquals(match.getEnd(), 6);
+    match = searchResults.getResults().get(1);
+    assertSame(match.getSequence(), al2.getSequenceAt(4));
+    assertEquals(match.getStart(), 10);
+    assertEquals(match.getEnd(), 12);
   }
 
   /**
-   * Test finding all matches of a sequence pattern in an alignment
+   * Test finding next match of a sequence pattern in an alignment
    */
   @Test(groups = "Functional")
-  public void testFindAll_simpleMatch()
+  public void testFind_findNext()
   {
-    Finder f = new Finder(al, null);
-    f.setFindAll(true);
+    /*
+     * efh should be matched in seq2 only
+     */
+    FinderI f = new Finder(av);
+    f.findNext("EfH", false, false);
+    SearchResultsI searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 1);
+    SearchResultMatchI match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(1));
+    assertEquals(match.getStart(), 5);
+    assertEquals(match.getEnd(), 7);
 
     /*
-     * case insensitive first
+     * I should be found in seq1 (twice) and seq2 (once)
      */
-    f.find("EfH");
+    f = new Finder(av);
+    f.findNext("I", false, false); // find next: seq1/16
+    searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 1);
+    match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(0));
+    assertEquals(match.getStart(), 16);
+    assertEquals(match.getEnd(), 16);
+
+    f.findNext("I", false, false); // find next: seq1/18
+    searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 1);
+    match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(0));
+    assertEquals(match.getStart(), 18);
+    assertEquals(match.getEnd(), 18);
+
+    f.findNext("I", false, false); // find next: seq2/8
+    searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 1);
+    match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(1));
+    assertEquals(match.getStart(), 8);
+    assertEquals(match.getEnd(), 8);
+
+    f.findNext("I", false, false);
+    assertTrue(f.getSearchResults().isEmpty());
+
+    /*
+     * find should reset to start of alignment after a failed search
+     */
+    f.findNext("I", false, false); // find next: seq1/16
+    searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 1);
+    match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(0));
+    assertEquals(match.getStart(), 16);
+    assertEquals(match.getEnd(), 16);
+  }
+
+  /**
+   * Test for JAL-2302 to verify that sub-matches are not included in a find all
+   * result
+   */
+  @Test(groups = "Functional")
+  public void testFind_maximalResultOnly()
+  {
+    Finder f = new Finder(av);
+    f.findAll("M+", false, false);
+    SearchResultsI searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 1);
+    SearchResultMatchI match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(3));
+    assertEquals(match.getStart(), 4); // dataset sequence positions
+    assertEquals(match.getEnd(), 8); // base 1
+  }
+
+  /**
+   * Test finding all matches of a sequence pattern in an alignment
+   */
+  @Test(groups = "Functional")
+  public void testFind_findAll()
+  {
+    Finder f = new Finder(av);
+    f.findAll("EfH", false, false);
     SearchResultsI searchResults = f.getSearchResults();
     assertEquals(searchResults.getSize(), 2);
     SearchResultMatchI match = searchResults.getResults().get(0);
-    assertSame(al.getSequenceAt(1), match.getSequence());
-    assertEquals(5, match.getStart());
-    assertEquals(7, match.getEnd());
+    assertSame(match.getSequence(), al.getSequenceAt(1));
+    assertEquals(match.getStart(), 5);
+    assertEquals(match.getEnd(), 7);
     match = searchResults.getResults().get(1);
-    assertSame(al.getSequenceAt(2), match.getSequence());
-    assertEquals(4, match.getStart());
-    assertEquals(6, match.getEnd());
+    assertSame(match.getSequence(), al.getSequenceAt(2));
+    assertEquals(match.getStart(), 4);
+    assertEquals(match.getEnd(), 6);
 
     /*
-     * case sensitive
+     * find all I should find 2 positions in seq1, 1 in seq2
      */
-    f = new Finder(al, null);
-    f.setFindAll(true);
-    f.setCaseSensitive(true);
-    f.find("BC");
+    f.findAll("I", false, false);
     searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 3);
+    match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(0));
+    assertEquals(match.getStart(), 16);
+    assertEquals(match.getEnd(), 16);
+    match = searchResults.getResults().get(1);
+    assertSame(match.getSequence(), al.getSequenceAt(0));
+    assertEquals(match.getStart(), 18);
+    assertEquals(match.getEnd(), 18);
+    match = searchResults.getResults().get(2);
+    assertSame(match.getSequence(), al.getSequenceAt(1));
+    assertEquals(match.getStart(), 8);
+    assertEquals(match.getEnd(), 8);
+  }
+
+  /**
+   * Test finding all matches, case-sensitive
+   */
+  @Test(groups = "Functional")
+  public void testFind_findAllCaseSensitive()
+  {
+    Finder f = new Finder(av);
+
+    /*
+     * BC should match seq1/9-10 and seq2/2-3
+     */
+    f.findAll("BC", true, false);
+    SearchResultsI searchResults = f.getSearchResults();
     assertEquals(searchResults.getSize(), 2);
+    SearchResultMatchI match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(0));
+    assertEquals(match.getStart(), 9);
+    assertEquals(match.getEnd(), 10);
+    match = searchResults.getResults().get(1);
+    assertSame(match.getSequence(), al.getSequenceAt(1));
+    assertEquals(match.getStart(), 2);
+    assertEquals(match.getEnd(), 3);
+
+    /*
+     * bc should match seq3/1-2
+     */
+    f = new Finder(av);
+    f.findAll("bc", true, false);
+    searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 1);
+    match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(2));
+    assertEquals(match.getStart(), 1);
+    assertEquals(match.getEnd(), 2);
+
+    f.findAll("bC", true, false);
+    assertTrue(f.getSearchResults().isEmpty());
+  }
+
+  /**
+   * Test finding next match of a sequence pattern in a selection group
+   */
+  @Test(groups = "Functional")
+  public void testFind_inSelection()
+  {
+    /*
+     * select sequences 2 and 3, columns 4-6 which contains
+     * BCD
+     * cdE
+     */
+    SequenceGroup sg = new SequenceGroup();
+    sg.setStartRes(3);
+    sg.setEndRes(5);
+    sg.addSequence(al.getSequenceAt(1), false);
+    sg.addSequence(al.getSequenceAt(2), false);
+    av.setSelectionGroup(sg);
+
+    FinderI f = new Finder(av);
+    f.findNext("b", false, false);
+    assertTrue(f.getIdMatches().isEmpty());
+    SearchResultsI searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 1);
+    SearchResultMatchI match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(1));
+    assertEquals(match.getStart(), 2);
+    assertEquals(match.getEnd(), 2);
+
+    /*
+     * a second Find should not return the 'b' in seq3 as outside the selection
+     */
+    f.findNext("b", false, false);
+    assertTrue(f.getSearchResults().isEmpty());
+    assertTrue(f.getIdMatches().isEmpty());
+
+    f = new Finder(av);
+    f.findNext("d", false, false);
+    assertTrue(f.getIdMatches().isEmpty());
+    searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 1);
     match = searchResults.getResults().get(0);
-    assertSame(al.getSequenceAt(0), match.getSequence());
-    assertEquals(2, match.getStart());
-    assertEquals(3, match.getEnd());
+    assertSame(match.getSequence(), al.getSequenceAt(1));
+    assertEquals(match.getStart(), 4);
+    assertEquals(match.getEnd(), 4);
+    f.findNext("d", false, false);
+    assertTrue(f.getIdMatches().isEmpty());
+    searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 1);
+    match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(2));
+    assertEquals(match.getStart(), 3);
+    assertEquals(match.getEnd(), 3);
+  }
+
+  /**
+   * Test finding all matches of a search pattern in a selection group
+   */
+  @Test(groups = "Functional")
+  public void testFind_findAllInSelection()
+  {
+    /*
+     * select sequences 2 and 3, columns 4-6 which contains
+     * BCD
+     * cdE
+     */
+    SequenceGroup sg = new SequenceGroup();
+    sg.setStartRes(3);
+    sg.setEndRes(5);
+    sg.addSequence(al.getSequenceAt(1), false);
+    sg.addSequence(al.getSequenceAt(2), false);
+    av.setSelectionGroup(sg);
+  
+    /*
+     * search for 'e' should match two sequence ids and one residue
+     */
+    Finder f = new Finder(av);
+    f.findAll("e", false, false);
+    assertEquals(f.getIdMatches().size(), 2);
+    assertSame(f.getIdMatches().get(0), al.getSequenceAt(1));
+    assertSame(f.getIdMatches().get(1), al.getSequenceAt(2));
+    SearchResultsI searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 1);
+    SearchResultMatchI match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(2));
+    assertEquals(match.getStart(), 4);
+    assertEquals(match.getEnd(), 4);
+
+    /*
+     * search for 'Q' should match two sequence ids only
+     */
+    f = new Finder(av);
+    f.findAll("Q", false, false);
+    assertEquals(f.getIdMatches().size(), 2);
+    assertSame(f.getIdMatches().get(0), al.getSequenceAt(1));
+    assertSame(f.getIdMatches().get(1), al.getSequenceAt(2));
+    assertTrue(f.getSearchResults().isEmpty());
+  }
+
+  /**
+   * Test finding in selection with a sequence too short to reach it
+   */
+  @Test(groups = "Functional")
+  public void testFind_findAllInSelectionWithShortSequence()
+  {
+    /*
+     * select all sequences, columns 10-12
+     * BCD
+     * cdE
+     */
+    SequenceGroup sg = new SequenceGroup();
+    sg.setStartRes(9);
+    sg.setEndRes(11);
+    sg.addSequence(al.getSequenceAt(0), false);
+    sg.addSequence(al.getSequenceAt(1), false);
+    sg.addSequence(al.getSequenceAt(2), false);
+    sg.addSequence(al.getSequenceAt(3), false);
+    av.setSelectionGroup(sg);
+
+    /*
+     * search for 'I' should match two sequence positions
+     */
+    Finder f = new Finder(av);
+    f.findAll("I", false, false);
+    assertTrue(f.getIdMatches().isEmpty());
+    SearchResultsI searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 2);
+    SearchResultMatchI match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(0));
+    assertEquals(match.getStart(), 16);
+    assertEquals(match.getEnd(), 16);
     match = searchResults.getResults().get(1);
-    assertSame(al.getSequenceAt(1), match.getSequence());
-    assertEquals(2, match.getStart());
-    assertEquals(3, match.getEnd());
+    assertSame(match.getSequence(), al.getSequenceAt(1));
+    assertEquals(match.getStart(), 8);
+    assertEquals(match.getEnd(), 8);
   }
 
   /**
-   * Test for JAL-2302 to verify that sub-matches are not included in a find all
-   * result
+   * Test that find does not report hidden positions
    */
   @Test(groups = "Functional")
-  public void testFind_maximalResultOnly()
+  public void testFind_withHiddenColumns()
   {
-    Finder f = new Finder(al, null);
-    f.setFindAll(true);
-    f.find("M+");
+    /*
+     * 0    5   9
+     * ABCD--EF-GHI
+     * A--BCDefHI
+     * --bcdEFH
+     * aa---aMMMMMaaa
+     */
+
+    /*
+     * hide 2-4 (CD- -BC bcd ---)
+     */
+    HiddenColumns hc = new HiddenColumns();
+    hc.hideColumns(2, 4);
+    al.setHiddenColumns(hc);
+
+    /*
+     * find all search for D should ignore hidden positions in seq1 and seq3,
+     * find the visible D in seq2
+     */
+    Finder f = new Finder(av);
+    f.findAll("D", false, false);
     SearchResultsI searchResults = f.getSearchResults();
     assertEquals(searchResults.getSize(), 1);
     SearchResultMatchI match = searchResults.getResults().get(0);
-    assertSame(al.getSequenceAt(3), match.getSequence());
-    assertEquals(4, match.getStart()); // dataset sequence positions
-    assertEquals(8, match.getEnd()); // base 1
+    assertSame(match.getSequence(), al.getSequenceAt(1));
+    assertEquals(match.getStart(), 4);
+    assertEquals(match.getEnd(), 4);
+
+    /*
+     * hide columns 2-5:
+     * find all 'aaa' should find end of seq4 only
+     */
+    hc.hideColumns(2, 5);
+    f = new Finder(av);
+    f.findAll("aaa", false, false);
+    searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 1);
+    match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(3));
+    assertEquals(match.getStart(), 9);
+    assertEquals(match.getEnd(), 11);
+
+    /*
+     * find all 'BE' should not match across hidden columns in seq1
+     */
+    f.findAll("BE", false, false);
+    assertTrue(f.getSearchResults().isEmpty());
+
+    /*
+     * boundary case: hide columns at end of alignment
+     * search for H should match seq3/6 only
+     */
+    hc.revealAllHiddenColumns(new ColumnSelection());
+    hc.hideColumns(8, 13);
+    f = new Finder(av);
+    f.findNext("H", false, false);
+    searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 1);
+    match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(2));
+    assertEquals(match.getStart(), 6);
+    assertEquals(match.getEnd(), 6);
+  }
+
+  @Test(groups = "Functional")
+  public void testFind_withHiddenColumnsAndSelection()
+  {
+    /*
+     * 0    5   9
+     * ABCD--EF-GHI
+     * A--BCDefHI
+     * --bcdEFH
+     * aa---aMMMMMaaa
+     */
+  
+    /*
+     * hide columns 2-4 and 6-7
+     */
+    HiddenColumns hc = new HiddenColumns();
+    hc.hideColumns(2, 4);
+    hc.hideColumns(6, 7);
+    al.setHiddenColumns(hc);
+  
+    /*
+     * select rows 2-3
+     */
+    SequenceGroup sg = new SequenceGroup();
+    sg.addSequence(al.getSequenceAt(1), false);
+    sg.addSequence(al.getSequenceAt(2), false);
+    sg.setStartRes(0);
+    sg.setEndRes(13);
+    av.setSelectionGroup(sg);
+
+    /*
+     * find all search for A or H
+     * should match seq2/1, seq2/7, not seq3/6
+     */
+    Finder f = new Finder(av);
+    f.findAll("[AH]", false, false);
+    SearchResultsI searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 2);
+    SearchResultMatchI match = searchResults.getResults().get(0);
+    assertSame(match.getSequence(), al.getSequenceAt(1));
+    assertEquals(match.getStart(), 1);
+    assertEquals(match.getEnd(), 1);
+    match = searchResults.getResults().get(1);
+    assertSame(match.getSequence(), al.getSequenceAt(1));
+    assertEquals(match.getStart(), 7);
+    assertEquals(match.getEnd(), 7);
   }
 }
diff --git a/test/jalview/analysis/GeneticCodesTest.java b/test/jalview/analysis/GeneticCodesTest.java
new file mode 100644 (file)
index 0000000..5f49092
--- /dev/null
@@ -0,0 +1,298 @@
+package jalview.analysis;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertSame;
+
+import java.util.Iterator;
+
+import org.testng.annotations.Test;
+
+public class GeneticCodesTest
+{
+  @Test(groups = "Functional")
+  public void testGetCodeTable()
+  {
+    GeneticCodes codes = GeneticCodes.getInstance();
+    assertEquals(codes.getStandardCodeTable().getName(), "Standard");
+    assertEquals(codes.getStandardCodeTable().getId(), "1");
+    assertSame(codes.getStandardCodeTable(), codes.getCodeTable("1"));
+    assertEquals(codes.getCodeTable("2").getName(),
+            "Vertebrate Mitochondrial");
+    assertEquals(codes.getCodeTable("11").getName(),
+            "Bacterial, Archaeal and Plant Plastid");
+    assertEquals(codes.getCodeTable("31").getName(),
+            "Blastocrithidia Nuclear");
+  }
+
+  @Test(groups = "Functional")
+  public void testGetCodeTables()
+  {
+    GeneticCodes codes = GeneticCodes.getInstance();
+    Iterator<GeneticCodeI> tableIterator = codes.getCodeTables().iterator();
+    String[] ids = new String[] { "1", "2", "3", "4", "5", "6", "9", "10",
+        "11", "12", "13", "14", "15", "16", "21", "22", "23", "24", "25",
+        "26", "27", "28", "29", "30", "31" };
+    for (int i = 0; i < ids.length; i++)
+    {
+      assertEquals(tableIterator.next().getId(), ids[i]);
+    }
+    assertFalse(tableIterator.hasNext());
+  }
+
+  @Test(groups = "Functional")
+  public void testTranslate()
+  {
+    GeneticCodes codes = GeneticCodes.getInstance();
+
+    GeneticCodeI gc = codes.getCodeTable("1");
+    assertNull(gc.translate("XYZ"));
+    assertEquals(gc.translate("AGA"), "R");
+
+    gc = codes.getCodeTable("2");
+    assertEquals(gc.translate("AGA"), "*"); // variant
+    assertEquals(gc.translate("ttc"), "F"); // non-variant
+
+    // table 11 has no variant translations - should serve the standard values
+    gc = codes.getCodeTable("11");
+    assertEquals(gc.translate("ttc"), "F");
+
+    gc = codes.getCodeTable("31");
+    assertEquals(gc.translate("TGA"), "W"); // variant
+    assertEquals(gc.translate("tag"), "E"); // variant
+    assertEquals(gc.translate("AGC"), "S"); // non-variant
+  }
+
+  /**
+   * Test 'standard' codon translations (no ambiguity codes)
+   */
+  @Test(groups = { "Functional" })
+  public void testTranslate_standardTable()
+  {
+    GeneticCodeI st = GeneticCodes.getInstance().getStandardCodeTable();
+    assertEquals("F", st.translate("TTT"));
+    assertEquals("F", st.translate("TTC"));
+    assertEquals("L", st.translate("TTA"));
+    assertEquals("L", st.translate("TTG"));
+    assertEquals("L", st.translate("CTT"));
+    assertEquals("L", st.translate("CTC"));
+    assertEquals("L", st.translate("CTA"));
+    assertEquals("L", st.translate("CTG"));
+    assertEquals("I", st.translate("ATT"));
+    assertEquals("I", st.translate("ATC"));
+    assertEquals("I", st.translate("ATA"));
+    assertEquals("M", st.translate("ATG"));
+    assertEquals("V", st.translate("GTT"));
+    assertEquals("V", st.translate("GTC"));
+    assertEquals("V", st.translate("GTA"));
+    assertEquals("V", st.translate("GTG"));
+    assertEquals("S", st.translate("TCT"));
+    assertEquals("S", st.translate("TCC"));
+    assertEquals("S", st.translate("TCA"));
+    assertEquals("S", st.translate("TCG"));
+    assertEquals("P", st.translate("CCT"));
+    assertEquals("P", st.translate("CCC"));
+    assertEquals("P", st.translate("CCA"));
+    assertEquals("P", st.translate("CCG"));
+    assertEquals("T", st.translate("ACT"));
+    assertEquals("T", st.translate("ACC"));
+    assertEquals("T", st.translate("ACA"));
+    assertEquals("T", st.translate("ACG"));
+    assertEquals("A", st.translate("GCT"));
+    assertEquals("A", st.translate("GCC"));
+    assertEquals("A", st.translate("GCA"));
+    assertEquals("A", st.translate("GCG"));
+    assertEquals("Y", st.translate("TAT"));
+    assertEquals("Y", st.translate("TAC"));
+    assertEquals("*", st.translate("TAA"));
+    assertEquals("*", st.translate("TAG"));
+    assertEquals("H", st.translate("CAT"));
+    assertEquals("H", st.translate("CAC"));
+    assertEquals("Q", st.translate("CAA"));
+    assertEquals("Q", st.translate("CAG"));
+    assertEquals("N", st.translate("AAT"));
+    assertEquals("N", st.translate("AAC"));
+    assertEquals("K", st.translate("AAA"));
+    assertEquals("K", st.translate("AAG"));
+    assertEquals("D", st.translate("GAT"));
+    assertEquals("D", st.translate("GAC"));
+    assertEquals("E", st.translate("GAA"));
+    assertEquals("E", st.translate("GAG"));
+    assertEquals("C", st.translate("TGT"));
+    assertEquals("C", st.translate("TGC"));
+    assertEquals("*", st.translate("TGA"));
+    assertEquals("W", st.translate("TGG"));
+    assertEquals("R", st.translate("CGT"));
+    assertEquals("R", st.translate("CGC"));
+    assertEquals("R", st.translate("CGA"));
+    assertEquals("R", st.translate("CGG"));
+    assertEquals("S", st.translate("AGT"));
+    assertEquals("S", st.translate("AGC"));
+    assertEquals("R", st.translate("AGA"));
+    assertEquals("R", st.translate("AGG"));
+    assertEquals("G", st.translate("GGT"));
+    assertEquals("G", st.translate("GGC"));
+    assertEquals("G", st.translate("GGA"));
+    assertEquals("G", st.translate("GGG"));
+  }
+
+  /**
+   * Test a sample of codon translations involving ambiguity codes. Should
+   * return a protein value where the ambiguity does not affect the translation.
+   */
+  @Test(groups = { "Functional" })
+  public void testTranslate_standardTableAmbiguityCodes()
+  {
+    GeneticCodeI st = GeneticCodes.getInstance().getStandardCodeTable();
+    // Y is C or T
+    assertEquals("C", st.translate("TGY"));
+    // Phenylalanine first base variation
+    assertEquals("L", st.translate("YTA"));
+
+    // W is A or T
+    assertEquals("L", st.translate("CTW"));
+    assertNull(st.translate("TTW"));
+
+    // S is G or C
+    assertEquals("G", st.translate("GGS"));
+    assertNull(st.translate("ATS"));
+
+    // K is T or G
+    assertEquals("S", st.translate("TCK"));
+    assertNull(st.translate("ATK"));
+
+    // M is C or A
+    assertEquals("T", st.translate("ACM"));
+    // Arginine first base variation
+    assertEquals("R", st.translate("MGA"));
+    assertEquals("R", st.translate("MGG"));
+    assertNull(st.translate("TAM"));
+
+    // D is A, G or T
+    assertEquals("P", st.translate("CCD"));
+    assertNull(st.translate("AAD"));
+
+    // V is A, C or G
+    assertEquals("V", st.translate("GTV"));
+    assertNull(st.translate("TTV"));
+
+    // H is A, C or T
+    assertEquals("A", st.translate("GCH"));
+    assertEquals("I", st.translate("ATH"));
+    assertNull(st.translate("AGH"));
+
+    // B is C, G or T
+    assertEquals("P", st.translate("CCB"));
+    assertNull(st.translate("TAB"));
+
+    // R is A or G
+    // additional tests for JAL-1685 (resolved)
+    assertEquals("L", st.translate("CTR"));
+    assertEquals("V", st.translate("GTR"));
+    assertEquals("S", st.translate("TCR"));
+    assertEquals("P", st.translate("CCR"));
+    assertEquals("T", st.translate("ACR"));
+    assertEquals("A", st.translate("GCR"));
+    assertEquals("R", st.translate("CGR"));
+    assertEquals("G", st.translate("GGR"));
+    assertEquals("R", st.translate("AGR"));
+    assertEquals("E", st.translate("GAR"));
+    assertEquals("K", st.translate("AAR"));
+    assertEquals("L", st.translate("TTR"));
+    assertEquals("Q", st.translate("CAR"));
+    assertEquals("*", st.translate("TAR"));
+    assertEquals("*", st.translate("TRA"));
+    // Arginine first and third base ambiguity
+    assertEquals("R", st.translate("MGR"));
+    assertNull(st.translate("ATR"));
+
+    // N is any base; 8 proteins accept any base in 3rd position
+    assertEquals("L", st.translate("CTN"));
+    assertEquals("V", st.translate("GTN"));
+    assertEquals("S", st.translate("TCN"));
+    assertEquals("P", st.translate("CCN"));
+    assertEquals("T", st.translate("ACN"));
+    assertEquals("A", st.translate("GCN"));
+    assertEquals("R", st.translate("CGN"));
+    assertEquals("G", st.translate("GGN"));
+    assertNull(st.translate("ATN"));
+    assertNull(st.translate("ANT"));
+    assertNull(st.translate("NAT"));
+    assertNull(st.translate("ANN"));
+    assertNull(st.translate("NNA"));
+    assertNull(st.translate("NNN"));
+
+    // some random stuff
+    assertNull(st.translate("YWB"));
+    assertNull(st.translate("VHD"));
+    assertNull(st.translate("WSK"));
+  }
+
+  /**
+   * Test a sample of codon translations involving ambiguity codes. Should
+   * return a protein value where the ambiguity does not affect the translation.
+   */
+  @Test(groups = { "Functional" })
+  public void testTranslate_nonStandardTableAmbiguityCodes()
+  {
+    GeneticCodeI standard = GeneticCodes.getInstance()
+            .getStandardCodeTable();
+
+    /*
+     * Vertebrate Mitochondrial (Table 2)
+     */
+    GeneticCodeI gc = GeneticCodes.getInstance().getCodeTable("2");
+    // AGR is AGA or AGG - R in standard code, * in table 2
+    assertEquals(gc.translate("AGR"), "*");
+    assertEquals(standard.translate("AGR"), "R");
+    // TGR is TGA or TGG - ambiguous in standard code, W in table 2
+    assertEquals(gc.translate("TGR"), "W");
+    assertNull(standard.translate("TGR"));
+
+    /*
+     * Yeast Mitochondrial (Table 3)
+     */
+    gc = GeneticCodes.getInstance().getCodeTable("3");
+    // CTN is L in standard code, T in table 3
+    assertEquals(gc.translate("ctn"), "T");
+    assertEquals(standard.translate("CTN"), "L");
+
+    /*
+     * Alternative Yeast Nuclear (Table 12)
+     */
+    gc = GeneticCodes.getInstance().getCodeTable("12");
+    // CTG is S; in the standard code CTN is L
+    assertEquals(gc.translate("CTG"), "S");
+    assertNull(gc.translate("CTK")); // K is G or T -> S or L
+    assertEquals(standard.translate("CTK"), "L");
+    assertEquals(gc.translate("CTH"), "L"); // H is anything other than G
+    assertEquals(standard.translate("CTH"), "L");
+    assertEquals(standard.translate("CTN"), "L");
+
+    /*
+     * Trematode Mitochondrial (Table 21)
+     */
+    gc = GeneticCodes.getInstance().getCodeTable("21");
+    // AAR is K in standard code, ambiguous in table 21 as AAA=N not K
+    assertNull(gc.translate("AAR"));
+    assertEquals(standard.translate("AAR"), "K");
+  }
+
+  @Test(groups = "Functional")
+  public void testTranslateCanonical()
+  {
+    GeneticCodes codes = GeneticCodes.getInstance();
+
+    GeneticCodeI gc = codes.getCodeTable("1");
+    assertNull(gc.translateCanonical("XYZ"));
+    assertEquals(gc.translateCanonical("AGA"), "R");
+    // translateCanonical should not resolve ambiguity codes
+    assertNull(gc.translateCanonical("TGY"));
+
+    gc = codes.getCodeTable("2");
+    assertNull(gc.translateCanonical("AGR"));
+    assertEquals(gc.translateCanonical("AGA"), "*"); // variant
+    assertEquals(gc.translateCanonical("ttc"), "F"); // non-variant
+  }
+}
index 3ac8656..0424acc 100644 (file)
@@ -279,8 +279,6 @@ public class CommandLineOperations
             "Failed command : -open examples/uniref50.fa" },
         { "CMD [-nosortbytree] executed successfully!",
             "Failed command : -nosortbytree" },
-        { "CMD [-dasserver nickname=www.test.com] executed successfully!",
-            "Failed command : -dasserver nickname=www.test.com" },
         {
             "CMD [-features examples/testdata/plantfdx.features]  executed successfully!",
             "Failed command : -features examples/testdata/plantfdx.features" },
@@ -294,7 +292,7 @@ public class CommandLineOperations
         { "CMD [-nousagestats] executed successfully!",
             "Failed command : -nousagestats" },
         { "CMD [-noquestionnaire] executed successfully!",
-            "Failed command : -noquestionnaire nickname=www.test.com" } };
+            "Failed command : -noquestionnaire" } };
 
   }
 
index efee93b..7990d21 100644 (file)
@@ -26,6 +26,7 @@ import static org.testng.AssertJUnit.assertTrue;
 import jalview.analysis.Finder;
 import jalview.api.AlignViewControllerI;
 import jalview.api.FeatureColourI;
+import jalview.api.FinderI;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
@@ -147,7 +148,8 @@ public class AlignViewControllerTest
      * seq1 feature in columns 4-6 is hidden
      * seq2 feature in columns 6-7 is shown
      */
-    FeatureColourI fc = new FeatureColour(Color.red, Color.blue, 0f, 10f);
+    FeatureColourI fc = new FeatureColour(null, Color.red, Color.blue, null,
+            0f, 10f);
     fc.setAboveThreshold(true);
     fc.setThreshold(5f);
     af.getFeatureRenderer().setColour("Metal", fc);
@@ -222,10 +224,8 @@ public class AlignViewControllerTest
     /*
      *  test Match/Find works first
      */
-    Finder f = new Finder(af.getViewport().getAlignment(), null);
-    f.setFindAll(true);
-    f.setCaseSensitive(true);
-    f.find("M+");
+    FinderI f = new Finder(af.getViewport());
+    f.findAll("M+", true, false);
     assertEquals(
             "Finder found different set of results to manually created SearchResults",
             sr, f.getSearchResults());
index 8aed114..dd19eb6 100644 (file)
@@ -1532,4 +1532,34 @@ public class AlignmentTest
     assertFalse(hc.equals(hc2));
     assertTrue(al.setHiddenColumns(hc)); // 'changed'
   }
+
+  @Test(groups = { "Functional" })
+  public void testGetWidth()
+  {
+    SequenceI seq1 = new Sequence("seq1", "ABCDEF--");
+    SequenceI seq2 = new Sequence("seq2", "-JKLMNO--");
+    SequenceI seq3 = new Sequence("seq2", "-PQR");
+    AlignmentI a = new Alignment(new SequenceI[] { seq1, seq2, seq3 });
+
+    assertEquals(9, a.getWidth());
+
+    // width includes hidden columns
+    a.getHiddenColumns().hideColumns(2, 5);
+    assertEquals(9, a.getWidth());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetVisibleWidth()
+  {
+    SequenceI seq1 = new Sequence("seq1", "ABCDEF--");
+    SequenceI seq2 = new Sequence("seq2", "-JKLMNO--");
+    SequenceI seq3 = new Sequence("seq2", "-PQR");
+    AlignmentI a = new Alignment(new SequenceI[] { seq1, seq2, seq3 });
+
+    assertEquals(9, a.getVisibleWidth());
+
+    // width excludes hidden columns
+    a.getHiddenColumns().hideColumns(2, 5);
+    assertEquals(5, a.getVisibleWidth());
+  }
 }
index 8709961..2dda4d3 100644 (file)
@@ -27,6 +27,9 @@ import static org.testng.AssertJUnit.fail;
 
 import jalview.analysis.AlignmentGenerator;
 import jalview.gui.JvOptionPane;
+import jalview.viewmodel.annotationfilter.AnnotationFilterParameter;
+import jalview.viewmodel.annotationfilter.AnnotationFilterParameter.SearchableAnnotationField;
+import jalview.viewmodel.annotationfilter.AnnotationFilterParameter.ThresholdType;
 
 import java.util.Arrays;
 import java.util.BitSet;
@@ -598,4 +601,129 @@ public class ColumnSelectionTest
     assertEquals(sg.getStartRes(), 10);
     assertEquals(sg.getEndRes(), 19);
   }
+
+  @Test(groups = { "Functional" })
+  public void testFilterAnnotations()
+  {
+    ColumnSelection cs = new ColumnSelection();
+
+    /*
+     * filter with no conditions clears the selection
+     */
+    Annotation[] anns = new Annotation[] { null };
+    AnnotationFilterParameter filter = new AnnotationFilterParameter();
+    cs.addElement(3);
+    int added = cs.filterAnnotations(anns, filter);
+    assertEquals(0, added);
+    assertTrue(cs.isEmpty());
+
+    /*
+     * select on description (regex)
+     */
+    filter.setRegexString("w.rld");
+    filter.addRegexSearchField(SearchableAnnotationField.DESCRIPTION);
+    Annotation helix = new Annotation("(", "hello", '<', 2f);
+    Annotation sheet = new Annotation("(", "world", '<', 2f);
+    added = cs.filterAnnotations(new Annotation[] { null, helix, sheet },
+            filter);
+    assertEquals(1, added);
+    assertTrue(cs.contains(2));
+
+    /*
+     * select on label (invalid regex, exact match)
+     */
+    filter = new AnnotationFilterParameter();
+    filter.setRegexString("(");
+    filter.addRegexSearchField(SearchableAnnotationField.DISPLAY_STRING);
+    added = cs.filterAnnotations(new Annotation[] { null, helix, sheet },
+            filter);
+    assertEquals(2, added);
+    assertTrue(cs.contains(1));
+    assertTrue(cs.contains(2));
+
+    /*
+     * select Helix (secondary structure symbol H)
+     */
+    filter = new AnnotationFilterParameter();
+    filter.setFilterAlphaHelix(true);
+    helix = new Annotation("x", "desc", 'H', 0f);
+    sheet = new Annotation("x", "desc", 'E', 1f);
+    Annotation turn = new Annotation("x", "desc", 'S', 2f);
+    Annotation ann4 = new Annotation("x", "desc", 'Y', 3f);
+    added = cs
+            .filterAnnotations(new Annotation[]
+            { null, helix, sheet, turn, ann4 },
+            filter);
+    assertEquals(1, added);
+    assertTrue(cs.contains(1));
+
+    /*
+     * select Helix and Sheet (E)
+     */
+    filter.setFilterBetaSheet(true);
+    added = cs
+            .filterAnnotations(new Annotation[]
+            { null, helix, sheet, turn, ann4 }, filter);
+    assertEquals(2, added);
+    assertTrue(cs.contains(1));
+    assertTrue(cs.contains(2));
+
+    /*
+     * select Sheet and Turn (S)
+     */
+    filter.setFilterAlphaHelix(false);
+    filter.setFilterTurn(true);
+    added = cs
+            .filterAnnotations(new Annotation[]
+            { null, helix, sheet, turn, ann4 }, filter);
+    assertEquals(2, added);
+    assertTrue(cs.contains(2));
+    assertTrue(cs.contains(3));
+
+    /*
+     * select value < 2f (ann1, ann2)
+     */
+    filter = new AnnotationFilterParameter();
+    filter.setThresholdType(ThresholdType.BELOW_THRESHOLD);
+    filter.setThresholdValue(2f);
+    added = cs
+            .filterAnnotations(new Annotation[]
+            { null, helix, sheet, turn, ann4 }, filter);
+    assertEquals(2, added);
+    assertTrue(cs.contains(1));
+    assertTrue(cs.contains(2));
+
+    /*
+     * select value > 2f (ann4 only)
+     */
+    filter.setThresholdType(ThresholdType.ABOVE_THRESHOLD);
+    added = cs
+            .filterAnnotations(new Annotation[]
+            { null, helix, sheet, turn, ann4 }, filter);
+    assertEquals(1, added);
+    assertTrue(cs.contains(4));
+
+    /*
+     * select >2f or Helix
+     */
+    filter.setFilterAlphaHelix(true);
+    added = cs
+            .filterAnnotations(new Annotation[]
+            { null, helix, sheet, turn, ann4 }, filter);
+    assertEquals(2, added);
+    assertTrue(cs.contains(1));
+    assertTrue(cs.contains(4));
+
+    /*
+     * select < 1f or Helix; one annotation matches both
+     * return value should only count it once
+     */
+    filter.setThresholdType(ThresholdType.BELOW_THRESHOLD);
+    filter.setThresholdValue(1f);
+    added = cs
+            .filterAnnotations(new Annotation[]
+            { null, helix, sheet, turn, ann4 }, filter);
+    assertEquals(1, added);
+    assertTrue(cs.contains(1));
+  }
 }
index f1a6e20..349b5d1 100644 (file)
@@ -186,6 +186,25 @@ public class SearchResultsTest
     assertEquals(5, m.getEnd());
   }
 
+  @Test(groups = { "Functional" })
+  public void testMatchContains()
+  {
+    SequenceI seq1 = new Sequence("", "abcdefghijklm");
+    SequenceI seq2 = new Sequence("", "abcdefghijklm");
+    SearchResultMatchI m = new SearchResults().new Match(seq1, 2, 5);
+
+    assertTrue(m.contains(seq1, 2, 5));
+    assertTrue(m.contains(seq1, 3, 5));
+    assertTrue(m.contains(seq1, 2, 4));
+    assertTrue(m.contains(seq1, 3, 3));
+
+    assertFalse(m.contains(seq1, 2, 6));
+    assertFalse(m.contains(seq1, 1, 5));
+    assertFalse(m.contains(seq1, 1, 8));
+    assertFalse(m.contains(seq2, 3, 3));
+    assertFalse(m.contains(null, 3, 3));
+  }
+
   /**
    * test markColumns for creating column selections
    */
@@ -268,4 +287,20 @@ public class SearchResultsTest
             "Didn't set expected number of columns in total for two successive marks",
             2, tbs.cardinality());
   }
+
+  /**
+   * Test to verify adding doesn't create duplicate results
+   */
+  @Test(groups = { "Functional" })
+  public void testAddResult()
+  {
+    SequenceI seq1 = new Sequence("", "abcdefghijklm");
+    SearchResultsI sr = new SearchResults();
+    sr.addResult(seq1, 3, 5);
+    assertEquals(1, sr.getSize());
+    sr.addResult(seq1, 3, 5);
+    assertEquals(1, sr.getSize());
+    sr.addResult(seq1, 3, 6);
+    assertEquals(2, sr.getSize());
+  }
 }
index f13a877..454ff61 100644 (file)
@@ -119,7 +119,8 @@ public class AlignFrameTest
      * seq1 feature in columns 1-5 is hidden
      * seq2 feature in columns 6-10 is shown
      */
-    FeatureColourI fc = new FeatureColour(Color.red, Color.blue, 0f, 10f);
+    FeatureColourI fc = new FeatureColour(null, Color.red, Color.blue, null,
+            0f, 10f);
     fc.setAboveThreshold(true);
     fc.setThreshold(5f);
     alignFrame.getFeatureRenderer().setColour("Metal", fc);
index 6ddebf8..6d8a47e 100644 (file)
@@ -13,6 +13,7 @@ import jalview.datamodel.features.FeatureMatcherSetI;
 import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
 import jalview.schemes.FeatureColour;
+import jalview.schemes.FeatureColourTest;
 import jalview.util.matcher.Condition;
 
 import java.awt.Color;
@@ -60,8 +61,8 @@ public class FeatureSettingsTest
     fr.setColour("type2", byLabel);
 
     // type3: by score above threshold
-    FeatureColourI byScore = new FeatureColour(Color.BLACK, Color.BLUE, 1,
-            10);
+    FeatureColourI byScore = new FeatureColour(null, Color.BLACK,
+            Color.BLUE, null, 1, 10);
     byScore.setAboveThreshold(true);
     byScore.setThreshold(2f);
     fr.setColour("type3", byScore);
@@ -73,8 +74,8 @@ public class FeatureSettingsTest
     fr.setColour("type4", byAF);
 
     // type5: by attribute CSQ:PolyPhen below threshold
-    FeatureColourI byPolyPhen = new FeatureColour(Color.BLACK, Color.BLUE,
-            1, 10);
+    FeatureColourI byPolyPhen = new FeatureColour(null, Color.BLACK,
+            Color.BLUE, null, 1, 10);
     byPolyPhen.setBelowThreshold(true);
     byPolyPhen.setThreshold(3f);
     byPolyPhen.setAttributeName("CSQ", "PolyPhen");
@@ -188,4 +189,50 @@ public class FeatureSettingsTest
     });
     seq.addSequenceFeature(sf);
   }
+
+  /**
+   * @see FeatureColourTest#testGetDescription()
+   * @throws IOException
+   */
+  @Test(groups = "Functional")
+  public void testGetColorTooltip() throws IOException
+  {
+    assertNull(FeatureSettings.getColorTooltip(null, false));
+
+    /*
+     * simple colour
+     */
+    FeatureColourI fc = new FeatureColour(Color.black);
+    String simpleTooltip = "Click to edit, right-click for menu";
+    assertEquals(FeatureSettings.getColorTooltip(fc, true), simpleTooltip);
+    assertNull(FeatureSettings.getColorTooltip(fc, false));
+
+    /*
+     * graduated colour tooltip includes description of colour
+     */
+    fc.setColourByLabel(true);
+    assertEquals(FeatureSettings.getColorTooltip(fc, false),
+            "<html>By Label</html>");
+    assertEquals(FeatureSettings.getColorTooltip(fc, true),
+            "<html>By Label<br>" + simpleTooltip + "</br></html>");
+
+    /*
+     * graduated colour with threshold is html-encoded
+     */
+    fc = new FeatureColour(null, Color.red, Color.blue, null, 2f, 10f);
+    fc.setBelowThreshold(true);
+    fc.setThreshold(4f);
+    assertEquals(FeatureSettings.getColorTooltip(fc, false),
+            "<html>By Score (&lt; 4.0)</html>");
+    assertEquals(FeatureSettings.getColorTooltip(fc, true),
+            "<html>By Score (&lt; 4.0)<br>" + simpleTooltip
+                    + "</br></html>");
+
+    fc.setAboveThreshold(true);
+    assertEquals(FeatureSettings.getColorTooltip(fc, false),
+            "<html>By Score (&gt; 4.0)</html>");
+    assertEquals(FeatureSettings.getColorTooltip(fc, true),
+            "<html>By Score (&gt; 4.0)<br>" + simpleTooltip
+                    + "</br></html>");
+  }
 }
index 3632cc7..77c18db 100644 (file)
@@ -779,7 +779,7 @@ public class FeaturesFileTest
     /*
      * now threshold to Score > 1.1 - should exclude sf2
      */
-    FeatureColourI fc = new FeatureColour(Color.white, Color.BLACK,
+    FeatureColourI fc = new FeatureColour(null, Color.white, Color.BLACK,
             Color.white, 0f, 2f);
     fc.setAboveThreshold(true);
     fc.setThreshold(1.1f);
@@ -855,7 +855,7 @@ public class FeaturesFileTest
      * now threshold to Score > 1.1 - should exclude sf2
      * (and there should be no empty STARTGROUP/ENDGROUP output)
      */
-    FeatureColourI fc = new FeatureColour(Color.white, Color.BLACK,
+    FeatureColourI fc = new FeatureColour(null, Color.white, Color.BLACK,
             Color.white, 0f, 2f);
     fc.setAboveThreshold(true);
     fc.setThreshold(1.1f);
index 87e35c7..cf3c7e5 100644 (file)
@@ -37,11 +37,11 @@ import jalview.viewmodel.seqfeatures.FeatureRendererModel;
 import java.awt.Color;
 import java.util.Map;
 
-import junit.extensions.PA;
-
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import junit.extensions.PA;
+
 public class SequenceAnnotationReportTest
 {
 
@@ -158,7 +158,8 @@ public class SequenceAnnotationReportTest
     /*
      * then with colour by an attribute the feature lacks
      */
-    FeatureColourI fc = new FeatureColour(Color.white, Color.black, 5, 10);
+    FeatureColourI fc = new FeatureColour(null, Color.white, Color.black,
+            null, 5, 10);
     fc.setAttributeName("Pfam");
     fr.setColour("METAL", fc);
     sb.setLength(0);
@@ -187,7 +188,8 @@ public class SequenceAnnotationReportTest
 
     FeatureRendererModel fr = new FeatureRenderer(null);
     Map<String, float[][]> minmax = fr.getMinMax();
-    FeatureColourI fc = new FeatureColour(Color.white, Color.blue, 12, 22);
+    FeatureColourI fc = new FeatureColour(null, Color.white, Color.blue,
+            null, 12, 22);
     fc.setAttributeName("clinical_significance");
     fr.setColour("METAL", fc);
     minmax.put("METAL", new float[][] { { 0f, 1f }, null });
@@ -328,7 +330,8 @@ public class SequenceAnnotationReportTest
 
     // with showDbRefs = true, colour Variant features by clinical_significance
     sb.setLength(0);
-    FeatureColourI fc = new FeatureColour(Color.green, Color.pink, 2, 3);
+    FeatureColourI fc = new FeatureColour(null, Color.green, Color.pink,
+            null, 2, 3);
     fc.setAttributeName("clinical_significance");
     fr.setColour("Variant", fc);
     sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
index d6df39a..afc445e 100644 (file)
@@ -930,8 +930,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     fr.setColour("type2", byLabel);
 
     // type3: by score above threshold
-    FeatureColourI byScore = new FeatureColour(Color.BLACK, Color.BLUE, 1,
-            10);
+    FeatureColourI byScore = new FeatureColour(null, Color.BLACK,
+            Color.BLUE, null, 1, 10);
     byScore.setAboveThreshold(true);
     byScore.setThreshold(2f);
     fr.setColour("type3", byScore);
@@ -943,8 +943,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     fr.setColour("type4", byAF);
 
     // type5: by attribute CSQ:PolyPhen below threshold
-    FeatureColourI byPolyPhen = new FeatureColour(Color.BLACK, Color.BLUE,
-            1, 10);
+    FeatureColourI byPolyPhen = new FeatureColour(null, Color.BLACK,
+            Color.BLUE, null, 1, 10);
     byPolyPhen.setBelowThreshold(true);
     byPolyPhen.setThreshold(3f);
     byPolyPhen.setAttributeName("CSQ", "PolyPhen");
index d8b905e..af7c2ed 100644 (file)
@@ -323,7 +323,7 @@ public class FeatureColourFinderTest
      */
     Color min = new Color(100, 50, 150);
     Color max = new Color(200, 0, 100);
-    FeatureColourI fc = new FeatureColour(min, max, 0, 10);
+    FeatureColourI fc = new FeatureColour(null, min, max, null, 0, 10);
     fr.setColour("kd", fc);
     fr.featuresAdded();
     av.setShowSequenceFeatures(true);
@@ -493,7 +493,7 @@ public class FeatureColourFinderTest
      */
     Color min = new Color(100, 50, 150);
     Color max = new Color(200, 0, 100);
-    FeatureColourI fc = new FeatureColour(min, max, 0, 10);
+    FeatureColourI fc = new FeatureColour(null, min, max, null, 0, 10);
     fc.setAboveThreshold(true);
     fc.setThreshold(5f);
     fr.setColour(kdFeature, fc);
index a0fb498..723f3b8 100644 (file)
@@ -285,8 +285,8 @@ public class FeatureRendererTest
      * give "Type3" features a graduated colour scheme
      * - first with no threshold
      */
-    FeatureColourI gc = new FeatureColour(Color.yellow, Color.red, null, 0f,
-            10f);
+    FeatureColourI gc = new FeatureColour(Color.green, Color.yellow,
+            Color.red, null, 0f, 10f);
     fr.getFeatureColours().put("Type3", gc);
     features = fr.findFeaturesAtColumn(seq, 8);
     assertTrue(features.contains(sf4));
@@ -428,8 +428,8 @@ public class FeatureRendererTest
      * graduated colour by score, no threshold, no score
      * 
      */
-    FeatureColourI gc = new FeatureColour(Color.yellow, Color.red,
-            Color.green, 1f, 11f);
+    FeatureColourI gc = new FeatureColour(Color.red, Color.yellow,
+            Color.red, Color.green, 1f, 11f);
     fr.getFeatureColours().put("Cath", gc);
     assertEquals(fr.getColour(sf1), Color.green);
 
@@ -453,7 +453,8 @@ public class FeatureRendererTest
      * threshold is min-max; now score 6 is 1/6 of the way from 5 to 11
      * or from yellow(255, 255, 0) to red(255, 0, 0)
      */
-    gc = new FeatureColour(Color.yellow, Color.red, Color.green, 5f, 11f);
+    gc = new FeatureColour(Color.red, Color.yellow, Color.red, Color.green,
+            5f, 11f);
     fr.getFeatureColours().put("Cath", gc);
     gc.setAutoScaled(false); // this does little other than save a checkbox setting!
     assertEquals(fr.getColour(sf2), new Color(255, 213, 0));
@@ -476,7 +477,8 @@ public class FeatureRendererTest
      * colour by feature attribute value
      * first with no value held
      */
-    gc = new FeatureColour(Color.yellow, Color.red, Color.green, 1f, 11f);
+    gc = new FeatureColour(Color.red, Color.yellow, Color.red, Color.green,
+            1f, 11f);
     fr.getFeatureColours().put("Cath", gc);
     gc.setAttributeName("AF");
     assertEquals(fr.getColour(sf2), Color.green);
@@ -574,7 +576,7 @@ public class FeatureRendererTest
     /*
      * feature score outwith colour threshold (score > 2)
      */
-    FeatureColourI fc = new FeatureColour(Color.white, Color.black,
+    FeatureColourI fc = new FeatureColour(null, Color.white, Color.black,
             Color.white, 0, 10);
     fc.setAboveThreshold(true);
     fc.setThreshold(2f);
index b7a5164..be8b58d 100644 (file)
@@ -124,6 +124,18 @@ public class AnnotationColourGradientTest
       Color result = testee.shadeCalculation(ann, col);
       assertEquals(result, expected, "for column " + col);
     }
+
+    /*
+     * test for boundary case threshold == graphMax (JAL-3206)
+     */
+    float thresh = ann.threshold.value;
+    ann.threshold.value = ann.graphMax;
+    Color result = testee.shadeCalculation(ann, WIDTH - 1);
+    assertEquals(result, maxColour);
+    testee.setThresholdIsMinMax(false);
+    result = testee.shadeCalculation(ann, WIDTH - 1);
+    assertEquals(result, maxColour);
+    ann.threshold.value = thresh; // reset
   }
 
   /**
@@ -174,6 +186,18 @@ public class AnnotationColourGradientTest
       Color result = testee.shadeCalculation(ann, col);
       assertEquals(result, expected, "for column " + col);
     }
+
+    /*
+     * test for boundary case threshold == graphMin (JAL-3206)
+     */
+    float thresh = ann.threshold.value;
+    ann.threshold.value = ann.graphMin;
+    Color result = testee.shadeCalculation(ann, 0);
+    assertEquals(result, minColour);
+    testee.setThresholdIsMinMax(false);
+    result = testee.shadeCalculation(ann, 0);
+    assertEquals(result, minColour);
+    ann.threshold.value = thresh; // reset
   }
 
   /**
diff --git a/test/jalview/schemes/DnaCodonTests.java b/test/jalview/schemes/DnaCodonTests.java
deleted file mode 100644 (file)
index 908d07b..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.schemes;
-
-import static org.testng.AssertJUnit.assertTrue;
-
-import jalview.gui.JvOptionPane;
-
-import java.util.Map;
-
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-public class DnaCodonTests
-{
-
-  @BeforeClass(alwaysRun = true)
-  public void setUpJvOptionPane()
-  {
-    JvOptionPane.setInteractiveMode(false);
-    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
-  }
-
-  @Test(groups = { "Functional" })
-  public void testAmbiguityCodeGeneration()
-  {
-    assertTrue(ResidueProperties.ambiguityCodes.size() > 0);
-  }
-
-  @Test(groups = { "Functional" })
-  public void testAmbiguityCodon()
-  {
-    for (String ac : ResidueProperties.ambiguityCodes.keySet())
-    {
-      assertTrue("Couldn't resolve GGN as glycine codon",
-              ResidueProperties.codonHash2.get("GG" + ac).equals("G"));
-    }
-  }
-
-  @Test(groups = { "Functional" })
-  public void regenerateCodonTable()
-  {
-    for (Map.Entry<String, String> codon : ResidueProperties.codonHash2
-            .entrySet())
-    {
-      System.out.println("ResidueProperties.codonHash2.set(\""
-              + codon.getKey() + "\", \"" + codon.getValue() + "\");");
-    }
-  }
-}
index 6ccce85..52ca360 100644 (file)
@@ -38,8 +38,6 @@ import java.awt.Color;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
-import junit.extensions.PA;
-
 public class FeatureColourTest
 {
 
@@ -51,6 +49,30 @@ public class FeatureColourTest
   }
 
   @Test(groups = { "Functional" })
+  public void testConstructors()
+  {
+    FeatureColourI fc = new FeatureColour();
+    assertNull(fc.getColour());
+    assertTrue(fc.isSimpleColour());
+    assertFalse(fc.isColourByLabel());
+    assertFalse(fc.isGraduatedColour());
+    assertFalse(fc.isColourByAttribute());
+    assertEquals(Color.white, fc.getMinColour());
+    assertEquals(Color.black, fc.getMaxColour());
+
+    fc = new FeatureColour(Color.RED);
+    assertEquals(Color.red, fc.getColour());
+    assertTrue(fc.isSimpleColour());
+    assertFalse(fc.isColourByLabel());
+    assertFalse(fc.isGraduatedColour());
+    assertFalse(fc.isColourByAttribute());
+    assertEquals(ColorUtils.bleachColour(Color.RED, 0.9f),
+            fc.getMinColour());
+    assertEquals(Color.RED, fc.getMaxColour());
+
+  }
+
+  @Test(groups = { "Functional" })
   public void testCopyConstructor()
   {
     /*
@@ -67,7 +89,8 @@ public class FeatureColourTest
     /*
      * min-max colour
      */
-    fc = new FeatureColour(Color.gray, Color.black, 10f, 20f);
+    fc = new FeatureColour(null, Color.gray, Color.black, Color.gray, 10f,
+            20f);
     fc.setAboveThreshold(true);
     fc.setThreshold(12f);
     fc1 = new FeatureColour(fc);
@@ -86,12 +109,14 @@ public class FeatureColourTest
     /*
      * min-max-noValue colour
      */
-    fc = new FeatureColour(Color.gray, Color.black, Color.green, 10f, 20f);
+    fc = new FeatureColour(Color.red, Color.gray, Color.black, Color.green,
+            10f, 20f);
     fc.setAboveThreshold(true);
     fc.setThreshold(12f);
     fc1 = new FeatureColour(fc);
     assertTrue(fc1.isGraduatedColour());
     assertFalse(fc1.isColourByLabel());
+    assertFalse(fc1.isSimpleColour());
     assertFalse(fc1.isColourByAttribute());
     assertNull(fc1.getAttributeName());
     assertTrue(fc1.isAboveThreshold());
@@ -99,6 +124,7 @@ public class FeatureColourTest
     assertEquals(Color.gray, fc1.getMinColour());
     assertEquals(Color.black, fc1.getMaxColour());
     assertEquals(Color.green, fc1.getNoColour());
+    assertEquals(Color.red, fc1.getColour());
     assertEquals(10f, fc1.getMin());
     assertEquals(20f, fc1.getMax());
 
@@ -128,7 +154,8 @@ public class FeatureColourTest
     /*
      * colour by attribute (value)
      */
-    fc = new FeatureColour(Color.gray, Color.black, Color.green, 10f, 20f);
+    fc = new FeatureColour(Color.yellow, Color.gray, Color.black,
+            Color.green, 10f, 20f);
     fc.setAboveThreshold(true);
     fc.setThreshold(12f);
     fc.setAttributeName("AF");
@@ -136,104 +163,19 @@ public class FeatureColourTest
     assertTrue(fc1.isGraduatedColour());
     assertFalse(fc1.isColourByLabel());
     assertTrue(fc1.isColourByAttribute());
+    assertFalse(fc1.isSimpleColour());
     assertArrayEquals(new String[] { "AF" }, fc1.getAttributeName());
     assertTrue(fc1.isAboveThreshold());
     assertEquals(12f, fc1.getThreshold());
     assertEquals(Color.gray, fc1.getMinColour());
     assertEquals(Color.black, fc1.getMaxColour());
     assertEquals(Color.green, fc1.getNoColour());
+    assertEquals(Color.yellow, fc1.getColour());
     assertEquals(10f, fc1.getMin());
     assertEquals(20f, fc1.getMax());
   }
 
   @Test(groups = { "Functional" })
-  public void testCopyConstructor_minMax()
-  {
-    /*
-     * graduated colour
-     */
-    FeatureColour fc = new FeatureColour(Color.BLUE, Color.RED, 1f, 5f);
-    assertTrue(fc.isGraduatedColour());
-    assertFalse(fc.isColourByLabel());
-    assertFalse(fc.isColourByAttribute());
-    assertNull(fc.getAttributeName());
-    assertEquals(1f, fc.getMin());
-    assertEquals(5f, fc.getMax());
-
-    /*
-     * update min-max bounds
-     */
-    FeatureColour fc1 = new FeatureColour(fc, 2f, 6f);
-    assertTrue(fc1.isGraduatedColour());
-    assertFalse(fc1.isColourByLabel());
-    assertFalse(fc1.isColourByAttribute());
-    assertNull(fc1.getAttributeName());
-    assertEquals(2f, fc1.getMin());
-    assertEquals(6f, fc1.getMax());
-    assertFalse((boolean) PA.getValue(fc1, "isHighToLow"));
-
-    /*
-     * update min-max bounds - high to low
-     */
-    fc1 = new FeatureColour(fc, 23f, 16f);
-    assertTrue(fc1.isGraduatedColour());
-    assertFalse(fc1.isColourByLabel());
-    assertFalse(fc1.isColourByAttribute());
-    assertNull(fc1.getAttributeName());
-    assertEquals(23f, fc1.getMin());
-    assertEquals(16f, fc1.getMax());
-    assertTrue((boolean) PA.getValue(fc1, "isHighToLow"));
-
-    /*
-     * graduated colour by attribute
-     */
-    fc1.setAttributeName("AF");
-    fc1 = new FeatureColour(fc1, 13f, 36f);
-    assertTrue(fc1.isGraduatedColour());
-    assertFalse(fc1.isColourByLabel());
-    assertTrue(fc1.isColourByAttribute());
-    assertArrayEquals(new String[] { "AF" }, fc1.getAttributeName());
-    assertEquals(13f, fc1.getMin());
-    assertEquals(36f, fc1.getMax());
-    assertFalse((boolean) PA.getValue(fc1, "isHighToLow"));
-
-    /*
-     * colour by label
-     */
-    fc = new FeatureColour(Color.BLUE, Color.RED, 1f, 5f);
-    fc.setColourByLabel(true);
-    assertFalse(fc.isGraduatedColour());
-    assertTrue(fc.isColourByLabel());
-    assertFalse(fc.isColourByAttribute());
-    assertNull(fc.getAttributeName());
-    assertEquals(1f, fc.getMin());
-    assertEquals(5f, fc.getMax());
-
-    /*
-     * update min-max bounds
-     */
-    fc1 = new FeatureColour(fc, 2f, 6f);
-    assertFalse(fc1.isGraduatedColour());
-    assertTrue(fc1.isColourByLabel());
-    assertFalse(fc1.isColourByAttribute());
-    assertNull(fc1.getAttributeName());
-    assertEquals(2f, fc1.getMin());
-    assertEquals(6f, fc1.getMax());
-
-    /*
-     * colour by attribute text
-     */
-    fc1.setAttributeName("AC");
-    fc1 = new FeatureColour(fc1, 13f, 36f);
-    assertFalse(fc1.isGraduatedColour());
-    assertTrue(fc1.isColourByLabel());
-    assertTrue(fc1.isColourByAttribute());
-    assertArrayEquals(new String[] { "AC" }, fc1.getAttributeName());
-    assertEquals(13f, fc1.getMin());
-    assertEquals(36f, fc1.getMax());
-  }
-
-  @Test(groups = { "Functional" })
   public void testGetColor_simpleColour()
   {
     FeatureColour fc = new FeatureColour(Color.RED);
@@ -260,7 +202,8 @@ public class FeatureColourTest
      * score 0 to 100
      * gray(128, 128, 128) to red(255, 0, 0)
      */
-    FeatureColour fc = new FeatureColour(Color.GRAY, Color.RED, 0f, 100f);
+    FeatureColour fc = new FeatureColour(null, Color.GRAY, Color.RED, null,
+            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);
@@ -276,8 +219,8 @@ public class FeatureColourTest
   public void testGetColor_aboveBelowThreshold()
   {
     // gradient from [50, 150] from WHITE(255, 255, 255) to BLACK(0, 0, 0)
-    FeatureColour fc = new FeatureColour(Color.WHITE, Color.BLACK, 50f,
-            150f);
+    FeatureColour fc = new FeatureColour(null, Color.WHITE, Color.BLACK,
+            Color.white, 50f, 150f);
     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 70f,
             null);
 
@@ -371,7 +314,8 @@ public class FeatureColourTest
      * graduated colour by score, no threshold
      * - default constructor sets noValueColor = minColor
      */
-    fc = new FeatureColour(Color.GREEN, Color.RED, 12f, 25f);
+    fc = new FeatureColour(null, Color.GREEN, Color.RED, Color.GREEN, 12f,
+            25f);
     String greenHex = Format.getHexString(Color.GREEN);
     String expected = String.format(
             "domain\tscore|%s|%s|noValueMin|abso|12.0|25.0|none", greenHex,
@@ -381,7 +325,8 @@ public class FeatureColourTest
     /*
      * graduated colour by score, no threshold, no value gets min colour
      */
-    fc = new FeatureColour(Color.GREEN, Color.RED, Color.GREEN, 12f, 25f);
+    fc = new FeatureColour(Color.RED, Color.GREEN, Color.RED, Color.GREEN,
+            12f, 25f);
     expected = String.format(
             "domain\tscore|%s|%s|noValueMin|abso|12.0|25.0|none", greenHex,
             redHex);
@@ -390,7 +335,8 @@ public class FeatureColourTest
     /*
      * graduated colour by score, no threshold, no value gets max colour
      */
-    fc = new FeatureColour(Color.GREEN, Color.RED, Color.RED, 12f, 25f);
+    fc = new FeatureColour(Color.RED, Color.GREEN, Color.RED, Color.RED,
+            12f, 25f);
     expected = String.format(
             "domain\tscore|%s|%s|noValueMax|abso|12.0|25.0|none", greenHex,
             redHex);
@@ -687,8 +633,9 @@ public class FeatureColourTest
      * graduated colour based on attribute value for AF
      * given a min-max range of 0-100
      */
-    FeatureColour fc = new FeatureColour(new Color(50, 100, 150),
-            new Color(150, 200, 250), Color.yellow, 0f, 100f);
+    FeatureColour fc = new FeatureColour(Color.white,
+            new Color(50, 100, 150), new Color(150, 200, 250), Color.yellow,
+            0f, 100f);
     String attName = "AF";
     fc.setAttributeName(attName);
 
@@ -721,7 +668,8 @@ public class FeatureColourTest
     assertFalse(fc.isOutwithThreshold(null));
     assertFalse(fc.isOutwithThreshold(sf));
 
-    fc = new FeatureColour(Color.white, Color.black, Color.green, 0f, 10f);
+    fc = new FeatureColour(null, Color.white, Color.black, Color.green, 0f,
+            10f);
     assertFalse(fc.isOutwithThreshold(sf)); // no threshold
 
     fc.setAboveThreshold(true);
@@ -752,4 +700,101 @@ public class FeatureColourTest
     sf.setValue("AC", "junk");
     assertFalse(fc.isOutwithThreshold(sf)); // bad value is ignored
   }
+
+  /**
+   * Test description of feature colour suitable for a tooltip
+   */
+  @Test(groups = { "Functional" })
+  public void testGetDescription()
+  {
+    /*
+     * plain colour
+     */
+    FeatureColour fc = new FeatureColour(Color.RED);
+    assertEquals(
+            String.format("r=%d,g=%d,b=%d", Color.RED.getRed(),
+                    Color.red.getGreen(), Color.red.getBlue()),
+            fc.getDescription());
+  
+    /*
+     * colour by label (no threshold)
+     */
+    fc = new FeatureColour();
+    fc.setColourByLabel(true);
+    assertEquals("By Label", fc.getDescription());
+  
+    /*
+     * colour by attribute text (no threshold)
+     */
+    fc = new FeatureColour();
+    fc.setColourByLabel(true);
+    fc.setAttributeName("CLIN_SIG");
+    assertEquals("By CLIN_SIG", fc.getDescription());
+  
+    /*
+     * colour by label (above score threshold) 
+     */
+    fc = new FeatureColour();
+    fc.setColourByLabel(true);
+    fc.setAutoScaled(false);
+    fc.setThreshold(12.5f);
+    fc.setAboveThreshold(true);
+    assertEquals("By Label (Score > 12.5)",
+            fc.getDescription());
+  
+    /*
+     * colour by label (below score threshold)
+     */
+    fc.setBelowThreshold(true);
+    assertEquals("By Label (Score < 12.5)",
+            fc.getDescription());
+  
+    /*
+     * colour by attributes text (below score threshold)
+     */
+    fc.setBelowThreshold(true);
+    fc.setAttributeName("CSQ", "Consequence");
+    assertEquals(
+            "By CSQ:Consequence (Score < 12.5)",
+            fc.getDescription());
+  
+    /*
+     * graduated colour by score, no threshold
+     */
+    fc = new FeatureColour(null, Color.GREEN, Color.RED, null, 12f, 25f);
+    assertEquals("By Score", fc.getDescription());
+  
+    /*
+     * graduated colour by score, below threshold
+     */
+    fc.setThreshold(12.5f);
+    fc.setBelowThreshold(true);
+    assertEquals("By Score (< 12.5)",
+            fc.getDescription());
+  
+    /*
+     * graduated colour by score, above threshold
+     */
+    fc.setThreshold(12.5f);
+    fc.setAboveThreshold(true);
+    fc.setAutoScaled(false);
+    assertEquals("By Score (> 12.5)",
+            fc.getDescription());
+
+    /*
+     * graduated colour by attribute, no threshold
+     */
+    fc.setAttributeName("CSQ", "AF");
+    fc.setAboveThreshold(false);
+    fc.setAutoScaled(false);
+    assertEquals("By CSQ:AF", fc.getDescription());
+  
+    /*
+     * graduated colour by attribute, above threshold
+     */
+    fc.setAboveThreshold(true);
+    fc.setAutoScaled(false);
+    assertEquals("By CSQ:AF (> 12.5)",
+            fc.getDescription());
+  }
 }
index 0ef3c25..0368d1e 100644 (file)
@@ -21,7 +21,6 @@
 package jalview.util;
 
 import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
@@ -121,38 +120,6 @@ public class DBRefUtilsTest
     assertEquals("pfam", DBRefUtils.getCanonicalName("pfam"));
 
   }
-
-  @Test(groups = { "Functional" })
-  public void testIsDasCoordinateSystem()
-  {
-    assertFalse(DBRefUtils.isDasCoordinateSystem(null, null));
-    assertFalse(DBRefUtils.isDasCoordinateSystem("pdbresnum", null));
-    assertFalse(DBRefUtils.isDasCoordinateSystem(null, new DBRefEntry(
-            "PDB", "v1", "a1")));
-
-    assertTrue(DBRefUtils.isDasCoordinateSystem("pdbresnum",
-            new DBRefEntry("PDB", "v1", "a1")));
-    assertTrue(DBRefUtils.isDasCoordinateSystem("PDBRESNUM",
-            new DBRefEntry("PDB", "v1", "a1")));
-    // "pdb" is converted to upper-case in DBRefEntry constructor
-    assertTrue(DBRefUtils.isDasCoordinateSystem("pdbresnum",
-            new DBRefEntry("pdb", "v1", "a1")));
-    assertFalse(DBRefUtils.isDasCoordinateSystem("pdb", new DBRefEntry(
-            "pdb", "v1", "a1")));
-
-    assertTrue(DBRefUtils.isDasCoordinateSystem("UNIPROT", new DBRefEntry(
-            "Uniprot", "v1", "a1")));
-    assertTrue(DBRefUtils.isDasCoordinateSystem("Uniprot", new DBRefEntry(
-            "UNIPROT", "v1", "a1")));
-    assertFalse(DBRefUtils.isDasCoordinateSystem("UNIPROTKB",
-            new DBRefEntry("pdb", "v1", "a1")));
-
-    assertTrue(DBRefUtils.isDasCoordinateSystem("EMBL", new DBRefEntry(
-            "EMBL", "v1", "a1")));
-    assertTrue(DBRefUtils.isDasCoordinateSystem("embl", new DBRefEntry(
-            "embl", "v1", "a1")));
-  }
-
   /**
    * Test 'parsing' a DBRef - non PDB case
    */
index 01973d2..360a700 100755 (executable)
@@ -7,10 +7,14 @@
 
 <taskdef resource="net/sf/antcontrib/antcontrib.properties">
   <classpath>
-    <pathelement location="${basedir}/utils/ant-contrib-0.3.jar"/>
+    <pathelement location="${basedir}/utils/ant-contrib-1.0b3.jar"/>
+  </classpath>
+</taskdef>
+<taskdef resource="net/sf/antcontrib/antlib.xml">
+  <classpath>
+    <pathelement location="${basedir}/utils/ant-contrib-1.0b3.jar"/>
   </classpath>
 </taskdef>
-<taskdef resource="net/sf/antcontrib/antlib.xml"/>
  
 <target name="checkLang" description="Reports missing entries in language bundles compared to Message.properties">
        <!-- adapted from http://stackoverflow.com/questions/14381660/ant-task-to-compare-two-properties-files -->