JAL-1782 JAL-1780 JAL-653 JAL-1892 update patched refactored test suite with TestNG
authorJim Procter <jprocter@issues.jalview.org>
Tue, 23 Jun 2015 08:48:13 +0000 (09:48 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Tue, 23 Jun 2015 08:48:13 +0000 (09:48 +0100)
74 files changed:
examples/testdata/exonerateoutput.fullgff [new file with mode: 0644]
examples/testdata/exonerateoutput.gff [new file with mode: 0644]
examples/testdata/exonerateseqs.fa [new file with mode: 0644]
examples/testdata/rna-alignment.xml [new file with mode: 0644]
examples/testdata/simplegff3.gff [new file with mode: 0644]
src/MCview/PDBfile.java
src/jalview/analysis/SequenceIdMatcher.java
src/jalview/api/AlignExportSettingI.java [new file with mode: 0644]
src/jalview/api/AlignViewControllerGuiI.java
src/jalview/api/AlignViewControllerI.java
src/jalview/api/AlignViewportI.java
src/jalview/api/FeatureRenderer.java
src/jalview/api/FeatureSettingsControllerI.java
src/jalview/appletgui/APopupMenu.java
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AlignViewport.java
src/jalview/appletgui/CutAndPasteTransfer.java
src/jalview/appletgui/FeatureSettings.java
src/jalview/appletgui/IdCanvas.java
src/jalview/appletgui/OverviewPanel.java
src/jalview/bin/JalviewLite.java
src/jalview/bin/JalviewLiteURLRetrieve.java
src/jalview/controller/AlignViewController.java
src/jalview/controller/FeatureSettingsController.java
src/jalview/datamodel/ASequence.java [new file with mode: 0755]
src/jalview/datamodel/ASequenceI.java [new file with mode: 0755]
src/jalview/datamodel/AlignedCodon.java
src/jalview/datamodel/AlignedCodonFrame.java
src/jalview/datamodel/ColumnSelection.java
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceDummy.java [new file with mode: 0644]
src/jalview/datamodel/SequenceFeature.java
src/jalview/datamodel/SequenceI.java
src/jalview/gui/AlignExportSettings.java [new file with mode: 0644]
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/CutAndPasteTransfer.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/IdCanvas.java
src/jalview/gui/OverviewPanel.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/SequenceFetcher.java
src/jalview/io/AlignFile.java
src/jalview/io/AppletFormatAdapter.java
src/jalview/io/BioJsHTMLOutput.java
src/jalview/io/FeaturesFile.java
src/jalview/io/FileLoader.java
src/jalview/io/FileParse.java
src/jalview/io/FormatAdapter.java
src/jalview/io/Gff3File.java [new file with mode: 0644]
src/jalview/io/HtmlFile.java
src/jalview/io/HtmlSvgOutput.java
src/jalview/io/IdentifyFile.java
src/jalview/io/JSONFile.java
src/jalview/io/PhylipFile.java
src/jalview/jbgui/GAlignExportSettings.java [new file with mode: 0644]
src/jalview/jbgui/GFinder.java
src/jalview/viewmodel/AlignmentViewport.java
src/jalview/viewmodel/seqfeatures/FeatureSettingsModel.java
src/jalview/ws/DasSequenceFeatureFetcher.java
src/jalview/ws/dbsources/Uniprot.java
src/jalview/ws/jws1/JPredThread.java
src/jalview/ws/seqfetcher/DbSourceProxyImpl.java
test/jalview/analysis/AlignmentUtilsTests.java
test/jalview/datamodel/AlignmentTest.java
test/jalview/datamodel/SequenceDummyTest.java [new file with mode: 0644]
test/jalview/io/Gff3tests.java [new file with mode: 0644]
test/jalview/io/JSONFileTest.java
test/jalview/io/PhylipFileTests.java
test/jalview/io/RNAMLfileTest.java
test/jalview/io/StockholmFileTest.java
test/jalview/util/MappingUtilsTest.java
utils/getJavaVersion.java

diff --git a/examples/testdata/exonerateoutput.fullgff b/examples/testdata/exonerateoutput.fullgff
new file mode 100644 (file)
index 0000000..9ab732e
--- /dev/null
@@ -0,0 +1,261 @@
+Command line: [exonerate --model protein2genome Input_Sequences63/dcsA.fas NewSequencedGenome/A_Ellipt_clc_pe_contigs.fa --bestn 1 --showtargetgff]
+Hostname: [ningal.cluster.lifesci.dundee.ac.uk]
+
+C4 Alignment:
+------------
+         Query: DDB_G0269124 
+        Target: contig_1146 [revcomp]
+         Model: protein2genome:local
+     Raw score: 3652
+   Query range: 142 -> 1059
+  Target range: 11269 -> 8533
+
+   143 : SerProSerSerGluTyrGlyThrThrSerGlyGlyGlnArgPheAspThrLeuValAsp :   162
+         ||||||!:!! !|||   !.!  !  !  !!.!  !! !!.!|||!!:||||||:!!|||
+         SerProAsnMetGluLeuAlaArgAspLeuAlaGlnProHisPheGluThrLeuIleAsp
+ 11269 : TCGCCCAACATGGAGCTGGCGCGCGACCTCGCCCAGCCGCACTTTGAGACGCTGATCGAC : 11212
+
+   163 : ProAspIleSerLeuAlaGluMetGluGluLysMetArgGlnHisLysValTyrGlnGlu :   182
+         ||||||!!:!!!! !!.!|||!!:||||||||||||||||||||||||!.!:!!!  |||
+         ProAspMetThrProGlyGluIleGluGluLysMetArgGlnHisLysAlaHisLeuGlu
+ 11211 : CCCGACATGACGCCCGGCGAGATCGAGGAGAAGATGCGCCAGCACAAGGCGCACCTCGAG : 11152
+
+   183 : GlnGlnGlnGlnGlnGlnGlnGlnGlnGlnGlnGlnLysGlnLysAspLysGluLeuSer :   202
+                     ..!|||:!!.....!..!:!!!  |||:!!|||..!:!!  !! !  !
+         ------------MetGlnLysSerSerSerGluLeuLysLysLysSerGlnMetGlnLeu
+ 11151 : ------------ATGCAAAAGTCCTCGTCGGAACTCAAGAAGAAGTCCCAAATGCAACTC : 11104
+
+   203 : SerGlnLysLysLysProSerSerMetGlnLeuSerLysLysLysHisValAlaLysGlu :   222
+         !.!||| ! :!!:!!  !..!..!:!:     !!.!|||   :::   :!!  !:!!!!:
+         LysGlnAspGlnGlnLysGlnGlnValValAlaLysLysProArgSerIleLeuGlnAsp
+ 11103 : AAGCAGGATCAGCAGAAACAACAAGTCGTCGCAAAGAAGCCCCGTTCGATCCTCCAGGAC : 11044
+
+   223 : AspSerGluThrLeuGluThrIleIleGlyGluGluLysLysGluValValPheGluVal :   242
+         |||! !||||||! !||||||:!!.!!!.!||||||:::|||||||||||||||||||||
+         AspMetGluThrSerGluThrLeuPheAlaGluGluArgLysGluValValPheGluVal
+ 11043 : GACATGGAGACGTCGGAGACCCTTTTCGCCGAGGAACGCAAGGAGGTCGTCTTTGAGGTG : 10984
+
+   243 : LysProTyrPheSerHisAlaIleLeuGlnAlaThrMetAlaValPheLeuIleTrpAsn :   262
+         :::|||||||||||||||:!!|||||||||||||||||||||||||||||||||||||||
+         ArgProTyrPheSerHisSerIleLeuGlnAlaThrMetAlaValPheLeuIleTrpAsn
+ 10983 : CGTCCCTACTTCTCGCACTCTATCCTCCAGGCGACGATGGCCGTCTTCCTCATCTGGAAC : 10924
+
+   263 : IlePheTyrPheAlaTyrArgAlaGlyTrpThrMetAsnArgThrAspTyrIle<->Thr :   281
+         |||||||||||||||||||||  !|||||||||||||||! !  !:!!  !:!!   ..!
+         IlePheTyrPheAlaTyrArgMetGlyTrpThrMetAsnThrGlnAsnGlyValTyrVal
+ 10923 : ATCTTTTACTTTGCCTACCGTATGGGCTGGACCATGAACACCCAGAACGGCGTCTACGTG : 10864
+
+   282 : PheSerTyrSerIleLeuPheIleIleValGluPheIleSerPheLeuGlySerAlaLeu :   301
+         .!!!!!||||||:!:||||||:!!||||||||||||||||||||||||||||||||||||
+         LeuCysTyrSerValLeuPheLeuIleValGluPheIleSerPheLeuGlySerAlaLeu
+ 10863 : CTCTGCTACTCGGTGCTCTTCCTCATCGTCGAGTTCATCTCTTTCCTCGGCTCCGCGCTC : 10804
+
+   302 : HisLeuAsnAsnPheThrAsnProCysThrPheValLeuValValThrLeuGluGlnIle :   321
+         |||||||||||||||||||||||||||||||||:!!||||||||||||||||||||||||
+         HisLeuAsnAsnPheThrAsnProCysThrPheIleLeuValValThrLeuGluGlnIle
+ 10803 : CATCTCAACAACTTTACCAATCCGTGCACCTTTATCCTGGTGGTCACGCTGGAGCAGATC : 10744
+
+   322 : LeuAlaLysArgArgLysLysHisProThrValMetMetTyrValCysThrTyrLysGlu :   341
+         ||||||:::|||||||||     !||||||||||||||||||:!!|||||||||||||||
+         LeuAlaArgArgArgLysProPheProThrValMetMetTyrIleCysThrTyrLysGlu
+ 10743 : CTCGCGCGCCGTCGCAAGCCCTTCCCCACCGTCATGATGTACATCTGTACCTACAAGGAG : 10684
+
+   342 : ProProSerIleValSerArgThrPheArgThrAlaIleSerMetAspTyrProSerGlu :   361
+         |||||||||||||||||||||||||||||||||||||||:!!||||||||||||:!!|||
+         ProProSerIleValSerArgThrPheArgThrAlaIleAlaMetAspTyrProAlaGlu
+ 10683 : CCGCCCTCGATCGTCTCGCGCACGTTCCGCACCGCCATCGCCATGGACTACCCCGCCGAG : 10624
+
+   362 : AsnLeuTrpIleGlyLeuLeuAspAspSerValAsnTyrArgGluSerArgGlyTrpAla :   381
+         ||||||||||||||||||||||||||||||:!!|||!:!||||||||||||||||||:!!
+         AsnLeuTrpIleGlyLeuLeuAspAspSerIleAsnPheArgGluSerArgGlyTrpSer
+ 10623 : AACCTCTGGATCGGCCTGCTCGACGACTCGATCAACTTCCGCGAGTCGCGCGGCTGGTCG : 10564
+
+   382 : HisLeuGlnSerValGluLysAsnPheLeuTyrValLeuLeuGlnLysAlaValTyrSer :   401
+         ||||||||||||||||||||||||||||||!:!  !|||||||||::::!!||||||:!!
+         HisLeuGlnSerValGluLysAsnPheLeuPheGlnLeuLeuGlnArgSerValTyrAla
+ 10563 : CACCTCCAATCGGTCGAGAAGAACTTCCTCTTCCAGCTGCTCCAGCGCTCCGTGTACGCC : 10504
+
+   402 : ValHisAsnIleArgProProValThrSerGlnHisGluAspProHisGlyIleLeuAsn :   421
+         ||||||||||||  !|||||||||.!!..!|||  !|||||||||:!!|||||||||..!
+         ValHisAsnIleAlaProProValAlaGlnGlnAlaGluAspProTyrGlyIleLeuGly
+ 10503 : GTGCACAACATCGCGCCGCCCGTCGCGCAGCAGGCCGAGGACCCGTACGGCATCCTCGGC : 10444
+
+   422 : GluThrSerSerLysIleGluSerSerThrLysGluValIleGluAlaGluValGlnTrp :   441
+         |||||||||..!:::||||||!.!!!!||||||||||||:!!||||||||||||||||||
+         GluThrSerGluArgIleGluLysThrThrLysGluValValGluAlaGluValGlnTrp
+ 10443 : GAGACGTCCGAGCGCATCGAAAAGACCACGAAAGAGGTCGTCGAGGCCGAGGTGCAGTGG : 10384
+
+   442 : PheIleGluTyrPheLeuLeuAsnSerTrpPheGlyValGlyGlnGluIleProArgAsp :   461
+         ||||||||||||||||||||||||||||||||||||:!!! !!::|||  !  !! !!!:
+         PheIleGluTyrPheLeuLeuAsnSerTrpPheGlyIleAspArgGluProGluIleGlu
+ 10383 : TTCATCGAGTACTTCCTCCTGAACAGCTGGTTCGGCATCGACCGCGAGCCCGAGATCGAG : 10324
+
+   462 : AlaAspAspAlaGluArgAlaLeuIleAlaLysLeuArgAspAspAsnPheSerProTyr :   481
+          !!..!||||||||||||  !!!!|||:!!! !||||||!!:|||||||||||| !!|||
+         ProSerAspAlaGluArgAsnPheIleSerMetLeuArgGluAspAsnPheSerAlaTyr
+ 10323 : CCCTCCGACGCCGAACGCAACTTTATCTCGATGCTGCGCGAGGACAACTTCTCGGCGTAC : 10264
+
+   482 : ArgThrPheThrLysSerGluSerGluLysIleSerAsnPheThrIleAspSerLeuGln :   501
+         ||||||.!!||| ! ..!||| !!|||   |||! !!..|||:!!! !|||:!!||||||
+         ArgThrIleThrAspGlnGluArgGluLeuIleTyrThrPheSerSerAspAlaLeuGln
+ 10263 : CGCACCATCACCGACCAGGAGCGCGAGCTCATCTACACGTTCTCGAGCGACGCGCTCCAG : 10204
+
+   502 : SerLeuTrpHisGlySerAlaPhePheArgProLeuIleArgSerIleLeuLeuLysLys :   521
+         |||:!!|||||||||||| !!.!.!:!|||||||||:!:|||!:!  !|||!!!:!!:::
+         SerIleTrpHisGlySerProMetTyrArgProLeuValArgAsnAlaLeuPheGlnArg
+ 10203 : TCGATCTGGCACGGCTCGCCCATGTACCGCCCGCTGGTGCGCAACGCCCTGTTCCAGCGC : 10144
+
+   522 : AspTyrValArgAsnPheValSerGluLeuAsnAsnGlnHisArgLeuArgPheLeuAsn :   541
+           !||||||!:!:!!|||:!!:!!|||! !|||   ..!|||||||||||||||||||||
+         ArgTyrValLysAspPheIleAlaGluHisAsnAlaSerHisArgLeuArgPheLeuAsn
+ 10143 : CGCTACGTCAAGGACTTTATCGCCGAGCACAACGCGTCGCACCGTCTGCGCTTCCTCAAC : 10084
+
+   542 : ThrGluAlaLeuAlaMetAlaGlnTyrGlnValLeuMetMetGlyArgGlnGluLeuPro :   561
+         ..!!!:|||:!!  !||||||||||||:!!|||! !||||||||||||||||||:!!|||
+         ValAspAlaIleAsnMetAlaGlnTyrLysValHisMetMetGlyArgGlnGluValPro
+ 10083 : GTCGACGCGATCAACATGGCGCAGTACAAGGTGCACATGATGGGCCGCCAGGAGGTGCCC : 10024
+
+   562 : TrpAspGluIleSerSerGlyAsnValArgIleAspPheAspThrCysAspGlyProIle :   581
+         !::|||!!::!:|||:!!|||||||||||||||||||||||| !!     !||| !!:!!
+         PheAspAspValSerAlaGlyAsnValArgIleAspPheAspPro---ThrGlySerVal
+ 10023 : TTCGACGACGTGTCCGCGGGCAACGTGCGCATCGACTTTGACCCG---ACCGGCTCGGTC :  9967
+
+   582 : ValSerProLysCysThrTyrLeuArgArgArgLysProProIleProHisAsnLysAla :   601
+         |||!!!|||:::||||||||||||||||||||||||||||||||||||||||||||||||
+         ValThrProArgCysThrTyrLeuArgArgArgLysProProIleProHisAsnLysAla
+  9966 : GTCACGCCGCGCTGCACCTACCTGCGCCGCCGCAAGCCGCCCATCCCGCACAACAAGGCC :  9907
+
+   602 : GlyAsnIleAsnAsnAlaLeuPheAsnGluSerThrLysAlaAspTyrGluPheLeuGly :   621
+         |||||||||||||||!.!|||||||||||||||! ! ! |||||||||||||||:!!|||
+         GlyAsnIleAsnAsnGlyLeuPheAsnGluSerIleHisAlaAspTyrGluPheMetGly
+  9906 : GGCAACATCAACAACGGCCTCTTCAACGAGTCGATCCACGCCGACTACGAGTTCATGGGC :  9847
+
+   622 : LeuLeuAspAlaAspGlnGlnProHisProAspPheLeuLysArgValLeuProTyrPhe :   641
+         ||||||||||||||||||||||||||||||||||||||||||||||||:!!|||||||||
+         LeuLeuAspAlaAspGlnGlnProHisProAspPheLeuLysArgValMetProTyrPhe
+  9846 : CTGCTCGATGCCGACCAGCAGCCGCACCCCGACTTCCTCAAGCGCGTCATGCCCTACTTC :  9787
+
+   642 : TyrSerAspGluGlyGlnAspLeuAlaPheValGlnThrProGlnPhePheSerAsnIle :   661
+         !:!||||||!!:|||!!.!!::!!||||||||||||||||||||||||||||||||||||
+         PheSerAspAspGlyHisGluValAlaPheValGlnThrProGlnPhePheSerAsnIle
+  9786 : TTCAGCGACGACGGCCACGAGGTCGCCTTTGTCCAGACGCCGCAGTTCTTCTCCAACATC :  9727
+
+   662 : TyrProValAspAspProLeuGlyHisArgAsnMetGluPheTyrGlyProValMetGlu :   681
+         ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+         TyrProValAspAspProLeuGlyHisArgAsnMetGluPheTyrGlyProValMetGlu
+  9726 : TACCCCGTCGACGACCCGCTCGGCCACAGAAACATGGAGTTCTACGGTCCCGTAATGGAG :  9667
+
+   682 : GlyArgSerAlaAsnAsnAlaCysProPheValGlyThrAsnAlaIlePheArgArgGln :   701
+         |||||||||.!!|||..!|||||||||||||||||||||||||||||||||||||||:!!
+         GlyArgSerThrAsnGlyAlaCysProPheValGlyThrAsnAlaIlePheArgArgLys
+  9666 : GGTCGCTCCACCAACGGCGCCTGCCCCTTCGTCGGAACCAACGCCATCTTCCGTCGCAAG :  9607
+
+   702 : ProLeuTyrAspIleGlyGlyIleMetTyrAsnSerValThrGluAspMetTyrThrGly :   721
+         ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+         ProLeuTyrAspIleGlyGlyIleMetTyrAsnSerValThrGluAspMetTyrThrGly
+  9606 : CCCCTCTACGACATTGGCGGCATCATGTACAACTCTGTCACTGAGGATATGTACACGGGA :  9547
+
+   722 : MetLysLeuGlnValSerGlyTyrLysSerTrpTyrHisAsnGluValLeuValValGly :   741
+         |||||||||||||||||||||!:!||||||||||||||||||||||||||||||||||||
+         MetLysLeuGlnValSerGlyPheLysSerTrpTyrHisAsnGluValLeuValValGly
+  9546 : ATGAAGCTCCAGGTCTCGGGATTCAAGTCGTGGTACCACAACGAGGTGCTCGTCGTCGGT :  9487
+
+   742 : ThrAlaProValAspLeuLysGluThrLeuGluGlnArgLysArgTrpAlaGlnGlyAla :   761
+         |||||||||||||||:!!||||||||||||||||||||||||||||||||||||||||||
+         ThrAlaProValAspIleLysGluThrLeuGluGlnArgLysArgTrpAlaGlnGlyAla
+  9486 : ACCGCGCCCGTCGATATCAAGGAAACGCTCGAGCAGAGAAAGCGTTGGGCGCAGGGCGCC :  9427
+
+   762 : ValGluIlePheSerLeuThrProTrpGlyTyrIleArgGlyLysLeuGlyTrpArgLys :   781
+         |||||||||||||||||||||||||||||||||||||||  !||||||||||||||||||
+         ValGluIlePheSerLeuThrProTrpGlyTyrIleArgLysLysLeuGlyTrpArgLys
+  9426 : GTCGAAATCTTCTCGCTCACGCCGTGGGGCTACATCCGCAAGAAGCTCGGCTGGAGAAAG :  9367
+
+   782 : MetLeuTyrAsnLeuAspSerCysIleTyrProPheLeuSerProThrAlaPhePheTyr :   801
+         |||||||||||||||||||||||||||||||||||||||||||||||||||.!!||||||
+         MetLeuTyrAsnLeuAspSerCysIleTyrProPheLeuSerProThrAlaIlePheTyr
+  9366 : ATGCTCTACAACCTCGACTCGTGCATCTACCCGTTCCTCTCGCCGACTGCCATCTTCTAC :  9307
+
+   802 : GlyAlaSerProLeuIleMetSerIleTrpThrValProIleValValLysAspProIle :   821
+         |||  !:!!||||||||||||!!!:!:|||||||||||||||||||||!  :!!||||||
+         GlyLeuAlaProLeuIleMetCysLeuTrpThrValProIleValValThrAsnProIle
+  9306 : GGTCTGGCGCCGCTGATCATGTGTCTGTGGACCGTGCCCATCGTCGTCACCAACCCCATC :  9247
+
+   822 : IlePheIleLeuValGlyMetIleProValMetValLeuProArgValIleGlnTyrMet :   841
+         |||||||||||||||||||||||||||||||||:!!||||||||||||!!:|||||||||
+         IlePheIleLeuValGlyMetIleProValMetIleLeuProArgValMetGlnTyrMet
+  9246 : ATCTTCATCCTCGTCGGTATGATCCCCGTCATGATCCTGCCGCGTGTCATGCAGTACATG :  9187
+
+   842 : IleLeuArgAlaLysArgProTyrGluAlaGlyLysSerGlyProSerLeuTrpValGlu :   861
+         ||||||||||||! !||||||!:!||||||||||||||||||||||||||||||||||||
+         IleLeuArgAlaThrArgProPheGluAlaGlyLysSerGlyProSerLeuTrpValGlu
+  9186 : ATCCTCCGCGCCACGCGTCCCTTCGAGGCCGGAAAGTCCGGCCCCTCGCTCTGGGTCGAA :  9127
+
+   862 : AlaThrAspLeuTrpArgAlaGluGlnThrPhePheGlyPheAlaGlyThrTyrIleSer :   881
+         ||||||||||||||||||||||||||||||||||||!.!|||||||||||||||||||||
+         AlaThrAspLeuTrpArgAlaGluGlnThrPhePheAlaPheAlaGlyThrTyrIleSer
+  9126 : GCCACCGATCTCTGGCGTGCCGAACAGACCTTCTTTGCGTTCGCCGGAACCTACATCTCT :  9067
+
+   882 : SerTrpArgGluGlySerAlaSerIleValLysLeuLeuLysAlaArgLysIleSerArg :   901
+         :!!|||!:!!  ||||||||||||:!!|||:::|||:!!|||||||||||||||||||||
+         AlaTrpLysAlaGlySerAlaSerValValArgLeuIleLysAlaArgLysIleSerArg
+  9066 : GCGTGGAAGGCCGGCTCCGCGTCGGTCGTCCGTCTCATCAAGGCGCGCAAGATCTCGCGT :  9007
+
+   902 : HisLysLeuAlaMetTrpAsnTrpLysArgAspPheValLysLysProValValCysGlu :   921
+         ||||||||||||||||||||||||||||||!!:|||!.!||||||||||||:!!  !|||
+         HisLysLeuAlaMetTrpAsnTrpLysArgGluPheAlaLysLysProValIleValGlu
+  9006 : CACAAACTCGCCATGTGGAACTGGAAGCGTGAGTTTGCCAAGAAGCCCGTCATCGTCGAG :  8947
+
+   922 : ValPheArgGlnThrLysLeuValAsnGluAsnAspAsnAlaGlnGluSerSerGlyLys :   941
+           !!:!||||||:!!|||||||||:!!.!.  !!!:   .!!:!!|||  !!.!|||  !
+         ArgTyrArgGlnSerLysLeuValHisHisAlaGlu---ThrGluGluHisLysGlyPro
+  8946 : CGCTACCGCCAGTCGAAGCTGGTGCACCACGCCGAG---ACCGAGGAGCACAAGGGCCCG :  8890
+
+   942 : HisLysAlaGluGlnSerPheArgThrSerAsnLysGluSerAspThrIleLysAsnSer :   961
+         !.!|||||||||||||||||||||:!!|||||||||||||||||||||||||||||||||
+         ArgLysAlaGluGlnSerPheArgSerSerAsnLysGluSerAspThrIleLysAsnSer
+  8889 : CGCAAGGCCGAGCAGTCGTTCCGTTCCTCCAACAAGGAGTCCGACACCATCAAGAACTCG :  8830
+
+   962 : ArgLeuPheLeuProAsnIleIleLeuPheValValAsnIleLeuAlaMetMetSerAla :   981
+         |||||||||  !||||||:!!|||:!!|||! !!.!||||||||||||!!::!!  !.!!
+         ArgLeuPheAlaProAsnLeuIleMetPheGlyAlaAsnIleLeuAlaIleLeuLeuThr
+  8829 : CGTCTCTTTGCGCCGAATCTCATCATGTTTGGCGCCAACATCCTCGCCATCCTGCTGACC :  8770
+
+   982 : ValLeuArgPheAsnCysPheGlnAsnAspMetTrpLeuLeuValValValAlaGlyPhe :  1001
+         :!!|||  !||||||||||||!  |||||||||||||||:!!:!!|||||||||||||||
+         LeuLeuSerPheAsnCysPheLeuAsnAspMetTrpLeuMetIleValValAlaGlyPhe
+  8769 : CTGCTCTCGTTCAACTGCTTCCTCAACGACATGTGGCTGATGATTGTCGTCGCCGGTTTC :  8710
+
+  1002 : SerPheSerThrLeuTrpHisLeuTrpSerPheIleProMetAlaLeuArgGlnSerGlu :  1021
+         :!!|||||||||! !|||||||||||||||||||||||||||||||||||||||||||||
+         AlaPheSerThrCysTrpHisLeuTrpSerPheIleProMetAlaLeuArgGlnSerGlu
+  8709 : GCCTTCTCCACGTGCTGGCATCTCTGGTCGTTCATCCCTATGGCCCTCAGACAGTCCGAG :  8650
+
+  1022 : LysGlnTrpProTyrAlaSerSerTyrHisAlaHisAsnIleValLeuPheLeuValLeu :  1041
+         ||||||||||||||||||||||||||||||||||||||||||:!!:!!||||||:!!|||
+         LysGlnTrpProTyrAlaSerSerTyrHisAlaHisAsnIleLeuIlePheLeuIleLeu
+  8649 : AAGCAGTGGCCCTACGCCTCCTCGTACCACGCGCACAACATTCTCATCTTTCTCATTCTC :  8590
+
+  1042 : GlyPheLeuValLeuLeuPheValAspValLysValCysIleProArgValGly :  1059
+         |||||||||||||||||||||..! ! |||   |||||||||||||||||||||
+         GlyPheLeuValLeuLeuPheThrLysValAlaValCysIleProArgValGly
+  8589 : GGTTTCCTGGTGCTCCTGTTCACCAAGGTCGCTGTCTGTATTCCTCGTGTCGGA :  8534
+
+vulgar: DDB_G0269124 142 1059 . contig_1146 11269 8533 - 3652 M 40 120 G 4 0 M 94 282 G 0 3 M 296 888 G 1 0 M 356 1068 G 1 0 M 125 375
+# --- START OF GFF DUMP ---
+#
+#
+##gff-version 2
+##source-version exonerate:protein2genome:local 2.2.0
+##date 2015-01-16
+##type DNA
+#
+#
+# seqname source feature start end score strand frame attributes
+#
+contig_1146    exonerate:protein2genome:local  gene    8534    11269   3652    -       .       gene_id 0 ; sequence DDB_G0269124 ; gene_orientation .
+contig_1146    exonerate:protein2genome:local  cds     8534    11269   .       -       .       
+contig_1146    exonerate:protein2genome:local  exon    8534    11269   .       -       .       insertions 3 ; deletions 6
+contig_1146    exonerate:protein2genome:local  similarity      8534    11269   3652    -       .       alignment_id 0 ; Query DDB_G0269124 ; Align 11270 143 120 ; Align 11150 187 282 ; Align 10865 281 888 ; Align 9977 578 1068 ; Align 8909 935 375
+# --- END OF GFF DUMP ---
+#
+-- completed exonerate analysis
diff --git a/examples/testdata/exonerateoutput.gff b/examples/testdata/exonerateoutput.gff
new file mode 100644 (file)
index 0000000..3ea68dc
--- /dev/null
@@ -0,0 +1,13 @@
+##gff-version 2
+##source-version exonerate:protein2genome:local 2.2.0
+##date 2015-01-16
+##type DNA
+#
+#
+# seqname source feature start end score strand frame attributes
+#
+contig_1146    exonerate:protein2genome:local  gene    8534    11269   3652    -       .       gene_id 0 ; sequence DDB_G0269124 ; gene_orientation .
+contig_1146    exonerate:protein2genome:local  cds     8534    11269   .       -       .       
+contig_1146    exonerate:protein2genome:local  exon    8534    11269   .       -       .       insertions 3 ; deletions 6
+contig_1146    exonerate:protein2genome:local  similarity      8534    11269   3652    -       .       alignment_id 0 ; Query DDB_G0269124 ; Align 11270 143 120 ; Align 11150 187 282 ; Align 10865 281 888 ; Align 9977 578 1068 ; Align 8909 935 375
+# --- END OF GFF DUMP ---
diff --git a/examples/testdata/exonerateseqs.fa b/examples/testdata/exonerateseqs.fa
new file mode 100644 (file)
index 0000000..e759925
--- /dev/null
@@ -0,0 +1,183 @@
+>DDB_G0280897 
+MTDKINNLINQWLKWDKNEITRKEIEQLKENNNEKELLVRLEERIQFGTAGLRGAMRAGF
+SCMNDLTVTQASQGLCEYVIETIEQSKSKGIVIGYDGRHNSYIFAKITAATFKSKGFKVY
+LFSHIVPTPYVSFAVPNLKAAIGVMITASHNPKNDNGYKVYWETGCQINTPHDKGISKKI
+DENLEPWSNVDATSDIKYGNGDDGESMIDPLSVITELYNKNIKEYSVGSKIELANEPIVY
+TAMHGVGGVYAKKAFETFQLKPFIPVAQQIEPDAEFPTVTYPNPEEGKGALKLSIETAEA
+NNSRLILANDPDADRLAVAEKLADGSWKVFNGNEIGVLLADWAWTNRSTLTKGGSTLENN
+KYFMINTAVSSAMLKTMSEKEGFIHQECLTGFKWIGNAAYNAINNNDGTTFLFGYEEAIG
+FQYGDVSFDKDGVRAAAIFAEFALSLYKKGSSVQDHLESMYKRYGYHISKNRYFFCYEPS
+KMVSIFNKIRNDGKYLTKLGDDDDEQFTITRIRDLTTGYDNGYPDCKARLPVSSSTQMIT
+FYFKNGGIATLRGSGTEPKLKYYVEMIGEVKSNVESTLTKAVELVINQLLKPIENQLEPP
+KDD
+>PPL_06716 
+MSNIKELAESWLKWDKNAETRKEIQSLLESDNQSELKSRLEQRIAFGTAGLRGPMKAGFS
+CMNDLTVIQASQGLCIYVEQTLSNSKNSGIVVGYDGRHHSKEFARLTAATFASRGFKVYL
+FSKIVPTPYVVILYLISNYMDCYVHQAFAVPELKASVGVMITASHNPKDDNGYKVYWDNG
+CQINTPHDIRIAMQIDLNLEPWNIDVNELLNGSLVSDPLDTITKSYFGKIAKYSVKNEVK
+LATSEKIVYTAMHGVGGEYAKMAFETFGLPAFIPVDQQIQPDPEFPTVAFPNPEEGKGAL
+KLSIETAERNNSRLILANDPDADRLAVAERQPDGQWKVFNGNEIGVLFADWAWQNARRAD
+STTPAERFCMINTAVSSSMLKTMANKDGYRHEECLTGFKWVGNKARELMDKGYNFLFAYE
+EAIGFMYGDVSLDKDGVRCAPIFAELALTCYQAGKSCQDHLEELYKRYGYHISKNRYFFC
+YDPKKMVAIFDKIRNYGQFPTNCGDFYITRVRDLTVGYDSGYPDHKARLPVSSSTQMITF
+YFENGGIATLRGSGTEPKLKYYVEMIGSDRQLVESTLSQLVEQVINQFLRPVENELTPPK
+DD
+>DFA_03821 
+MTDINQLAQNWLKWDRNPKTHKEIEQLVEAKDENELRARLENRIAFGTAGIVSTTIVQSH
+MNIGPMKAGFANMNDLTVIQASQGLSIYVQETISQAQSKGVVVGYDGRYNSEVFAKLTAA
+TFASKGFKVYLFSKIVPTPFVAFAVPELGASVGVMVTASHNPKDDNGYKVYWDNGCQINT
+PHDKGIAKQIDLNLEPWTINIDKLLSSELVNDPLETISNAYFSKIYSYSVKNRSTPLELA
+NEKVVYTAMHGVGGDYVKKAFETFKLPPYVEVAQQIKPDPAFPTVAFPNPEEGKGALKLS
+IETAESVNSRLILANDPDADRLAVAEKLKDGSWKVFNGNEIGILLADWAWTNAKINHPDV
+PAEKFFMINTAVSSAMLKTMAKKEGYICEETLTGFKWVGNKAKEMIDQGYKFLFAYEEAI
+GFMYGDVSLDKDGVRCAPIFAEYALNLYANGSSCQDHLDHLMQRYGYHISKNRYFFCYEP
+SKMVRIFNDIRKSNNGQFPDKCGPYEIIRIRDLTVDYDTAYPDNKARLPVSTSTQMITFY
+FKNGAIATLRGSGTEPKLKYYVEMIGDNKQEVESTLQQVVQQVIDNFLQPVVNQLTPPKD
+D
+>DLA_10096 
+MDIYTLANKWLEWDKNEKNRKEIQHFVDEKNEQELRERLENRIQFGTAGLRGPMKAGFAN
+MNDLTVIQASQGLALYVKETIDSALTKGVVVGYDGRHNSQTFARLTAATFLSKGFKVYLF
+SKLVPTPFVAFAVPELGASCGVMITASHNPKDDNGYKVYWDNGCQINTPHDKGISKLIDE
+NLVPWTMNLDDLNKSDLVSDPLERVSKSYFTKISKYSVVKSGATIKQEKVVYTPMHGVGG
+DYAAEAFKVFDLHPFIPVELQIKPDAEFPTVAFPNPEEGKGALKLAIETAESNQSRLILA
+NDPDADRLAVAEKQSSDGSWKVFNGNEIGVLFADWAWRKERALFSEGYNCKPSEYTMIST
+AVSSAMLSTMAKKEGFQHEEVLTGFKWVGNAAKQAMDRGQKFLFAYEEAIGFMYGDVSLD
+KDGVRGASIFAELAFDLYQQGSSCQEHLESLYKKYGYHISNNRYFFCYDPKKMVRIFNEI
+RGNNREYVKELGEFKVERIRDLTTGYDTAFPPEFKAQLPTSSSTQMITFYFTNGSIATLR
+GSGTEPKLKYYVESIGSDKLQVQQTLTKLVSLVIEKLLRPKENELTPPKESVGSERLLAL
+LSEVMSTSMKIQVKYNESITEYNIIKGVKLLTQIDVLCQIFKVDANPDRFVLNYRESNLI
+LSEDNLSKLFSNEISSCSSQSQNGSNGELSSLYSSFGENSSNNNNNSTLKFELILAPIYQ
+VDSVLEHLNNSNLIKKRII
+>DPU1265769
+MSMIRSISGVRGVIGQSWTPTLVSNHIIGFTQLLESEKYYNQKQKKIVVGRDSRVSGPWI
+EMIVNGSLISMGYQVIHIDIAATPTVQYMVEKTKSSGGIVITSSHNPVEWNGLKFVGPDG
+LFIAPVECEVLFSLADNPSSFKFPNYDKLGSVVCNTTANKEHIEAIFKLPFISVDKIKEK
+KFKVCLDSVNGAGGPIMSYLLTELGCEVIGINLEPTGLFAHTPEPVPANLGQLCELVKTH
+KADFGIAVDPDVDRCVFIDDKGVPLGEEYTLAMAVELLLGDCGRRGNVCKNLSSSRAIDD
+ICKKYDSQVICAPVGEIQVAKKMQQVNAVIGGEGNGGVMLPDIHIGRDAPVAATLALQLL
+ANRNAASISEFKRTTLPTYEIVKLKAGIEGLDPDAILAEYTKQYENKEGVVINQEDGLKI
+DSADWWVHLRKSNTEHIIRVISEAKNTKEATDIATKFINEIESKRK
+>440792448
+MASRVSGRMRKISDETQQMVNAWLSVDWDPESREHVKGLVAAGKEEELVAHLGRRISFGT
+AGLRGKMKWGFAFMNAVTVTQASQGLCAYLRTVHPCLTDLRERGVIVGHDGRYNSRMFAR
+LTAAVFLSRKIKVHLFRDDVPTPLVAFGVRHLKCAAGVMVTASHNPKEDNGYKVYWANSA
+QITAPHDAQIARAIEANFSIWDRMPDDKAIDEHPLCLDPTTDVCAAYLAAARHWSFRTPQ
+QNAAAQLRVVYTAMHGVGGQSVERIFDAFGLPPVIAVREQHDPDPDFTTVEFPNPEEANG
+CSLRLAMSTADREGAPLILANDPDADRLAVAERQRDSGEWRILDGNEIALLLADWLWRNY
+TERHPEVDRAKIVMLNSTVSSKALAAMAAKEGFHYRETLTGFKWLGNLADELVRAGYTFL
+FAYEVEIGFMIGDMSLDTDGVRAAPVFVEMANHLYERGLTLSDHLDNLYHKYGYYKMAVG
+YYFCHDPRLMDQIFNEIRNDGLYISTCGDHKVQYVRDLTTGFDNSQPHNRAVLPVSSAAH
+MITFTFENECVATFRGSGTEPKLKYYIEVANASNEQLATDLLDSMKQEIIDRFLQPSQNG
+LRPPAAAEDAHNSPHNSGNSPEQMAPARIARDVIHKEIQALQNLEATLGRDFEKVVEIIE
+SRGSGRVIFTGVGKSGIIAQKISASFSSLGISSFFVHATEAAHGDLGVITAEDVIIAISN
+SGNTPELIFIIPSLRVLAGKIIGITSNKDSLLARYSDASIITGKIMEADQHKIAPTASTI
+VCLAIGDALAVTLSARMKFTLPEFGLRHPGGVLGEKVLGKVFQEFAMKGQGRFLRFWKRM
+TNEERDKLRRDFERIDLAELSRIYLQCRSKAEKGAIDPHSLEPLPSHTWVKLHESDPAAV
+AAWRDAGLRALREGKIGVVLMAGGQATRLGMTMPKGFLDLNLPSHKSLYQLHAEKLLRLQ
+DEVRQTFGGGGGDEEVQQQQQQIQIPFYVMTSPEALQQTHQFFIKHQFFGLCPKQVFFFK
+QRSLPCVAPSGEIIMDTKCSVVFSPDGHGGLFVALKDAKAYEDMKRRGVEYVFAFGVDNP
+LCEVADPAYMGYCIQRNVKMGYKVVDRRDPQETAGVVCVRDGVINCVEYSELPESVAELR
+DEQSGELVYNAANMLNLFFTLRFMRKIADNPSLMEYHLAKKRIPFVNDNGVRTEPLVPNG
+WKFEKYLVDCTPYANNSVAVMFVKREEEFAPIKNGWNSEVDSPRSARRLLAAHYRRRIER
+AGGKLAADDPDKMVEVSPLVTDRKLAQLLQDKHLVTGPAVLQ
+>ENY64621.1 
+MALNNYIKKTEMDYLYEQAALWLKWDKTPETRKEIEDLVASKNEEELKKRFCKRIEFGTA
+GLRGKMCAGFNCMNNLIVQQASQGLALAVEELVQNAHEKGVVIGYDGRYHSKEFAAITAK
+VFISKGFKTYLFSTLCPTPWTAFAVGYLKTACGVMVTASHNPKADNGYKVYWENGCQIIE
+PIDANIASKIHSNLEPWDLSNVDISKVIDPLADVSAEYYKQMMLTIPHFECPEQPKVKYV
+YTAMHGVGSKYVQDAFKTAKLPQPILVPLQNEPDPEFPTVPFPNPEEGKGALKCSIEVAE
+ANGATVIIANDPDADRLSVAVKSGNGWRQFTGNEMANLIADWTYNKYIVSGDKTPAFMVR
+STVSSSFISKMGEVEGFDTYETLTGFKWIGNKAKEIVDTQHKKLLMAYEEAIGFVIGNMS
+YDKDGVRAAVCFAAMALEYAEQGFNLEDRLNMLYEKYGYFASNNKYYFCYDPKLMEKIFN
+KMRNNGQYYWKFGKYAVKSIRDLTVGIDTAQPDKKPLLPVSASTQMITYTFENGCKATLR
+GSGTEPKLKYYIELPGKKGVKAEDVIAELMDLSHELLQASLEPEKNGLIPPKAE
+>Ppo014092.000
+MSISPSVQELVGKWLQWDKNPQNIKEIKDLVAANNEAELKNRLATRIAFGTAGLRGPMRA
+GFSCMNDLTVIQASQGLCKYLQQMVSDIKTRGIVVGYDGRHHSKEFAEWTAATFLSQGIT
+VYLFTRLVPTPFVSYATPLLRCAAGIMITASHNPKDDNGYKVYWDNGCQINVPHDKGISD
+CIEQNLTPWDINKAELLKSELVKDPTETVASAYLKEIKAKCCFHHDENSQKIPVTYTAMH
+GVGSEWVARAFEVFGLAPYVPVAPQISADPEFPTVAFPNPEEGKGALKLSMEAADKAGST
+LILATDPDADRLAVAEKLPSGSWKIFTGNEIGALLAYWAWLKYKERNPKVDPSKCVVINS
+TVSSKLLKALADKEGLKYDETLTGFKWIGGQAAIRIKEGYTFIFGFEEAIGFLFGDVNLD
+KDGVRAAAVFAEMNIQLHKQGITVVQQLEKIYKLYGYFITRNRYFFCYDPAKMERIFNAI
+RNYNNSGTYPTSCGPFKIKNTRDLTTGYDDSQTDKKAILPVSKSTQMITFFFENGGVVTL
+RGSGTEPKLKYYTELSGSDPEKVKSTLDEMVQAIIDTCLKPVENQLQPPSDE
+>ADB0001102_3
+MSTTTSINKLAQDWLKWDKNPKTRAEIQELVEQNDVKELTARLENRIAFGTAGLRGPMKA
+GFSCMNDLTVIQASQGLCLYVIDTIPNAIKSGVVIGYDGRYNSKEFAKYTAATFLSKGYK
+VYLFSKVVPTPYVAFAVTDLKASIGVMITASHNPKDDNGYKVYWENGCQINTPHDKGIAK
+LIDLNLEPWEINVDQLLSGPLVEDPLDRIVSSYNTKIAQYSVASHVKFANEKIIYTAMHG
+VGGEYTKMAFEAFKLPPFIPVAQQYQPDPAFPTVTFPNPEEGKGALKLSIETAEANGSRL
+ILANDPDADRLAVAERLKDGTWKVFNGNEIGVLLADWAWQNARRSHPDTPAEKFFMINTA
+VSSAMLKTMAKKDGYRCEETLTGFKWVGNRAREVMDAEGLHFLFAYEEAIGFLYGDVSLD
+KDGVRCAAIFAELALSYYANGSSCEDHLESLYKRYGYHISRNRYFFCYEPPKMVAIFNKI
+RNNRNFPTKCGRFEIERVRDLTIDYDDGFPDKKARLPVSTSTQMITFYFKNGAIATLRGS
+GTEPKLKYYVEMIGQDKAHVQQELAELVQCIINEFLRPVENELTPPKDD
+>Carpum
+MTQSTCITSMVINNYLSIYIFIYTINDYLKRSLFVLCLVAKMSHHKVAITHPISSYNSII
+NELAQNWLRWDKNKETRKEIEQLVEQKNEKELYDCLAKRIAFGTADNEIMMLLTHTLHTG
+LRGQMKAGFSNMNDLTVIQASQGLCKYVKETIPEAQKKGVVVGYDCRHHSETFARLTAAT
+FASQGFTVYLYSKMVPTPFVAFGVTDLKACVGVMVTASHNPKEDNGYKVYWENGCQINSP
+HDKGISQQIELNLEPWTIDVNSLLEKVDDPLERVTKSYMDQISKYSVRGSVDMATENVVY
+TAMHGVGGVFVKDAFAAFGLAPYIPVPAQVGPDAEFPTVTLPNPEEGKGALKLSIETAEA
+NNSRLIVANDPDADRLAAAEKLKDGSWKVFNGNEIGVLFADWAWQNARRQHGGDSINPSE
+YFMVTTAVSSSMLRTMATKEGYGYDETLTGFKWVGNKARDLIDQGKKFLFAYEESIGYMY
+GEVSLDKDGVRGAAVFTEMALSCYARGTSCQEHLESLYVKYGYHLSKNRYYFCYDPSKMV
+SIFNRIRNNGEFPKTCGPFEITRIRDLTVDYDNGYEDKKARLPVSSSTQMITFYFKNGAI
+ATLRGSGTEPKLKYYVEMIGDDKEQVKATLDQVHDQVIQQFLRPTENQLSPPSDE
+>Cephalum
+MTTDIYQIAQNWLRWDRNPKTHKEISQLVQDKNESELKARLESRIAFGTAGLRGPMKAGF
+SCMNDLTVIQASQGLCMYVKQTLAPDAERKGIVVGYDGRYNSEVFAKLTAATFVSQGFKV
+HLFSRLVPTPFVAFAVPFLKACVGVMITASHNPKDDNGYKVYWDNGCQINTPHDKGIAKQ
+IELNLEPWNVFYKEYFDRIERYTVRHNKQMAREKIVYSAMHGVGGEYTKRAFEVFALDPF
+IAVKEQFHPDPAFPTVTFPNPEEGKGALKLSIETAEANNNWAWKNGKPYYEKGLGSFPND
+QYFMINTAVSSAMLKTMAMKEGFTYEEVLTGFKWVGNAAQNLIEKGKHLLFAYEEAIGFM
+YGDVSLDKDGVRCAPIFAELAQHLYSKGSSCQDHLEELYKRYGYHISKNRYFFCYDPLKM
+EKIFNRIRNGGQYPTKCGDFEITRIRDLTTGYDTGYPPENKAQLPTSTSTQMITFYFKNG
+GIATLRGSGTEPKLKYYVEMIGDDKENVELILQSMVDQVINQFLRPIENELIPPKD
+>Violaceum
+MVINPFYPYYLYFCYSPGISYQGVKINKTKLEQSTLTTINQWLNGNYDEQTKKNIQNLLD
+QESYTELTDAFYRNLEFGTGGLRGIMGAGSNRINKYTIGTATQGLSNYLLKKYPGEKIKV
+AIAHDSRNNSDQFAKITADVFSANGIYVYFFKELRPTPELSFAIRELGCRSGVMLTASHN
+PKEYNGYKAYGADGGQFTAPDDRLVMDEVAKITSIDEVKFTRIDANIELIGEEIDQLYLD
+KITALSVSPEAISRQKDLKIVYSPIHGTGITLVPKALAQFGFDNVTIVEEQSKPDGNFPT
+VVYPNPEEKEAMTLALKKAQEIDADLVLATDPDADRVGIAVKNNNNEWILLNGNQTGSLL
+VHYVLTAWEEKGKIDGNQYIVKTVVTSNLIEAIAKAKKVDCYNTLTGFKWIGQLITSLQG
+KKTFVVGGEESYGYSVGELVRDKDAVISCAFIAEMTAYYKDKGSSLYNALIDMYVTHGLY
+KEELVSLTKKGKTGAEEIKAMMEKFRNNPPASLGGSKVSTLKDYELGTETDLNTGKISKL
+SLPKSDVLQFVTEDGSIVSARPSGTEPKIKFYCSVNATLSQASEFDKTDEKLGLKINALM
+EDLQK
+>Deminut
+MTDIYQIAQNWLKWDRNPKTHKEISTLVEKKDEAELRARLETRIAFGTAGLRGPMKAGFS
+CMNDLTVIQASQGLSLYVKKTLAGSESKGAVVGYDGRYNSEVFAKLTAATFASQGFKVYL
+FSKVVPTPYVAFAVPELGASVGVMVTASHNPKDDNGYKVYWDNGCQINTPHDKHISELIE
+SNLEPWNVCIYITLQINIDKLLSGVIDPLQVVTSSYMSKIEKYSVKHLPQPLKLATEQKI
+VYTAMHGVGAEYAKLAFEAFSLPPFIPVTQQVTPDPAFPTVAFPNPEEGKGALKLAIETA
+EANKSRIILANDPDADRLAVAEKQPEYVFLFYLISNNGTWKVFNGNEIGILFADWAWQNC
+RRVYPDVPADQFFMINTAVSSAMLKSMAKKDGYIHEETLTGFKWVGNKARELLDQNKRFL
+FAYEEAIGFMYGDVSLDKDGVRCAAIFAELALYQYANGSSCQRHLDSLYERYGYHISKNR
+YFFCYEPPKMVAIFNAIRNNKNYPTKCGEFEIERIRDLTDDYDNGYPDNKARLPISKSTQ
+MITFFFKNGAIATLRGSGTEPKLKYYVEMIGDNKSEVEAILAKVVTAVIDNFLRPVENQL
+TPPKDD
+>Ellipt
+MADLDKLVEDWMRWDKNTKTRDEVQKMVAQGDKKALAAALQNRIAFGTAGLRGPMKAGFA
+NMNDLTVIQASQGLCIYVSATIADAAKKGVVVGYDGRHNSLQFARLTAATFRSKGFKVYL
+FSTVVPTPYVAFSVPELGACVGVMVTASHNPKDDNGYKIDVEKLLKEDGVEDPLEKITAS
+YMSKVADYSIKSHPATKDIVMSDDKIVYTAMHGVGGEYTRRSFKAFSLPEFIPVVQQFHP
+DPEFPTVTFPNPEEGKGALKLAIETAEKNNSRLILANDPDADRLAVAERQPDGTWKVFNG
+NEIGVLFADWAWKNARARDPTTPASEFFMVNTAVSSAMLKTMAKTEGYTYEETLTGFKWV
+GNKAKEAIDKGGRFLFAYEEAIGFMYGDVSLDKDGVRTAPIFAQMALSLYAKGLSCVDHL
+EQLMKTYGYHISRNRYFFCYEPPKMVAIFDKIRNNGNFPKHCGPFEIVRVRDLTVDYDDA
+YEDKKARLPVSTSTQMITFYFKNGAIATLRGSGTEPKLKYYVEMIGDKSAKKEDVEKTLA
+EVVKQVIDNFLRPVENELTPPKDD
+>Lepto
+MASSERLQQLIQDWLKWDKNPTTLSEIQELVKKNDEKELRARLENRIAFGTAGMFLLGPM
+KAGFSCMNDLTVIQASQGLCIYVSDTIPNALNSGVVVGYDGRYNSKEFAKYTAATFLSKG
+YKVYLFSKVVPTPYVAFAVTELKAAIGVMITASHNPKDDNGYKVYWDNGCQINTPHDKGI
+AKQIQLNLEPWNVCAFFLDINANELLSGSSVVDPLDTIVNSYNSKITSYSVGNSGVKLAN
+EKIVYTAMHGVGGEYTKLAFEAFKLPPFVPVPQQYTPDPAFPTVAFPNPEEGKGALKLSI
+ETAEANGSRLILANDPDADRLAVAERNTNGTWKVFNGNEIGVLLADWAWQNARRAHPDTP
+ANRYFMINTAVSSAMLKTMAKHEGYRCDETLTGFKWVGNQARKVIDEEKLNFLFAYEEAI
+GFMYGDVSLDKDGVRCAPIFAEMALSYYAQGHSCEDHLETLYKRYGYHISRNRYFFCYEP
+PKMVAIFDRIRNGRNFPTKCGRFEIERVRDLTVDYDDAYPDKKARLPVSTSTQMITFWFK
+NGGIATLRGSGTEPKLKYYVEMIGQDKQVVEKELAELVDAVIQQFLRPVENELTPPKDD
diff --git a/examples/testdata/rna-alignment.xml b/examples/testdata/rna-alignment.xml
new file mode 100644 (file)
index 0000000..60aa433
--- /dev/null
@@ -0,0 +1,1326 @@
+<?xml version="1.0"?>
+<!--
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
+ * Copyright (C) 2014 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.
+-->
+<!DOCTYPE rnaml SYSTEM "rnaml.dtd">
+
+<rnaml version="1.0">
+
+   <molecule id="1">
+      <sequence>
+         <numbering-system id="1" used-in-file="false">
+            <numbering-range>
+               <start>1</start>
+               <end>249</end>
+            </numbering-range>
+         </numbering-system>
+         <seq-data>
+            gaggaaaguc cggacUUCGC AGAAAAAGGU GCCAGUGAAA AACUGGGGGC CGUAAGGCUA
+            CGGAAAGUGU AACAGAAAAC AAACCGCUAA UUCUACCUAG GUAAGAUUAG ACAGGAUGAA
+            AAUGUCGAGC UUAUGGCUCG ACCUCUUUGU GGAAACACAA GGACGCUGCA AACCCCACCU
+            GAAGCAAGAA AGAGUUCGUU UCAGUUUUUC GCUCAGGAAC UCUUAGAGUC GCUCGAGGAU
+            UUUGGUGAC
+         </seq-data>
+      </sequence>
+      <structure>
+         <model id="?">
+            <str-annotation>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>15</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>184</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>16</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>183</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>17</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>182</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>18</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>181</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>22</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>210</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>23</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>209</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>24</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>208</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>25</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>207</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>27</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>180</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>28</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>179</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>29</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>178</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>30</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>177</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>31</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>176</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>32</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>46</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>33</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>45</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>34</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>44</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>35</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>43</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>36</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>42</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>47</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>61</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>48</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>59</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>49</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>58</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>50</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>57</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>51</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>56</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>62</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>175</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>63</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>174</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>67</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>173</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>68</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>172</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>69</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>169</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>70</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>168</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>71</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>167</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>84</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>115</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>85</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>114</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>86</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>111</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>87</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>110</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>88</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>109</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>89</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>108</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>90</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>107</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>91</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>106</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>92</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>105</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>93</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>104</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>94</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>103</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>95</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>102</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>96</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>101</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>124</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>142</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>125</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>141</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>126</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>140</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>127</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>139</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>128</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>138</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>129</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>137</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>143</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>165</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>144</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>163</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>145</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>162</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>146</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>161</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>147</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>160</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>148</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>159</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>149</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>158</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>150</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>157</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>151</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>156</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>188</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>230</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>189</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>229</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>190</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>224</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>191</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>223</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>192</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>222</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>193</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>221</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>194</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>220</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>195</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>219</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>196</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>218</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>197</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>217</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>203</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>213</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>204</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>212</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>205</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>211</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>244</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>249</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+            </str-annotation>
+         </model>
+      </structure>
+   </molecule>
+<molecule id="2">
+      <sequence>
+         <numbering-system id="2" used-in-file="false">
+            <numbering-range>
+               <start>1</start>
+               <end>294</end>
+            </numbering-range>
+         </numbering-system>
+         <seq-data>
+            gaggaaaguc cgggCUCCAU AGGGCAGAGU GCCAGGUAAC GCCUGGGAGG CGCGAGCCUA
+            CGGAAAGUGC CACAGAAAAC AACCGCCUAA GCGCGCAAGC GCCGGUAAGG GUGAAAAGGU
+            GCGGUAAGAG CGCACCGCAC GGCUGGCAAC AGUUCGUGGC UAGGUAAACC CCACUCGGAG
+            CAAGACCAAA UAGGGAUCCA UUGGCGUGGC CCGCGCUGGA UCCGGGUAGG UUGCUAAAGG
+            CGGCCAGCGA UGGUCGUCGU AGAGGAAUGA CUGUCCUCGa cagaacccgg cuua
+         </seq-data>
+      </sequence>
+      <structure>
+         <model id="?">
+            <str-annotation>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>6</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>293</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>7</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>292</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>8</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>291</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>10</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>290</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>11</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>289</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>12</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>288</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>13</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>287</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>14</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>286</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>15</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>180</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>16</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>179</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>17</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>178</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>18</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>177</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>22</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>212</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>23</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>211</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>24</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>210</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>25</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>209</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>27</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>176</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>28</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>175</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>29</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>174</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>30</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>173</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>31</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>172</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>32</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>46</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>33</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>45</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>34</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>44</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>35</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>43</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>36</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>42</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>47</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>61</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>48</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>59</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>49</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>58</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>50</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>57</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>51</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>56</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>62</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>171</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>63</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>170</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>67</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>169</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>68</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>168</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>69</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>165</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>70</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>164</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>71</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>163</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>83</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>110</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>84</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>109</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>85</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>106</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>86</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>105</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>87</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>104</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>91</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>102</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>92</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>101</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>93</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>100</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>94</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>99</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>118</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>136</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>119</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>135</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>120</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>134</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>121</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>133</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>122</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>132</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>123</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>131</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>137</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>160</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>138</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>158</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>139</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>157</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>140</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>156</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>141</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>155</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>142</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>154</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>143</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>152</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>144</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>151</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>145</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>150</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>184</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>232</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>185</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>231</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>186</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>230</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>187</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>229</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>194</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>223</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>195</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>222</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>196</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>221</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>197</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>220</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>198</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>219</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>199</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>218</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>203</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>217</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>204</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>216</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>205</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>215</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>206</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>214</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>207</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>213</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>239</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>258</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>240</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>257</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>241</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>256</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>242</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>255</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>243</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>254</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>244</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>253</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>245</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>252</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+               <base-pair comment="?">
+                  <base-id-5p>
+                     <base-id><position>246</position></base-id>
+                  </base-id-5p>
+                  <base-id-3p>
+                     <base-id><position>251</position></base-id>
+                  </base-id-3p>
+               </base-pair>
+            </str-annotation>
+         </model>
+      </structure>
+   </molecule>
+</rnaml>
diff --git a/examples/testdata/simplegff3.gff b/examples/testdata/simplegff3.gff
new file mode 100644 (file)
index 0000000..2ac5421
--- /dev/null
@@ -0,0 +1,19 @@
+##gff-version 2
+##source-version exonerate:protein2genome:local 2.2.0
+##date 2015-01-16
+##type DNA
+#
+#
+# seqname source feature start end score strand frame attributes
+#
+seq1   exonerate:protein2genome:local  gene    8       11      3652    -       .       gene_id 0 ; sequence seq2 ; gene_orientation .
+seq1   exonerate:protein2genome:local  cds     9       11      .       -       .       
+seq1   exonerate:protein2genome:local  exon    9       11      .       -       .       insertions 3 ; deletions 6
+seq1   exonerate:protein2genome:local  similarity      8       11      3652    -       .       alignment_id 0 ; Query seq2 ; Align 11 1 3
+##FASTA
+>seq1
+ACTACGACACGACGACGACGACG
+>seq2
+CDEQEATGTQDAQEQAQC
+
+
index 4039cdd..7b7f4b0 100755 (executable)
  */
 package MCview;
 
-import java.awt.Color;
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Vector;
-
 import jalview.analysis.AlignSeq;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
@@ -37,6 +29,14 @@ import jalview.datamodel.SequenceI;
 import jalview.io.FileParse;
 import jalview.util.MessageManager;
 
+import java.awt.Color;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Vector;
+
 public class PDBfile extends jalview.io.AlignFile
 {
   private static String CALC_ID_PREFIX = "JalviewPDB";
@@ -383,7 +383,7 @@ public class PDBfile extends jalview.io.AlignFile
                 "getSeqsAsArray", new Class[]
                 {}).invoke(jmf));
         cl.getMethod("addAnnotations", new Class[]
-        { Alignment.class }).invoke(jmf, al);
+        { AlignmentI.class }).invoke(jmf, al);
         for (SequenceI sq : al.getSequences())
         {
           if (sq.getDatasetSequence() != null)
index e6a4853..5b812dd 100755 (executable)
@@ -24,7 +24,9 @@ import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.SequenceI;
 
 import java.util.ArrayList;
-import java.util.Hashtable;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
 import java.util.Vector;
 
 /**
@@ -35,17 +37,27 @@ import java.util.Vector;
  */
 public class SequenceIdMatcher
 {
-  private Hashtable names;
+  private HashMap<SeqIdName, SequenceI> names;
 
-  public SequenceIdMatcher(SequenceI[] seqs)
+  public SequenceIdMatcher(List<SequenceI> seqs)
   {
-    names = new Hashtable();
-    for (int i = 0; i < seqs.length; i++)
+    names = new HashMap<SeqIdName, SequenceI>();
+    addAll(seqs);
+  }
+
+  /**
+   * add more sequences to this matcher - also used by the constructor
+   * 
+   * @param seqs
+   */
+  public void addAll(List<SequenceI> seqs)
+  {
+    for (SequenceI seq : seqs)
     {
       // TODO: deal with ID collisions - SequenceI should be appended to list
       // associated with this key.
-      names.put(new SeqIdName(seqs[i].getDisplayId(true)), seqs[i]);
-      SequenceI dbseq = seqs[i];
+      names.put(new SeqIdName(seq.getDisplayId(true)), seq);
+      SequenceI dbseq = seq;
       while (dbseq.getDatasetSequence()!=null)
       {
         dbseq = dbseq.getDatasetSequence();
@@ -58,9 +70,9 @@ public class SequenceIdMatcher
         for (int r = 0; r < dbr.length; r++)
         {
           sid = new SeqIdName(dbr[r].getAccessionId());
-          if (!names.contains(sid))
+          if (!names.containsKey(sid))
           {
-            names.put(sid, seqs[i]);
+            names.put(sid, seq);
           }
         }
       }
@@ -68,19 +80,30 @@ public class SequenceIdMatcher
   }
 
   /**
+   * convenience method to make a matcher from concrete array
+   * 
+   * @param sequences
+   */
+  public SequenceIdMatcher(SequenceI[] sequences)
+  {
+    this(Arrays.asList(sequences));
+  }
+
+  /**
    * returns the closest SequenceI in matches to SeqIdName and returns all the
    * matches to the names hash.
    * 
    * @param candName
    *          SeqIdName
    * @param matches
-   *          Vector of SequenceI objects
+   *          List of SequenceI objects
    * @return SequenceI closest SequenceI to SeqIdName
    */
-  private SequenceI pickbestMatch(SeqIdName candName, Vector matches)
+  private SequenceI pickbestMatch(SeqIdName candName,
+          List<SequenceI> matches)
   {
-    SequenceI[] st = pickbestMatches(candName, matches);
-    return st == null || st.length == 0 ? null : st[0];
+    List<SequenceI> st = pickbestMatches(candName, matches);
+    return st == null || st.size() == 0 ? null : st.get(0);
   }
 
   /**
@@ -94,16 +117,15 @@ public class SequenceIdMatcher
    * @return Object[] { SequenceI closest SequenceI to SeqIdName, SequenceI[]
    *         ties }
    */
-  private SequenceI[] pickbestMatches(SeqIdName candName, Vector matches)
+  private List<SequenceI> pickbestMatches(SeqIdName candName,
+          List<SequenceI> matches)
   {
-    ArrayList best = new ArrayList();
-    SequenceI match = null;
+    ArrayList<SequenceI> best = new ArrayList<SequenceI>();
     if (candName == null || matches == null || matches.size() == 0)
     {
       return null;
     }
-    match = (SequenceI) matches.elementAt(0);
-    matches.removeElementAt(0);
+    SequenceI match = matches.remove(0);
     best.add(match);
     names.put(new SeqIdName(match.getName()), match);
     int matchlen = match.getName().length();
@@ -111,8 +133,7 @@ public class SequenceIdMatcher
     while (matches.size() > 0)
     {
       // look through for a better one.
-      SequenceI cand = (SequenceI) matches.elementAt(0);
-      matches.remove(0);
+      SequenceI cand = matches.remove(0);
       names.put(new SeqIdName(cand.getName()), cand);
       int q, w, candlen = cand.getName().length();
       // keep the one with an id 'closer' to the given seqnam string
@@ -136,7 +157,7 @@ public class SequenceIdMatcher
       return null;
     }
     ;
-    return (SequenceI[]) best.toArray(new SequenceI[0]);
+    return best;
   }
 
   /**
@@ -163,12 +184,18 @@ public class SequenceIdMatcher
    * 
    * @param seqnam
    *          string to query Matcher with.
+   * @return a new array or (possibly) null
    */
   public SequenceI[] findAllIdMatches(String seqnam)
   {
 
     SeqIdName nam = new SeqIdName(seqnam);
-    return findAllIdMatches(nam);
+    List<SequenceI> m = findAllIdMatches(nam);
+    if (m!=null)
+    {
+      return m.toArray(new SequenceI[m.size()]);
+    }
+    return null;
   }
 
   /**
@@ -233,15 +260,15 @@ public class SequenceIdMatcher
    *          SeqIdName
    * @return SequenceI[]
    */
-  private SequenceI[] findAllIdMatches(
+  private List<SequenceI> findAllIdMatches(
           jalview.analysis.SequenceIdMatcher.SeqIdName nam)
   {
-    Vector matches = new Vector();
+    ArrayList<SequenceI> matches = new ArrayList<SequenceI>();
     while (names.containsKey(nam))
     {
-      matches.addElement(names.remove(nam));
+      matches.add(names.remove(nam));
     }
-    SequenceI[] r = pickbestMatches(nam, matches);
+    List<SequenceI> r = pickbestMatches(nam, matches);
     return r;
   }
 
diff --git a/src/jalview/api/AlignExportSettingI.java b/src/jalview/api/AlignExportSettingI.java
new file mode 100644 (file)
index 0000000..cf56bf3
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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.api;
+
+/**
+ * Abstract interface implemented by Alignment Export dialog to retrieve user
+ * configurations
+ * 
+ * @author tcnofoegbu
+ *
+ */
+public interface AlignExportSettingI
+{
+  /**
+   * Checks if hidden sequences should be exported
+   * 
+   * @return
+   */
+  public boolean isExportHiddenSequences();
+
+  /**
+   * Checks if hidden columns shoulb be exported
+   * 
+   * @return
+   */
+  public boolean isExportHiddenColumns();
+
+  /**
+   * Checks if Annotations should be exported, note this is available for
+   * complex flat file exports like JSON, HTML, GFF
+   * 
+   * @return
+   */
+  public boolean isExportAnnotations();
+
+  /**
+   * Checks if SequenceFeatures should be exported, note this is available for
+   * complex flat file exports like JSON, HTML, GFF
+   * 
+   * @return
+   */
+  public boolean isExportFeatures();
+
+  /**
+   * Checks if SequenceGroups should be exported, note this is available for
+   * complex flat file exports like JSON, HTML, GFF
+   * 
+   * @return
+   */
+  public boolean isExportGroups();
+
+  /**
+   * Checks if settings/export process is cancelled
+   * 
+   * @return
+   */
+  public boolean isCancelled();
+}
index 584f596..4896b35 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.api;
 
 import jalview.commands.CommandI;
+import jalview.schemes.ColourSchemeI;
 
 /**
  * Interface implemented by gui implementations managing a Jalview Alignment
@@ -41,4 +42,24 @@ public interface AlignViewControllerGuiI
 
   void addHistoryItem(CommandI command);
 
+  void setShowSeqFeatures(boolean show);
+  
+  void setMenusForViewport();
+  
+  void changeColour(ColourSchemeI cs);
+
+  /**
+   * trigger an update of the UI in response to a model data change, and if
+   * necessary enable the display of sequence feature annotation on the view.
+   * 
+   * @param enableIfNecessary
+   */
+  void refreshFeatureUI(boolean enableIfNecessary);
+
+  /**
+   * get the Feature Settings control panel for the alignment view if one exists
+   * 
+   * @return
+   */
+  FeatureSettingsControllerI getFeatureSettingsUI();
 }
index 235a656..fef9f14 100644 (file)
@@ -76,4 +76,17 @@ public interface AlignViewControllerI
    */
   void sortAlignmentByFeatureDensity(String[] typ);
 
+  /**
+   * add a features file of some kind to the current view
+   * 
+   * @param file
+   * @param protocol
+   * @param relaxedIdMatching
+   *          if true, try harder to match up IDs with local sequence data
+   * @return true if parsing resulted in something being imported to the view or
+   *         dataset
+   */
+  public boolean parseFeaturesFile(String file, String protocol,
+          boolean relaxedIdMatching);
+
 }
index 34ee209..93b2134 100644 (file)
  */
 package jalview.api;
 
-import java.awt.Color;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-
 import jalview.analysis.Conservation;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
@@ -36,6 +31,11 @@ import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.schemes.ColourSchemeI;
 
+import java.awt.Color;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
 /**
  * @author jimp
  * 
@@ -372,11 +372,4 @@ public interface AlignViewportI extends ViewStyleI
    * Set whether view should scroll to show the highlighted region of a sequence
    */
   void setFollowHighlight(boolean b);
-
-  public FeatureRenderer getFeatureRenderer();
-
-  public void setFeatureRenderer(FeatureRenderer featureRenderer);
-
-  public boolean isIncludeHiddenRegion();
-
 }
index 79911d9..cf98b2f 100644 (file)
@@ -24,7 +24,6 @@ import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 
 import java.awt.Color;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 
@@ -37,42 +36,145 @@ import java.util.Map;
 public interface FeatureRenderer
 {
 
+  /**
+   * compute the perceived colour for a given column position in sequenceI,
+   * taking transparency and feature visibility into account.
+   * 
+   * @param col
+   *          - background colour (due to alignment/group shading schemes, etc).
+   * @param sequenceI
+   *          - sequence providing features
+   * @param r
+   *          - column position
+   * @return
+   */
   Color findFeatureColour(Color col, SequenceI sequenceI, int r);
 
+  /**
+   * trigger the feature discovery process for a newly created feature renderer.
+   */
   void featuresAdded();
 
+  /**
+   * 
+   * @param ft
+   * @return display style for a feature
+   */
   Object getFeatureStyle(String ft);
 
+  /**
+   * update the feature style for a particular feature
+   * 
+   * @param ft
+   * @param ggc
+   *          - currently allows java.awt.Color and
+   *          jalview.schemes.GraduatedColor
+   */
   void setColour(String ft, Object ggc);
 
   AlignViewportI getViewport();
 
+  /**
+   * 
+   * @return container managing list of feature types and their visibility
+   */
   FeaturesDisplayedI getFeaturesDisplayed();
 
+  /**
+   * get display style for all features types - visible or invisible
+   * 
+   * @return
+   */
   Map<String,Object> getFeatureColours();
 
+  /**
+   * query the alignment view to find all features
+   * 
+   * @param newMadeVisible
+   *          - when true, automatically make newly discovered types visible
+   */
   void findAllFeatures(boolean newMadeVisible);
 
+  /**
+   * get display style for all features types currently visible
+   * 
+   * @return
+   */
   Map<String,Object> getDisplayedFeatureCols();
 
+  /**
+   * get all registered groups
+   * 
+   * @return
+   */
   List<String> getFeatureGroups();
 
+  /**
+   * get groups that are visible/invisible
+   * 
+   * @param visible
+   * @return
+   */
   List<String> getGroups(boolean visible);
 
+  /**
+   * change visibility for a range of groups
+   * 
+   * @param toset
+   * @param visible
+   */
   void setGroupVisibility(List<String> toset, boolean visible);
 
+  /**
+   * change visibiilty of given group
+   * 
+   * @param group
+   * @param visible
+   */
   void setGroupVisibility(String group, boolean visible);
 
+  /**
+   * locate features at a particular position on the given sequence
+   * 
+   * @param sequence
+   * @param res
+   * @return
+   */
   List<SequenceFeature> findFeaturesAtRes(SequenceI sequence, int res);
 
+  /**
+   * 
+   * @return true if the rendering platform supports transparency
+   */
   boolean isTransparencyAvailable();
 
+  /**
+   * get current displayed types
+   * 
+   * @return
+   */
+
   String[] getDisplayedFeatureTypes();
 
+  /**
+   * get current displayed groups
+   * 
+   * @return
+   */
   String[] getDisplayedFeatureGroups();
 
+  /**
+   * display all features of these types
+   * 
+   * @param featureTypes
+   */
   void setAllVisible(List<String> featureTypes);
 
+  /**
+   * display featureType
+   * 
+   * @param featureType
+   */
   void setVisible(String featureType);
 
 }
index c718e36..2bcd667 100644 (file)
@@ -2,5 +2,7 @@ package jalview.api;
 
 public interface FeatureSettingsControllerI
 {
+
+  void discoverAllFeatureData();
   
 }
index d71fdd4..f16da84 100644 (file)
  */
 package jalview.appletgui;
 
-import java.awt.CheckboxMenuItem;
-import java.awt.Frame;
-import java.awt.Menu;
-import java.awt.MenuItem;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.Vector;
-
 import jalview.analysis.AAFrequency;
 import jalview.analysis.AlignmentAnnotationUtils;
 import jalview.analysis.AlignmentUtils;
@@ -67,6 +51,22 @@ import jalview.schemes.ZappoColourScheme;
 import jalview.util.MessageManager;
 import jalview.util.UrlLink;
 
+import java.awt.CheckboxMenuItem;
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuItem;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.Vector;
+
 public class APopupMenu extends java.awt.PopupMenu implements
         ActionListener, ItemListener
 {
@@ -832,7 +832,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
     // TODO consider using getSequenceSelection instead here
 
     cap.setText(new jalview.io.AppletFormatAdapter().formatSequences(
-            e.getActionCommand(), ap.av.getShowJVSuffix(), ap.av, true));
+            e.getActionCommand(), ap.av.getShowJVSuffix(), ap, true));
 
   }
 
@@ -898,7 +898,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
   {
     if (seq.getPDBId() != null)
     {
-      PDBEntry entry = (PDBEntry) seq.getPDBId().firstElement();
+      PDBEntry entry = seq.getPDBId().firstElement();
 
       if (ap.av.applet.jmolAvailable)
       {
index 1510a14..ca1d158 100644 (file)
  */
 package jalview.appletgui;
 
-import java.awt.BorderLayout;
-import java.awt.Canvas;
-import java.awt.CheckboxMenuItem;
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.Frame;
-import java.awt.Graphics;
-import java.awt.Label;
-import java.awt.Menu;
-import java.awt.MenuBar;
-import java.awt.MenuItem;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.KeyListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.io.IOException;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.util.Arrays;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
 import jalview.analysis.AlignmentSorter;
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.api.AlignViewControllerGuiI;
 import jalview.api.AlignViewControllerI;
 import jalview.api.AlignViewportI;
 import jalview.api.FeatureRenderer;
+import jalview.api.FeatureSettingsControllerI;
 import jalview.api.SequenceStructureBinding;
 import jalview.bin.JalviewLite;
 import jalview.commands.CommandI;
@@ -105,6 +72,40 @@ import jalview.util.MappingUtils;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 
+import java.awt.BorderLayout;
+import java.awt.Canvas;
+import java.awt.CheckboxMenuItem;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Label;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
 public class AlignFrame extends EmbmenuFrame implements ActionListener,
         ItemListener, KeyListener, AlignViewControllerGuiI
 {
@@ -209,7 +210,6 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     if (hiddenSeqs != null && hiddenSeqs.length > 0)
     {
       viewport.hideSequence(hiddenSeqs);
-      viewport.setHasHiddenRows(true);
     }
     if (columnSelection != null)
     {
@@ -1340,9 +1340,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
             { e.getActionCommand() }), 600, 500);
 
     FeatureRenderer fr = this.alignPanel.cloneFeatureRenderer();
-    viewport.setFeatureRenderer(fr);
-    viewport.setIncludeHiddenRegion(false);
-    cap.setText(new AppletFormatAdapter(viewport).formatSequences(
+    cap.setText(new AppletFormatAdapter(alignPanel).formatSequences(
             e.getActionCommand(), viewport.getAlignment(),
             viewport.getShowJVSuffix()));
   }
@@ -4207,4 +4205,36 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
   {
     this.splitFrame = sf;
   }
+
+    // may not need this
+  @Override
+  public void setShowSeqFeatures(boolean b)
+  {
+    // showSeqFeatures.setSelected(b);
+    viewport.setShowSequenceFeatures(b);
+
+  }
+
+  @Override
+  public void setMenusForViewport()
+  {
+    // setMenusFromViewport(viewport);
+
+  }
+  @Override
+  public void refreshFeatureUI(boolean enableIfNecessary)
+  {
+    if (enableIfNecessary)
+    {
+      sequenceFeatures.setState(true);
+      alignPanel.av.setShowSequenceFeatures(true);
+    }
+  }
+
+  @Override
+  public FeatureSettingsControllerI getFeatureSettingsUI()
+  {
+    return alignPanel.av.featureSettings;
+  }
+
 }
index 607dc05..e4e3e17 100644 (file)
  */
 package jalview.appletgui;
 
-import java.awt.Font;
-
 import jalview.analysis.NJTree;
 import jalview.api.AlignViewportI;
-import jalview.api.FeatureRenderer;
 import jalview.bin.JalviewLite;
 import jalview.commands.CommandI;
 import jalview.datamodel.AlignmentI;
@@ -41,6 +38,8 @@ import jalview.structure.StructureSelectionManager;
 import jalview.structure.VamsasSource;
 import jalview.viewmodel.AlignmentViewport;
 
+import java.awt.Font;
+
 public class AlignViewport extends AlignmentViewport implements
         SelectionSource, VamsasSource, CommandListener
 {
@@ -58,10 +57,6 @@ public class AlignViewport extends AlignmentViewport implements
 
   private AnnotationColumnChooser annotationColumnSelectionState;
 
-  private FeatureRenderer featureRenderer;
-
-  private boolean includeHiddenRegion = true;
-
   public void finalize()
   {
     applet = null;
@@ -472,27 +467,5 @@ public class AlignViewport extends AlignmentViewport implements
     }
   }
 
-  @Override
-  public FeatureRenderer getFeatureRenderer()
-  {
-    return featureRenderer;
-  }
-
-  @Override
-  public void setFeatureRenderer(FeatureRenderer featureRenderer)
-  {
-    this.featureRenderer = featureRenderer;
-
-  }
-
-  public boolean isIncludeHiddenRegion()
-  {
-    return includeHiddenRegion;
-  }
-
-  public void setIncludeHiddenRegion(boolean includeHiddenRegion)
-  {
-    this.includeHiddenRegion = includeHiddenRegion;
-  }
 
 }
index bb2fa12..535dc62 100644 (file)
  */
 package jalview.appletgui;
 
-import java.awt.BorderLayout;
-import java.awt.Button;
-import java.awt.Dialog;
-import java.awt.Font;
-import java.awt.Frame;
-import java.awt.Label;
-import java.awt.Panel;
-import java.awt.TextArea;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-
 import jalview.analysis.AlignmentUtils;
 import jalview.api.ComplexAlignFile;
 import jalview.bin.JalviewLite;
-import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.PDBEntry;
@@ -51,6 +37,19 @@ import jalview.schemes.ColourSchemeI;
 import jalview.schemes.TCoffeeColourScheme;
 import jalview.util.MessageManager;
 
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Dialog;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.Label;
+import java.awt.Panel;
+import java.awt.TextArea;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
 public class CutAndPasteTransfer extends Panel implements ActionListener,
         MouseListener
 {
@@ -221,11 +220,11 @@ public class CutAndPasteTransfer extends Panel implements ActionListener,
   protected void loadAlignment(String text, boolean newWindow,
           AlignViewport viewport)
   {
-    Alignment al = null;
+    AlignmentI al = null;
 
     String format = new IdentifyFile().Identify(text,
             AppletFormatAdapter.PASTE);
-    AppletFormatAdapter afa = new AppletFormatAdapter(viewport);
+    AppletFormatAdapter afa = new AppletFormatAdapter(alignFrame.alignPanel);
     try
     {
       al = afa.readFile(text, AppletFormatAdapter.PASTE, format);
@@ -294,7 +293,7 @@ public class CutAndPasteTransfer extends Panel implements ActionListener,
    * @param al
    * @return
    */
-  protected boolean openSplitFrame(Alignment al, String format)
+  protected boolean openSplitFrame(AlignmentI al, String format)
   {
     final AlignmentI thisAlignment = this.alignFrame.getAlignViewport().getAlignment();
     if (thisAlignment.isNucleotide() == al.isNucleotide())
index 8ce3e62..2b79256 100755 (executable)
  */
 package jalview.appletgui;
 
-import java.util.*;
-import java.util.List;
-import java.awt.*;
-import java.awt.event.*;
-
-import jalview.analysis.AlignmentSorter;
-import jalview.commands.OrderCommand;
-import jalview.datamodel.*;
+import jalview.api.FeatureSettingsControllerI;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceFeature;
 import jalview.schemes.AnnotationColourGradient;
 import jalview.schemes.GraduatedColor;
 import jalview.util.MessageManager;
 
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Checkbox;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.GridLayout;
+import java.awt.Image;
+import java.awt.Label;
+import java.awt.MenuItem;
+import java.awt.Panel;
+import java.awt.PopupMenu;
+import java.awt.ScrollPane;
+import java.awt.Scrollbar;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.AdjustmentEvent;
+import java.awt.event.AdjustmentListener;
+import java.awt.event.InputEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Vector;
+
 public class FeatureSettings extends Panel implements ItemListener,
         MouseListener, MouseMotionListener, ActionListener,
-        AdjustmentListener
+        AdjustmentListener, FeatureSettingsControllerI
 {
   FeatureRenderer fr;
 
@@ -84,7 +114,7 @@ public class FeatureSettings extends Panel implements ItemListener,
       fr.findAllFeatures(true); // was default - now true to make all visible
     }
 
-    setTableData();
+    discoverAllFeatureData();
 
     this.setLayout(new BorderLayout());
     scrollPane = new ScrollPane();
@@ -249,7 +279,8 @@ public class FeatureSettings extends Panel implements ItemListener,
     men.show(this.featurePanel, x, y);
   }
 
-  public void setTableData()
+  @Override
+  public void discoverAllFeatureData()
   {
     if (fr.getAllFeatureColours()!=null && fr.getAllFeatureColours().size()>0)
     {
@@ -276,7 +307,7 @@ public class FeatureSettings extends Panel implements ItemListener,
     }
     // TODO: JAL-964 - smoothly incorporate new group entries if panel already
     // displayed and new groups present
-    for (String group:(List<String>)fr.getFeatureGroups())
+    for (String group:fr.getFeatureGroups())
     {
       boolean vis = fr.checkGroupVisibility(group, false);
       Checkbox check = new MyCheckbox(group, vis,
@@ -648,7 +679,7 @@ public class FeatureSettings extends Panel implements ItemListener,
 
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
-    fr.setTransparency((float) (100 - transparency.getValue()) / 100f);
+    fr.setTransparency((100 - transparency.getValue()) / 100f);
     ap.seqPanel.seqCanvas.repaint();
 
   }
index 7f9eba9..5204094 100755 (executable)
@@ -56,7 +56,8 @@ public class IdCanvas extends Panel
     PaintRefresher.Register(this, av.getSequenceSetId());
   }
 
-  public void drawIdString(Graphics gg, SequenceI s, int i, int starty,
+  public void drawIdString(Graphics gg, boolean hiddenRows, SequenceI s,
+          int i, int starty,
           int ypos)
   {
     int charHeight = av.getCharHeight();
@@ -88,7 +89,7 @@ public class IdCanvas extends Panel
             ((i - starty) * charHeight) + ypos + charHeight
                     - (charHeight / 5));
 
-    if (av.hasHiddenRows() && av.getShowHiddenMarkers())
+    if (hiddenRows)
     {
       drawMarker(i, starty, ypos);
     }
@@ -199,6 +200,10 @@ public class IdCanvas extends Panel
     Color currentColor = Color.white;
     Color currentTextColor = Color.black;
 
+    final boolean doHiddenCheck = av.isDisplayReferenceSeq()
+            || av.hasHiddenRows(), hiddenRows = av.hasHiddenRows()
+            && av.getShowHiddenMarkers();
+
     if (av.getWrapAlignment())
     {
       int maxwidth = av.getAlignment().getWidth();
@@ -227,7 +232,6 @@ public class IdCanvas extends Panel
       int cHeight = alheight * avcharHeight + hgap + annotationHeight;
 
       int rowSize = av.getEndRes() - av.getStartRes();
-
       // Draw the rest of the panels
       for (int ypos = hgap, row = av.startRes; (ypos <= getSize().height)
               && (row < maxwidth); ypos += cHeight, row += rowSize)
@@ -237,11 +241,11 @@ public class IdCanvas extends Panel
 
           SequenceI s = av.getAlignment().getSequenceAt(i);
           gg.setFont(italic);
-          if (av.isDisplayReferenceSeq() || av.hasHiddenRows())
+          if (doHiddenCheck)
           {
             setHiddenFont(s);
           }
-          drawIdString(gg, s, i, 0, ypos);
+          drawIdString(gg, hiddenRows, s, i, 0, ypos);
         }
 
         if (labels != null)
@@ -267,7 +271,7 @@ public class IdCanvas extends Panel
         }
         gg.setFont(italic);
         // boolean isrep=false;
-        if (av.isDisplayReferenceSeq() || av.hasHiddenRows())
+        if (doHiddenCheck)
         {
           // isrep =
           setHiddenFont(seq);
@@ -302,7 +306,7 @@ public class IdCanvas extends Panel
                 (((i - starty) * avcharHeight) + avcharHeight)
                         - (avcharHeight / 5));
 
-        if (av.hasHiddenRows() && av.getShowHiddenMarkers())
+        if (hiddenRows)
         {
           drawMarker(i, starty, 0);
         }
index 3301543..f09bda5 100755 (executable)
@@ -22,8 +22,17 @@ package jalview.appletgui;
 
 import jalview.datamodel.AlignmentI;
 
-import java.awt.*;
-import java.awt.event.*;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Panel;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
 
 public class OverviewPanel extends Panel implements Runnable,
         MouseMotionListener, MouseListener
@@ -289,6 +298,8 @@ public class OverviewPanel extends Panel implements Runnable,
     Color color = Color.yellow;
     int row, col, sameRow = 0, sameCol = 0;
     jalview.datamodel.SequenceI seq;
+    final boolean hasHiddenRows = av.hasHiddenRows(), hasHiddenCols = av
+            .hasHiddenColumns();
     boolean hiddenRow = false;
     AlignmentI alignment = av.getAlignment();
     for (row = 0; row <= sequencesHeight; row++)
@@ -300,7 +311,7 @@ public class OverviewPanel extends Panel implements Runnable,
       }
 
       hiddenRow = false;
-      if (av.hasHiddenRows())
+      if (hasHiddenRows)
       {
         seq = alignment.getHiddenSequences().getHiddenSequence(lastrow);
         if (seq == null)
@@ -346,7 +357,7 @@ public class OverviewPanel extends Panel implements Runnable,
         }
 
         if (hiddenRow
-                || (av.hasHiddenColumns() && !av.getColumnSelection()
+                || (hasHiddenCols && !av.getColumnSelection()
                         .isVisible(lastcol)))
         {
           color = color.darker().darker();
index ebadb84..ae5c63f 100644 (file)
  */
 package jalview.bin;
 
-import java.applet.Applet;
-import java.awt.Button;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.EventQueue;
-import java.awt.Font;
-import java.awt.Frame;
-import java.awt.Graphics;
-import java.awt.event.ActionEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
-import netscape.javascript.JSException;
-import netscape.javascript.JSObject;
-
 import jalview.api.StructureSelectionManagerProvider;
 import jalview.appletgui.AlignFrame;
 import jalview.appletgui.AlignViewport;
@@ -72,6 +48,30 @@ import jalview.structure.SelectionListener;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 
+import java.applet.Applet;
+import java.awt.Button;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.EventQueue;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import netscape.javascript.JSException;
+import netscape.javascript.JSObject;
+
 /**
  * Jalview Applet. Runs in Java 1.18 runtime
  * 
@@ -847,7 +847,7 @@ public class JalviewLite extends Applet implements
    */
   public AlignFrame loadAlignment(String text, String title)
   {
-    Alignment al = null;
+    AlignmentI al = null;
 
     String format = new IdentifyFile().Identify(text,
             AppletFormatAdapter.PASTE);
index 462cb81..6be1016 100644 (file)
@@ -20,7 +20,7 @@
  */
 package jalview.bin;
 
-import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
 import jalview.io.AppletFormatAdapter;
 import jalview.io.FileParse;
 
@@ -120,7 +120,7 @@ public class JalviewLiteURLRetrieve extends Applet
       {
         System.out.println("User specified Format is " + format);
       }
-      Alignment al = null;
+      AlignmentI al = null;
       try
       {
         al = new AppletFormatAdapter().readFile(file, protocol, format);
index 972b6ab..3be32bb 100644 (file)
@@ -33,6 +33,7 @@ import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.io.FeaturesFile;
 import jalview.util.MessageManager;
 
 import java.awt.Color;
@@ -379,4 +380,38 @@ public class AlignViewController implements AlignViewControllerI
   {
     sortBy(typ, "Sort by Feature Score", AlignmentSorter.FEATURE_SCORE);
   }
+
+  @Override
+  public boolean parseFeaturesFile(String file, String protocol,
+          boolean relaxedIdMatching)
+  {
+    boolean featuresFile = false;
+    try
+    {
+      featuresFile = new FeaturesFile(file, protocol).parse(viewport
+              .getAlignment().getDataset(), alignPanel.getFeatureRenderer()
+              .getFeatureColours(), false, relaxedIdMatching);
+    } catch (Exception ex)
+    {
+      ex.printStackTrace();
+    }
+
+    if (featuresFile)
+    {
+      avcg.refreshFeatureUI(true);
+      if (alignPanel.getFeatureRenderer() != null)
+      {
+        // update the min/max ranges where necessary
+        alignPanel.getFeatureRenderer().findAllFeatures(true);
+      }
+      if (avcg.getFeatureSettingsUI() != null)
+      {
+        avcg.getFeatureSettingsUI().discoverAllFeatureData();
+      }
+      alignPanel.paintAlignment(true);
+    }
+
+    return featuresFile;
+
+  }
 }
index ebf4958..7dd1399 100644 (file)
@@ -3,7 +3,8 @@ package jalview.controller;
 import jalview.api.FeatureRenderer;
 import jalview.api.FeatureSettingsModelI;
 
-public class FeatureSettingsController implements jalview.api.FeatureSettingsControllerI
+public class FeatureSettingsController // implements
+                                       // jalview.api.FeatureSettingsControllerI
 {
   FeatureSettingsControllerGuiI settingUI;
   FeatureRenderer fr;
diff --git a/src/jalview/datamodel/ASequence.java b/src/jalview/datamodel/ASequence.java
new file mode 100755 (executable)
index 0000000..238fd38
--- /dev/null
@@ -0,0 +1,16 @@
+/**
+ * 
+ */
+package jalview.datamodel;
+
+/**
+ * Metadata for a sequence that may or may not be physically present in Jalview
+ * at the moment
+ * 
+ * @author jprocter
+ *
+ */
+public class ASequence implements ASequenceI
+{
+
+}
diff --git a/src/jalview/datamodel/ASequenceI.java b/src/jalview/datamodel/ASequenceI.java
new file mode 100755 (executable)
index 0000000..481b1e3
--- /dev/null
@@ -0,0 +1,12 @@
+package jalview.datamodel;
+
+/**
+ * interfaces to access the basic metadata for a concrete or virtual sequence
+ * 
+ * @author jprocter
+ *
+ */
+public interface ASequenceI
+{
+
+}
index 0daa3fb..12eb470 100644 (file)
@@ -7,6 +7,8 @@ package jalview.datamodel;
  * 
  * Example: in "G-AT-C-GA" the aligned codons are (0, 2, 3) and (5, 7, 8).
  * 
+ * JBPComment: Is this useful anywhere other than jalview.analysis.Dna ?
+ * 
  * @author gmcarstairs
  *
  */
index d0b2731..eb977bc 100644 (file)
@@ -33,12 +33,12 @@ import jalview.util.MappingUtils;
 public class AlignedCodonFrame
 {
 
-  /*
+  /**
    * tied array of na Sequence objects.
    */
   private SequenceI[] dnaSeqs = null;
 
-  /*
+  /**
    * tied array of Mappings to protein sequence Objects and SequenceI[]
    * aaSeqs=null; MapLists where each maps from the corresponding dnaSeqs
    * element to corresponding aaSeqs element
index 835d7e9..3916b7d 100644 (file)
@@ -1138,7 +1138,7 @@ public class ColumnSelection
    *         profileseq marked as hidden.
    */
   public static ColumnSelection propagateInsertions(SequenceI profileseq,
-          Alignment al, AlignmentView input)
+          AlignmentI al, AlignmentView input)
   {
     int profsqpos = 0;
 
index 9e93444..37bb7a9 100755 (executable)
@@ -37,7 +37,7 @@ import jalview.util.StringUtils;
  * @author $author$
  * @version $Revision$
  */
-public class Sequence implements SequenceI
+public class Sequence extends ASequence implements SequenceI
 {
   SequenceI datasetSequence;
 
@@ -91,20 +91,30 @@ public class Sequence implements SequenceI
    */
   public Sequence(String name, String sequence, int start, int end)
   {
-    this.name = name;
-    this.sequence = sequence.toCharArray();
-    this.start = start;
-    this.end = end;
-    parseId();
-    checkValidRange();
+    initSeqAndName(name, sequence.toCharArray(), start, end);
   }
 
   public Sequence(String name, char[] sequence, int start, int end)
   {
-    this.name = name;
-    this.sequence = sequence;
-    this.start = start;
-    this.end = end;
+    initSeqAndName(name, sequence, start, end);
+  }
+
+  /**
+   * Stage 1 constructor - assign name, sequence, and set start and end fields.
+   * start and end are updated values from name2 if it ends with /start-end
+   * 
+   * @param name2
+   * @param sequence2
+   * @param start2
+   * @param end2
+   */
+  protected void initSeqAndName(String name2, char[] sequence2, int start2,
+          int end2)
+  {
+    this.name = name2;
+    this.sequence = sequence2;
+    this.start = start2;
+    this.end = end2;
     parseId();
     checkValidRange();
   }
@@ -197,7 +207,15 @@ public class Sequence implements SequenceI
    */
   public Sequence(SequenceI seq, AlignmentAnnotation[] alAnnotation)
   {
-    this(seq.getName(), seq.getSequence(), seq.getStart(), seq.getEnd());
+    initSeqFrom(seq, alAnnotation);
+
+  }
+
+  protected void initSeqFrom(SequenceI seq,
+          AlignmentAnnotation[] alAnnotation)
+  {
+    initSeqAndName(seq.getName(), seq.getSequence(), seq.getStart(),
+            seq.getEnd());
     description = seq.getDescription();
     if (seq.getSequenceFeatures() != null)
     {
diff --git a/src/jalview/datamodel/SequenceDummy.java b/src/jalview/datamodel/SequenceDummy.java
new file mode 100644 (file)
index 0000000..4a8c3ee
--- /dev/null
@@ -0,0 +1,32 @@
+package jalview.datamodel;
+
+public class SequenceDummy extends Sequence implements SequenceI
+{
+  public SequenceDummy(String sequenceId)
+  {
+    super(sequenceId, "THISAPLACEHOLDER");
+  }
+
+  private boolean dummy = true;
+  /**
+   * become a proxy for mseq, merging any existing annotation on this sequence
+   * 
+   * @param mseq
+   */
+  public void become(SequenceI mseq)
+  {
+    initSeqFrom(mseq, null);
+    dummy=false;
+  }
+
+  /**
+   * Test if the SequenceDummy has been promoted to a real sequence via
+   * SequenceDummy.become
+   * 
+   * @return true if this is a placeholder and contains no actual sequence data
+   */
+  public boolean isDummy()
+  {
+    return dummy;
+  }
+}
index 28ab82c..1b6498f 100755 (executable)
@@ -302,4 +302,23 @@ public class SequenceFeature
     return begin;
   }
 
+  public int getStrand()
+  {
+    String str;
+    if (otherDetails == null
+            || (str = otherDetails.get("STRAND").toString()) == null)
+    {
+      return 0;
+    }
+    if (str.equals("-"))
+    {
+      return -1;
+    }
+    if (str.equals("+"))
+    {
+      return 1;
+    }
+    return 0;
+  }
+
 }
index 38ae372..f69c8b6 100755 (executable)
@@ -26,12 +26,13 @@ import java.util.Vector;
 import fr.orsay.lri.varna.models.rna.RNA;
 
 /**
- * DOCUMENT ME!
+ * Methods for manipulating a sequence, its metadata and related annotation in
+ * an alignment or dataset.
  * 
  * @author $author$
  * @version $Revision$
  */
-public interface SequenceI
+public interface SequenceI extends ASequenceI
 {
   /**
    * Set the display name for the sequence
diff --git a/src/jalview/gui/AlignExportSettings.java b/src/jalview/gui/AlignExportSettings.java
new file mode 100644 (file)
index 0000000..fe7c940
--- /dev/null
@@ -0,0 +1,115 @@
+package jalview.gui;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.JDialog;
+import javax.swing.JInternalFrame;
+import javax.swing.JOptionPane;
+
+import jalview.api.AlignExportSettingI;
+import jalview.jbgui.GAlignExportSettings;
+
+@SuppressWarnings("serial")
+public class AlignExportSettings extends GAlignExportSettings implements
+        AlignExportSettingI
+{
+  protected JInternalFrame frame;
+
+  boolean cancelled = false;
+
+  private int width = 450;
+
+  private int height = 200;
+
+  JDialog dialog;
+
+  public AlignExportSettings(boolean hasHiddenSeq, boolean hasHiddenCols,
+          String alignFileFormat)
+  {
+    super(hasHiddenSeq, hasHiddenCols, alignFileFormat);
+
+    // frame = new JInternalFrame();
+    // frame.setContentPane(this);
+    // frame.setLayer(JLayeredPane.PALETTE_LAYER);
+    // Desktop.addInternalFrame(frame, "Export Settings", width, height);
+
+    JOptionPane pane = new JOptionPane(null, JOptionPane.DEFAULT_OPTION,
+            JOptionPane.DEFAULT_OPTION, null, new Object[]
+            { this });
+    dialog = pane.createDialog(Desktop.desktop, "Export Settings");
+
+    // dialog = new JDialog(Desktop.instance, true);
+    // dialog.setTitle("Export Settings");
+
+    dialog.pack();
+    dialog.setVisible(true);
+
+    dialog.setContentPane(this);
+    dialog.validate();
+
+  }
+
+  // public static void main(String[] args)
+  // {
+  // new AlignExportSettings(false, false, false);
+  // }
+
+  // public void cancel_actionPerformed(ActionEvent e)
+  // {
+    // try
+    // {
+    // frame.setClosed(true);
+    // } catch (Exception ex)
+    // {
+    // }
+  // }
+
+  public void ok_actionPerformed(ActionEvent e)
+  {
+    cancelled = false;
+    dialog.setVisible(false);
+  }
+
+  public void cancel_actionPerformed(ActionEvent e)
+  {
+    cancelled = true;
+    dialog.setVisible(false);
+  }
+
+  @Override
+  public boolean isExportHiddenSequences()
+  {
+    return chkHiddenSeqs.isSelected();
+  }
+
+  @Override
+  public boolean isExportHiddenColumns()
+  {
+    return chkHiddenCols.isSelected();
+  }
+
+  @Override
+  public boolean isExportAnnotations()
+  {
+    return chkExportAnnots.isSelected();
+  }
+
+  @Override
+  public boolean isExportFeatures()
+  {
+    return chkExportFeats.isSelected();
+  }
+
+  @Override
+  public boolean isExportGroups()
+  {
+    return chkExportGrps.isSelected();
+  }
+
+  @Override
+  public boolean isCancelled()
+  {
+    return cancelled;
+  }
+
+}
index db61f77..01353d8 100644 (file)
  */
 package jalview.gui;
 
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Rectangle;
-import java.awt.Toolkit;
-import java.awt.datatransfer.Clipboard;
-import java.awt.datatransfer.DataFlavor;
-import java.awt.datatransfer.StringSelection;
-import java.awt.datatransfer.Transferable;
-import java.awt.dnd.DnDConstants;
-import java.awt.dnd.DropTargetDragEvent;
-import java.awt.dnd.DropTargetDropEvent;
-import java.awt.dnd.DropTargetEvent;
-import java.awt.dnd.DropTargetListener;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.print.PageFormat;
-import java.awt.print.PrinterJob;
-import java.beans.PropertyChangeEvent;
-import java.io.File;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Deque;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Set;
-import java.util.Vector;
-
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JEditorPane;
-import javax.swing.JInternalFrame;
-import javax.swing.JLayeredPane;
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
-import javax.swing.JRadioButtonMenuItem;
-import javax.swing.JScrollPane;
-import javax.swing.SwingUtilities;
-
 import jalview.analysis.AAFrequency;
 import jalview.analysis.AlignmentSorter;
 import jalview.analysis.AlignmentUtils;
@@ -74,10 +28,12 @@ import jalview.analysis.CrossRef;
 import jalview.analysis.Dna;
 import jalview.analysis.ParseProperties;
 import jalview.analysis.SequenceIdMatcher;
+import jalview.api.AlignExportSettingI;
 import jalview.api.AlignViewControllerGuiI;
 import jalview.api.AlignViewControllerI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
+import jalview.api.FeatureSettingsControllerI;
 import jalview.api.SplitContainerI;
 import jalview.api.ViewStyleI;
 import jalview.api.analysis.ScoreModelI;
@@ -107,7 +63,6 @@ import jalview.gui.ViewSelectionMenu.ViewSetProvider;
 import jalview.io.AlignmentProperties;
 import jalview.io.AnnotationFile;
 import jalview.io.BioJsHTMLOutput;
-import jalview.io.FeaturesFile;
 import jalview.io.FileLoader;
 import jalview.io.FormatAdapter;
 import jalview.io.HtmlSvgOutput;
@@ -144,6 +99,52 @@ import jalview.ws.jws2.Jws2Discoverer;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.seqfetcher.DbSourceProxy;
 
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetEvent;
+import java.awt.dnd.DropTargetListener;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.print.PageFormat;
+import java.awt.print.PrinterJob;
+import java.beans.PropertyChangeEvent;
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JEditorPane;
+import javax.swing.JInternalFrame;
+import javax.swing.JLayeredPane;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+
 /**
  * DOCUMENT ME!
  * 
@@ -305,7 +306,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     if (hiddenSeqs != null && hiddenSeqs.length > 0)
     {
       viewport.hideSequence(hiddenSeqs);
-      viewport.setHasHiddenRows(true);
     }
     alignPanel = new AlignmentPanel(this, viewport);
     addAlignmentPanel(alignPanel, true);
@@ -1140,8 +1140,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         return false;
       }
 
-      ExportData exportData = getAlignmentForExport();
-      FormatAdapter f = new FormatAdapter(viewport);
+      ExportData exportData = getAlignmentForExport(format);
+      FormatAdapter f = new FormatAdapter(alignPanel);
       String output = f.formatSequences(format,
               exportData.getAlignment(), // class cast exceptions will
               // occur in the distant future
@@ -1213,13 +1213,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void outputText_actionPerformed(ActionEvent e)
   {
 
-    ExportData exportData = getAlignmentForExport();
+    ExportData exportData = getAlignmentForExport(e.getActionCommand());
+    if (exportData.getSettings().isCancelled())
+    {
+      return;
+    }
     CutAndPasteTransfer cap = new CutAndPasteTransfer();
     cap.setForInput(null);
-
     try
     {
-      cap.setText(new FormatAdapter(viewport).formatSequences(
+      cap.setText(new FormatAdapter(alignPanel, exportData.getSettings())
+              .formatSequences(
               e.getActionCommand(),
  exportData.getAlignment(),
               exportData.getOmitHidden(), exportData.getStartEndPostions(),
@@ -1235,13 +1239,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
   }
 
-  public ExportData getAlignmentForExport()
+  public ExportData getAlignmentForExport(String exportFomat)
   {
     AlignmentI alignmentToExport = null;
     String[] omitHidden = null;
     int[] alignmentStartEnd = new int[2];
-    FeatureRenderer fr = new FeatureRenderer(this.alignPanel);
-    viewport.setFeatureRenderer(fr);
+
     HiddenSequences hiddenSeqs = viewport.getAlignment()
             .getHiddenSequences();
 
@@ -1250,36 +1253,28 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     alignmentStartEnd = new int[]
     { 0, alignmentToExport.getWidth() - 1 };
 
-    if (viewport.hasHiddenColumns() || hiddenSeqs.getSize() > 0)
-    {
-      int reply = JOptionPane
-              .showInternalConfirmDialog(
-                      Desktop.desktop,
-                      MessageManager
-                              .getString("label.alignment_contains_hidden_columns"),
-                      MessageManager
-                              .getString("action.save_omit_hidden_columns"),
-                      JOptionPane.YES_NO_OPTION,
-                      JOptionPane.QUESTION_MESSAGE);
+    boolean hasHiddenSeqs = hiddenSeqs.getSize() > 0;
+    AlignExportSettingI settings = new AlignExportSettings(hasHiddenSeqs,
+            viewport.hasHiddenColumns(), exportFomat);
+    settings.isExportAnnotations();
 
-      if (reply == JOptionPane.YES_OPTION)
-      {
-        // export only visible region
-        omitHidden = viewport.getViewAsString(false);
-        alignmentToExport = viewport.getAlignment();
-        alignmentStartEnd = getStartEnd(alignmentStartEnd, viewport
-                .getColumnSelection().getHiddenColumns());
-        viewport.setIncludeHiddenRegion(false);
-      }
-      else
-      {
-        // export all region including visible
-        alignmentToExport = hiddenSeqs.getFullAlignment();
-        viewport.setIncludeHiddenRegion(true);
-      }
+    if (viewport.hasHiddenColumns() && !settings.isExportHiddenColumns())
+    {
+      omitHidden = viewport.getViewAsString(false);
     }
 
-    return new ExportData(alignmentToExport, omitHidden, alignmentStartEnd);
+    if (hasHiddenSeqs && settings.isExportHiddenSequences())
+    {
+      alignmentToExport = hiddenSeqs.getFullAlignment();
+    }
+    else
+    {
+      alignmentToExport = viewport.getAlignment();
+      alignmentStartEnd = getStartEnd(alignmentStartEnd, viewport
+              .getColumnSelection().getHiddenColumns());
+    }
+    return new ExportData(alignmentToExport, omitHidden, alignmentStartEnd,
+            settings);
   }
 
   private static int[] getStartEnd(int[] aligmentStartEnd,
@@ -1352,17 +1347,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   protected void htmlMenuItem_actionPerformed(ActionEvent e)
   {
-    // new HTMLOutput(alignPanel,
-    // alignPanel.getSeqPanel().seqCanvas.getSequenceRenderer(),
-    // alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer());
     new HtmlSvgOutput(null, alignPanel);
   }
 
   @Override
   public void bioJSMenuItem_actionPerformed(ActionEvent e)
   {
-    BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel,
-            alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer());
+    BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel);
     bjs.exportJalviewAlignmentAsBioJsHtmlFile();
   }
   public void createImageMap(File file, String image)
@@ -3159,6 +3150,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public FeatureSettings featureSettings;
 
   @Override
+  public FeatureSettingsControllerI getFeatureSettingsUI()
+  {
+    return featureSettings;
+  }
+
+  @Override
   public void featureSettings_actionPerformed(ActionEvent e)
   {
     if (featureSettings != null)
@@ -5008,41 +5005,29 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          contents or path to retrieve file
    * @param type
    *          access mode of file (see jalview.io.AlignFile)
-   * @return true if features file was parsed corectly.
+   * @return true if features file was parsed correctly.
    */
   public boolean parseFeaturesFile(String file, String type)
   {
-    boolean featuresFile = false;
-    try
-    {
-      featuresFile = new FeaturesFile(file, type).parse(viewport
-              .getAlignment().getDataset(), alignPanel.getSeqPanel().seqCanvas
-              .getFeatureRenderer().getFeatureColours(), false,
-              jalview.bin.Cache.getDefault("RELAXEDSEQIDMATCHING", false));
-    } catch (Exception ex)
-    {
-      ex.printStackTrace();
-    }
+    return avc.parseFeaturesFile(file, type,
+            jalview.bin.Cache.getDefault("RELAXEDSEQIDMATCHING", false));
+    
+  }
 
-    if (featuresFile)
+  @Override
+  public void refreshFeatureUI(boolean enableIfNecessary)
+  {
+    // note - currently this is only still here rather than in the controller
+    // because of the featureSettings hard reference that is yet to be
+    // abstracted
+    if (enableIfNecessary)
     {
       viewport.setShowSequenceFeatures(true);
       showSeqFeatures.setSelected(true);
-      if (alignPanel.getSeqPanel().seqCanvas.fr != null)
-      {
-        // update the min/max ranges where necessary
-        alignPanel.getSeqPanel().seqCanvas.fr.findAllFeatures(true);
-      }
-      if (featureSettings != null)
-      {
-        featureSettings.setTableData();
-      }
-      alignPanel.paintAlignment(true);
     }
 
-    return featuresFile;
-  }
 
+  }
   @Override
   public void dragEnter(DropTargetDragEvent evt)
   {
@@ -6094,11 +6079,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     private int[] startEnd;
 
-    public ExportData(AlignmentI align, String[] ommit, int[] startEnd)
+    private AlignExportSettingI settings;
+
+    public ExportData(AlignmentI align, String[] ommit, int[] startEnd,
+            AlignExportSettingI settings)
     {
       this.alignment = align;
       this.omitHidden = ommit;
       this.startEnd = startEnd;
+      this.settings = settings;
     }
 
     public AlignmentI getAlignment()
@@ -6130,6 +6119,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       this.startEnd = startEnd;
     }
+
+    public AlignExportSettingI getSettings()
+    {
+      return settings;
+    }
+
+    public void setSettings(AlignExportSettingI settings)
+    {
+      this.settings = settings;
+    }
   }
 
 }
index 2224021..fc889ad 100644 (file)
  */
 package jalview.gui;
 
-import java.awt.Container;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.Rectangle;
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Set;
-import java.util.Vector;
-
-import javax.swing.JInternalFrame;
-import javax.swing.JOptionPane;
-
 import jalview.analysis.AlignmentUtils;
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.analysis.NJTree;
 import jalview.api.AlignViewportI;
-import jalview.api.FeatureRenderer;
 import jalview.api.ViewStyleI;
 import jalview.bin.Cache;
 import jalview.commands.CommandI;
@@ -78,6 +64,19 @@ import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.ws.params.AutoCalcSetting;
 
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Rectangle;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.swing.JInternalFrame;
+import javax.swing.JOptionPane;
+
 /**
  * DOCUMENT ME!
  * 
@@ -97,9 +96,6 @@ public class AlignViewport extends AlignmentViewport implements
 
   private Rectangle explodedGeometry;
 
-  private FeatureRenderer featureRenderer;
-
-  private boolean includeHiddenRegion = true;
   String viewName;
 
   /*
@@ -1041,25 +1037,4 @@ public class AlignViewport extends AlignmentViewport implements
     }
   }
 
-  @Override
-  public FeatureRenderer getFeatureRenderer()
-  {
-    return featureRenderer;
-  }
-
-  @Override
-  public void setFeatureRenderer(FeatureRenderer featureRenderer)
-  {
-    this.featureRenderer = featureRenderer;
-  }
-
-  public boolean isIncludeHiddenRegion()
-  {
-    return includeHiddenRegion;
-  }
-
-  public void setIncludeHiddenRegion(boolean includeHiddenRegion)
-  {
-    this.includeHiddenRegion = includeHiddenRegion;
-  }
 }
index f3c4d87..b492ddf 100644 (file)
  */
 package jalview.gui;
 
+import jalview.api.AlignViewportI;
+import jalview.api.AlignmentViewPanel;
+import jalview.api.ComplexAlignFile;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.SequenceI;
+import jalview.io.FileParse;
+import jalview.io.FormatAdapter;
+import jalview.io.IdentifyFile;
+import jalview.io.JalviewFileChooser;
+import jalview.io.JalviewFileView;
+import jalview.jbgui.GCutAndPasteTransfer;
+import jalview.schemes.ColourSchemeI;
+import jalview.util.MessageManager;
+
 import java.awt.Toolkit;
 import java.awt.datatransfer.Clipboard;
 import java.awt.datatransfer.DataFlavor;
@@ -34,19 +49,6 @@ import javax.swing.JOptionPane;
 import javax.swing.JPopupMenu;
 import javax.swing.SwingUtilities;
 
-import jalview.api.ComplexAlignFile;
-import jalview.datamodel.Alignment;
-import jalview.datamodel.ColumnSelection;
-import jalview.datamodel.SequenceI;
-import jalview.io.FileParse;
-import jalview.io.FormatAdapter;
-import jalview.io.IdentifyFile;
-import jalview.io.JalviewFileChooser;
-import jalview.io.JalviewFileView;
-import jalview.jbgui.GCutAndPasteTransfer;
-import jalview.schemes.ColourSchemeI;
-import jalview.util.MessageManager;
-
 /**
  * Cut'n'paste files into the desktop See JAL-1105
  * 
@@ -56,7 +58,9 @@ import jalview.util.MessageManager;
 public class CutAndPasteTransfer extends GCutAndPasteTransfer
 {
 
-  AlignViewport viewport;
+  AlignmentViewPanel alignpanel;
+
+  AlignViewportI viewport;
 
   FileParse source = null;
   public CutAndPasteTransfer()
@@ -74,9 +78,14 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer
   /**
    * DOCUMENT ME!
    */
-  public void setForInput(AlignViewport viewport)
+  public void setForInput(AlignmentViewPanel viewpanel)
   {
-    this.viewport = viewport;
+    this.alignpanel = viewpanel;
+    if (alignpanel != null)
+    {
+
+    }
+    this.viewport = alignpanel.getAlignViewport();
     if (viewport != null)
     {
       ok.setText(MessageManager.getString("action.add"));
@@ -188,13 +197,13 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer
   {
     String format = new IdentifyFile().Identify(getText(), "Paste");
     // TODO: identify feature, annotation or tree file and parse appropriately.
-    Alignment al = null;
+    AlignmentI al = null;
 
     if (FormatAdapter.isValidFormat(format))
     {
       try
       {
-        FormatAdapter fa = new FormatAdapter(viewport);
+        FormatAdapter fa = new FormatAdapter(alignpanel);
         al = fa.readFile(getText(), "Paste", format);
         source = fa.getAlignFile();
 
@@ -216,7 +225,7 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer
               { format });
       if (viewport != null)
       {
-        viewport.addAlignment(al, title);
+        ((AlignViewport) viewport).addAlignment(al, title);
       }
       else
       {
index 9e84407..cc9daa1 100644 (file)
  */
 package jalview.gui;
 
+import jalview.api.AlignViewportI;
+import jalview.api.AlignmentViewPanel;
+import jalview.bin.Cache;
+import jalview.io.FileLoader;
+import jalview.io.FormatAdapter;
+import jalview.io.IdentifyFile;
+import jalview.io.JalviewFileChooser;
+import jalview.io.JalviewFileView;
+import jalview.jbgui.GSplitFrame;
+import jalview.jbgui.GStructureViewer;
+import jalview.structure.StructureSelectionManager;
+import jalview.util.ImageMaker;
+import jalview.util.MessageManager;
+import jalview.viewmodel.AlignmentViewport;
+import jalview.ws.params.ParamManager;
+
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Dimension;
@@ -84,22 +100,6 @@ import javax.swing.event.HyperlinkEvent.EventType;
 import javax.swing.event.MenuEvent;
 import javax.swing.event.MenuListener;
 
-import jalview.api.AlignViewportI;
-import jalview.api.AlignmentViewPanel;
-import jalview.bin.Cache;
-import jalview.io.FileLoader;
-import jalview.io.FormatAdapter;
-import jalview.io.IdentifyFile;
-import jalview.io.JalviewFileChooser;
-import jalview.io.JalviewFileView;
-import jalview.jbgui.GSplitFrame;
-import jalview.jbgui.GStructureViewer;
-import jalview.structure.StructureSelectionManager;
-import jalview.util.ImageMaker;
-import jalview.util.MessageManager;
-import jalview.viewmodel.AlignmentViewport;
-import jalview.ws.params.ParamManager;
-
 /**
  * Jalview Desktop
  * 
@@ -1133,7 +1133,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
   public void inputTextboxMenuItem_actionPerformed(AlignViewport viewport)
   {
     CutAndPasteTransfer cap = new CutAndPasteTransfer();
-    cap.setForInput(viewport);
+    cap.setForInput(viewport.getAlignPanel());
     Desktop.addInternalFrame(cap,
             MessageManager.getString("label.cut_paste_alignmen_file"),
             true, 600, 500);
index 918fc02..940a216 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import jalview.api.FeatureSettingsControllerI;
 import jalview.bin.Cache;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
@@ -88,7 +89,8 @@ import javax.swing.table.AbstractTableModel;
 import javax.swing.table.TableCellEditor;
 import javax.swing.table.TableCellRenderer;
 
-public class FeatureSettings extends JPanel
+public class FeatureSettings extends JPanel implements
+        FeatureSettingsControllerI
 {
   DasSourceBrowser dassourceBrowser;
 
@@ -227,7 +229,7 @@ public class FeatureSettings extends JPanel
       fr.findAllFeatures(true); // display everything!
     }
 
-    setTableData();
+    discoverAllFeatureData();
     final PropertyChangeListener change;
     final FeatureSettings fs = this;
     fr.addPropertyChangeListener(change = new PropertyChangeListener()
@@ -421,7 +423,8 @@ public class FeatureSettings extends JPanel
    */
   Hashtable typeWidth = null;
 
-  synchronized public void setTableData()
+  @Override
+  synchronized public void discoverAllFeatureData()
   {
     Vector allFeatures = new Vector();
     Vector allGroups = new Vector();
index a7a4e34..fe42e1e 100755 (executable)
@@ -86,6 +86,8 @@ public class IdCanvas extends JPanel
    * 
    * @param gg
    *          DOCUMENT ME!
+   * @param hiddenRows
+   *          true - check and display hidden row marker if need be
    * @param s
    *          DOCUMENT ME!
    * @param i
@@ -95,7 +97,8 @@ public class IdCanvas extends JPanel
    * @param ypos
    *          DOCUMENT ME!
    */
-  public void drawIdString(Graphics2D gg, SequenceI s, int i, int starty,
+  public void drawIdString(Graphics2D gg, boolean hiddenRows, SequenceI s,
+          int i, int starty,
           int ypos)
   {
     int xPos = 0;
@@ -134,7 +137,7 @@ public class IdCanvas extends JPanel
     gg.drawString(s.getDisplayId(av.getShowJVSuffix()), xPos,
             (((i - starty + 1) * charHeight) + ypos) - (charHeight / 5));
 
-    if (av.hasHiddenRows() && av.getShowHiddenMarkers())
+    if (hiddenRows)
     {
       drawMarker(i, starty, ypos);
     }
@@ -274,6 +277,9 @@ public class IdCanvas extends JPanel
     Color currentColor = Color.white;
     Color currentTextColor = Color.black;
 
+    final boolean doHiddenCheck = av.isDisplayReferenceSeq()
+            || av.hasHiddenRows(), hiddenRows = av.hasHiddenRows();
+
     if (av.getWrapAlignment())
     {
       int maxwidth = av.getAlignment().getWidth();
@@ -317,7 +323,7 @@ public class IdCanvas extends JPanel
         for (int i = starty; i < alheight; i++)
         {
           SequenceI s = av.getAlignment().getSequenceAt(i);
-          if (av.isDisplayReferenceSeq() || av.hasHiddenRows())
+          if (doHiddenCheck)
           {
             setHiddenFont(s);
           }
@@ -326,7 +332,7 @@ public class IdCanvas extends JPanel
             gg.setFont(getIdfont());
           }
 
-          drawIdString(gg, s, i, 0, ypos);
+          drawIdString(gg, hiddenRows, s, i, 0, ypos);
         }
 
         if (labels != null && av.isShowAnnotation())
@@ -357,7 +363,7 @@ public class IdCanvas extends JPanel
           continue;
         }
 
-        if (av.isDisplayReferenceSeq() || av.hasHiddenRows())
+        if (doHiddenCheck)
         {
           setHiddenFont(sequence);
         }
@@ -399,7 +405,7 @@ public class IdCanvas extends JPanel
                 (((i - starty) * av.getCharHeight()) + av.getCharHeight())
                         - (av.getCharHeight() / 5));
 
-        if (av.hasHiddenRows() && av.getShowHiddenMarkers())
+        if (hiddenRows)
         {
           drawMarker(i, starty, 0);
         }
index 39a232a..609e010 100755 (executable)
@@ -292,6 +292,8 @@ public class OverviewPanel extends JPanel implements Runnable
     int color = Color.white.getRGB();
     int row, col;
     jalview.datamodel.SequenceI seq;
+    final boolean hasHiddenRows = av.hasHiddenRows(), hasHiddenCols = av
+            .hasHiddenColumns();
     boolean hiddenRow = false;
     for (row = 0; row < sequencesHeight; row++)
     {
@@ -309,7 +311,7 @@ public class OverviewPanel extends JPanel implements Runnable
       lastrow = (int) (row * sampleRow);
 
       hiddenRow = false;
-      if (av.hasHiddenRows())
+      if (hasHiddenRows)
       {
         seq = av.getAlignment().getHiddenSequences()
                 .getHiddenSequence(lastrow);
@@ -362,7 +364,7 @@ public class OverviewPanel extends JPanel implements Runnable
         }
 
         if (hiddenRow
-                || (av.hasHiddenColumns() && !av.getColumnSelection()
+                || (hasHiddenCols && !av.getColumnSelection()
                         .isVisible(lastcol)))
         {
           color = new Color(color).darker().darker().getRGB();
index 0d28a70..2aa8675 100644 (file)
@@ -2396,7 +2396,7 @@ public class PopupMenu extends JPopupMenu
     // wysiwig behaviour
 
     cap.setText(new FormatAdapter().formatSequences(e.getActionCommand(),
-            ap.av, true));
+            ap, true));
   }
 
   public void pdbFromFile_actionPerformed()
index dd25532..c330a92 100755 (executable)
  */
 package jalview.gui;
 
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.io.FormatAdapter;
+import jalview.io.IdentifyFile;
+import jalview.util.DBRefUtils;
+import jalview.util.MessageManager;
+import jalview.ws.dbsources.das.api.DasSourceRegistryI;
+import jalview.ws.seqfetcher.DbSourceProxy;
+
 import java.awt.BorderLayout;
 import java.awt.Font;
 import java.awt.event.ActionEvent;
@@ -44,19 +56,6 @@ import javax.swing.tree.DefaultMutableTreeNode;
 
 import com.stevesoft.pat.Regex;
 
-import jalview.datamodel.Alignment;
-import jalview.datamodel.AlignmentI;
-import jalview.datamodel.DBRefEntry;
-import jalview.datamodel.DBRefSource;
-import jalview.datamodel.SequenceFeature;
-import jalview.datamodel.SequenceI;
-import jalview.io.FormatAdapter;
-import jalview.io.IdentifyFile;
-import jalview.util.DBRefUtils;
-import jalview.util.MessageManager;
-import jalview.ws.dbsources.das.api.DasSourceRegistryI;
-import jalview.ws.seqfetcher.DbSourceProxy;
-
 public class SequenceFetcher extends JPanel implements Runnable
 {
   JLabel dbeg = new JLabel();
@@ -774,7 +773,7 @@ public class SequenceFetcher extends JPanel implements Runnable
   AlignmentI parseResult(String result, String title)
   {
     String format = new IdentifyFile().Identify(result, "Paste");
-    Alignment sequences = null;
+    AlignmentI sequences = null;
     if (FormatAdapter.isValidFormat(format))
     {
       sequences = null;
index 5d8a297..3b46760 100755 (executable)
  */
 package jalview.io;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Vector;
-
-import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Sequence;
@@ -35,6 +27,13 @@ import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.util.MessageManager;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Vector;
+
 /**
  * DOCUMENT ME!
  * 
@@ -200,7 +199,7 @@ public abstract class AlignFile extends FileParse
    * 
    * @param al
    */
-  public void addAnnotations(Alignment al)
+  public void addAnnotations(AlignmentI al)
   {
     addProperties(al);
     for (int i = 0; i < annotations.size(); i++)
@@ -220,6 +219,11 @@ public abstract class AlignFile extends FileParse
 
   }
 
+  /**
+   * register sequence groups on the alignment for **output**
+   * 
+   * @param al
+   */
   public void addSeqGroups(AlignmentI al)
   {
     this.seqGroups = al.getGroups();
@@ -233,7 +237,7 @@ public abstract class AlignFile extends FileParse
    * @note implicitly called by addAnnotations()
    * @param al
    */
-  public void addProperties(Alignment al)
+  public void addProperties(AlignmentI al)
   {
     if (properties != null && properties.size() > 0)
     {
@@ -378,4 +382,13 @@ public abstract class AlignFile extends FileParse
     return newickStrings == null ? 0 : newickStrings.size();
   }
 
+  public void addGroups(AlignmentI al)
+  {
+
+    for (SequenceGroup sg : getSeqGroups())
+    {
+      al.addGroup(sg);
+    }
+  }
+
 }
index 78aa86b..b235bcc 100755 (executable)
  */
 package jalview.io;
 
-import java.io.File;
-import java.io.InputStream;
-import java.util.List;
-
-import jalview.api.AlignViewportI;
+import jalview.api.AlignExportSettingI;
+import jalview.api.AlignmentViewPanel;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
-import jalview.datamodel.SequenceGroup;
+import jalview.gui.AlignmentPanel;
 import jalview.util.MessageManager;
 
+import java.io.File;
+import java.io.InputStream;
+import java.util.List;
+
 /**
  * A low level class for alignment and feature IO with alignment formatting
  * methods used by both applet and application for generating flat alignment
@@ -43,7 +44,7 @@ import jalview.util.MessageManager;
  */
 public class AppletFormatAdapter
 {
-  private AlignViewportI viewport;
+  private AlignmentViewPanel viewpanel;
 
   public static String FILE = "File";
 
@@ -77,12 +78,14 @@ public class AppletFormatAdapter
    */
   protected String newline = System.getProperty("line.separator");
 
+  private AlignExportSettingI exportSettings;
+
   /**
    * List of valid format strings used in the isValidFormat method
    */
   public static final String[] READABLE_FORMATS = new String[]
   { "BLC", "CLUSTAL", "FASTA", "MSF", "PileUp", "PIR", "PFAM", "STH",
-      "PDB", "JnetFile", "RNAML", PhylipFile.FILE_DESC, JSONFile.FILE_DESC,
+      "PDB", "JnetFile", "RNAML", PhylipFile.FILE_DESC, JSONFile.FILE_DESC, IdentifyFile.GFF3File,
       "HTML" };
 
   /**
@@ -92,6 +95,7 @@ public class AppletFormatAdapter
   public static final String[] READABLE_EXTENSIONS = new String[]
   { "fa, fasta, mfa, fastq", "aln", "pfam", "msf", "pir", "blc", "amsa",
       "sto,stk", "xml,rnaml", PhylipFile.FILE_EXT, JSONFile.FILE_EXT,
+      ".gff2,gff3",
       "jar,jvp", HtmlFile.FILE_EXT };
 
   /**
@@ -100,7 +104,7 @@ public class AppletFormatAdapter
    */
   public static final String[] READABLE_FNAMES = new String[]
   { "Fasta", "Clustal", "PFAM", "MSF", "PIR", "BLC", "AMSA", "Stockholm",
-      "RNAML", PhylipFile.FILE_DESC, JSONFile.FILE_DESC, "Jalview",
+      "RNAML", PhylipFile.FILE_DESC, JSONFile.FILE_DESC, IdentifyFile.GFF3File, "Jalview",
       HtmlFile.FILE_DESC };
 
   /**
@@ -137,9 +141,16 @@ public class AppletFormatAdapter
   {
   }
 
-  public AppletFormatAdapter(AlignViewportI viewport)
+  public AppletFormatAdapter(AlignmentViewPanel viewpanel)
+  {
+    this.viewpanel = viewpanel;
+  }
+
+  public AppletFormatAdapter(AlignmentPanel alignPanel,
+          AlignExportSettingI settings)
   {
-    this.viewport = viewport;
+    viewpanel = alignPanel;
+    exportSettings = settings;
   }
 
   /**
@@ -221,7 +232,7 @@ public class AppletFormatAdapter
    *
    * @return DOCUMENT ME!
    */
-  public Alignment readFile(String inFile, String type, String format)
+  public AlignmentI readFile(String inFile, String type, String format)
           throws java.io.IOException
   {
     // TODO: generalise mapping between format string and io. class instances
@@ -229,7 +240,6 @@ public class AppletFormatAdapter
     this.inFile = inFile;
     try
     {
-      Alignment al;
       if (format.equals("FASTA"))
       {
         alignFile = new FastaFile(inFile, type);
@@ -285,37 +295,20 @@ public class AppletFormatAdapter
       else if (format.equals(JSONFile.FILE_DESC))
       {
         alignFile = new JSONFile(inFile, type);
-        al = new Alignment(alignFile.getSeqsAsArray());
-        alignFile.addAnnotations(al);
-        ((JSONFile) alignFile).setViewport(viewport);
-        for (SequenceGroup sg : alignFile.getSeqGroups())
-        {
-          al.addGroup(sg);
-        }
-
-        return al;
       }
       else if (format.equals(HtmlFile.FILE_DESC))
       {
         alignFile = new HtmlFile(inFile, type);
-        al = new Alignment(alignFile.getSeqsAsArray());
-        alignFile.addAnnotations(al);
-        for (SequenceGroup sg : alignFile.getSeqGroups())
-        {
-          al.addGroup(sg);
-        }
-        return al;
       }
       else if (format.equals("RNAML"))
       {
         alignFile = new RnamlFile(inFile, type);
       }
-
-      al = new Alignment(alignFile.getSeqsAsArray());
-
-      alignFile.addAnnotations(al);
-
-      return al;
+      else if (format.equals(IdentifyFile.GFF3File))
+      {
+        alignFile = new Gff3File(inFile, type);
+      }
+      return buildAlignmentFrom(alignFile);
     } catch (Exception e)
     {
       e.printStackTrace();
@@ -335,11 +328,7 @@ public class AppletFormatAdapter
         {
           // Possible sequence is just residues with no label
           alignFile = new FastaFile(">UNKNOWN\n" + inFile, "Paste");
-          Alignment al = new Alignment(alignFile.getSeqsAsArray());
-
-          alignFile.addSeqGroups(al);
-          alignFile.addAnnotations(al);
-          return al;
+          return buildAlignmentFrom(alignFile);
 
         } catch (Exception ex)
         {
@@ -378,7 +367,6 @@ public class AppletFormatAdapter
     String type = source.type;
     try
     {
-      Alignment al;
       if (format.equals("FASTA"))
       {
         alignFile = new FastaFile(source);
@@ -433,22 +421,21 @@ public class AppletFormatAdapter
       {
         alignFile = new PhylipFile(source);
       }
+      else if (format.equals(IdentifyFile.GFF3File))
+      {
+        alignFile = new Gff3File(inFile, type);
+      }
       else if (format.equals(JSONFile.FILE_DESC))
       {
         alignFile = new JSONFile(source);
-        al = new Alignment(alignFile.getSeqsAsArray());
-        alignFile.addAnnotations(al);
-        alignFile.addSeqGroups(al);
-        return al;
       }
       else if (format.equals(HtmlFile.FILE_DESC))
       {
         alignFile = new HtmlFile(source);
       }
-      al = new Alignment(alignFile.getSeqsAsArray());
-      alignFile.addAnnotations(al);
 
-      return al;
+      return buildAlignmentFrom(alignFile);
+
     } catch (Exception e)
     {
       e.printStackTrace();
@@ -468,10 +455,7 @@ public class AppletFormatAdapter
         {
           // Possible sequence is just residues with no label
           alignFile = new FastaFile(">UNKNOWN\n" + inFile, "Paste");
-          Alignment al = new Alignment(alignFile.getSeqsAsArray());
-          alignFile.addAnnotations(al);
-          alignFile.addSeqGroups(al);
-          return al;
+          return buildAlignmentFrom(alignFile);
 
         } catch (Exception ex)
         {
@@ -491,6 +475,27 @@ public class AppletFormatAdapter
 
 
   /**
+   * boilerplate method to handle data from an AlignFile and construct a new
+   * alignment or import to an existing alignment
+   * 
+   * @param alignFile2
+   * @return AlignmentI instance ready to pass to a UI constructor
+   */
+  private AlignmentI buildAlignmentFrom(AlignFile alignFile2)
+  {
+    // Standard boilerplate for creating alignment from parser
+    alignFile.configureForView(viewpanel);
+
+    AlignmentI al = new Alignment(alignFile.getSeqsAsArray());
+
+    alignFile.addAnnotations(al);
+
+    alignFile.addGroups(al);
+
+    return al;
+  }
+
+  /**
    * create an alignment flatfile from a Jalview alignment view
    * @param format
    * @param jvsuffix
@@ -499,13 +504,14 @@ public class AppletFormatAdapter
    * @return flatfile in a string
    */
   public String formatSequences(String format, boolean jvsuffix,
-          AlignViewportI av, boolean selectedOnly)
+          AlignmentViewPanel ap, boolean selectedOnly)
   {
 
-    AlignmentView selvew = av.getAlignmentView(selectedOnly, false);
-    AlignmentI aselview = selvew.getVisibleAlignment(av
+    AlignmentView selvew = ap.getAlignViewport().getAlignmentView(
+            selectedOnly, false);
+    AlignmentI aselview = selvew.getVisibleAlignment(ap.getAlignViewport()
             .getGapCharacter());
-    List<AlignmentAnnotation> ala = (av
+    List<AlignmentAnnotation> ala = (ap.getAlignViewport()
             .getVisibleAlignmentAnnotation(selectedOnly));
     if (ala != null)
     {
@@ -582,22 +588,6 @@ public class AppletFormatAdapter
        else if (format.equalsIgnoreCase(JSONFile.FILE_DESC))
        {
         afile = new JSONFile();
-        afile.setViewport(viewport);
-        // Add groups to AlignFile
-        afile.seqGroups = alignment.getGroups();
-
-        // Add non auto calculated annotation to AlignFile
-        for (AlignmentAnnotation annot : alignment.getAlignmentAnnotation())
-        {
-          if (annot != null && !annot.autoCalculated)
-          {
-            if (annot.label.equals("PDB.CATempFactor"))
-            {
-              continue;
-            }
-            afile.annotations.add(annot);
-          }
-        }
        }
       else if (format.equalsIgnoreCase("RNAML"))
       {
@@ -611,8 +601,21 @@ public class AppletFormatAdapter
       afile.setNewlineString(newline);
       afile.addJVSuffix(jvsuffix);
 
-      afile.setSeqs(alignment.getSequencesArray());
+      afile.setExportSettings(exportSettings);
 
+      afile.configureForView(viewpanel);
+
+      // check whether we were given a specific alignment to export, rather than
+      // the one in the viewpanel
+      if (viewpanel == null || viewpanel.getAlignment() == null
+              || viewpanel.getAlignment() != alignment)
+      {
+        afile.setSeqs(alignment.getSequencesArray());
+      }
+      else
+      {
+        afile.setSeqs(viewpanel.getAlignment().getSequencesArray());
+      }
 
       String afileresp = afile.print();
       if (afile.hasWarningMessage())
@@ -659,7 +662,7 @@ public class AppletFormatAdapter
           System.gc();
           long memf = -r.totalMemory() + r.freeMemory();
           long t1 = -System.currentTimeMillis();
-          Alignment al = afa.readFile(args[i], FILE,
+          AlignmentI al = afa.readFile(args[i], FILE,
                   new IdentifyFile().Identify(args[i], FILE));
           t1 += System.currentTimeMillis();
           System.gc();
index a026c57..74fb147 100644 (file)
@@ -1,9 +1,7 @@
 package jalview.io;
 
+import jalview.api.AlignmentViewPanel;
 import jalview.exceptions.NoFileSelectedException;
-import jalview.gui.AlignViewport;
-import jalview.gui.AlignmentPanel;
-import jalview.gui.FeatureRenderer;
 import jalview.json.binding.v1.BioJSReleasePojo;
 import jalview.json.binding.v1.BioJSRepositoryPojo;
 import jalview.util.MessageManager;
@@ -23,7 +21,7 @@ import java.util.TreeMap;
 
 public class BioJsHTMLOutput
 {
-  private AlignViewport av;
+  private AlignmentViewPanel ap;
 
   private static File currentBJSTemplateFile;
 
@@ -40,12 +38,11 @@ public class BioJsHTMLOutput
                   "biojs_template_git_repo",
                   "https://raw.githubusercontent.com/tcofoegbu/bjs-template/master/package.json");
 
-  public BioJsHTMLOutput(AlignmentPanel ap, FeatureRenderer fr1)
+  public BioJsHTMLOutput(AlignmentViewPanel ap)
   {
     if (ap != null)
     {
-      this.av = ap.av;
-      av.setFeatureRenderer(new FeatureRenderer(ap));
+      this.ap = ap;
     }
   }
 
@@ -54,7 +51,7 @@ public class BioJsHTMLOutput
     try
     {
       String outputFile = getOutputFile();
-      String jalviewAlignmentJson = JSONFile.getJSONData(av);
+      String jalviewAlignmentJson = JSONFile.getJSONData(ap);
       String bioJSTemplateString = getBioJsTemplateAsString();
       String generatedBioJsWithJalviewAlignmentAsJson = bioJSTemplateString
               .replaceAll(
index 260b32d..57f6384 100755 (executable)
  */
 package jalview.io;
 
-import java.io.*;
-import java.util.*;
-
 import jalview.analysis.SequenceIdMatcher;
-import jalview.datamodel.*;
-import jalview.schemes.*;
+import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceDummy;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.schemes.AnnotationColourGradient;
+import jalview.schemes.GraduatedColor;
+import jalview.schemes.UserColourScheme;
 import jalview.util.Format;
+import jalview.util.MapList;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.Vector;
 
 /**
  * Parse and create Jalview Features files Detects GFF format features files and
@@ -45,6 +60,8 @@ public class FeaturesFile extends AlignFile
    */
   private boolean doGffSource = true;
 
+  private int gffversion;
+
   /**
    * Creates a new FeaturesFile object.
    */
@@ -53,27 +70,48 @@ public class FeaturesFile extends AlignFile
   }
 
   /**
-   * Creates a new FeaturesFile object.
-   * 
    * @param inFile
-   *          DOCUMENT ME!
    * @param type
-   *          DOCUMENT ME!
-   * 
    * @throws IOException
-   *           DOCUMENT ME!
    */
   public FeaturesFile(String inFile, String type) throws IOException
   {
     super(inFile, type);
   }
 
+  /**
+   * @param source
+   * @throws IOException
+   */
   public FeaturesFile(FileParse source) throws IOException
   {
     super(source);
   }
 
   /**
+   * @param parseImmediately
+   * @param source
+   * @throws IOException
+   */
+  public FeaturesFile(boolean parseImmediately, FileParse source)
+          throws IOException
+  {
+    super(parseImmediately, source);
+  }
+
+  /**
+   * @param parseImmediately
+   * @param inFile
+   * @param type
+   * @throws IOException
+   */
+  public FeaturesFile(boolean parseImmediately, String inFile, String type)
+          throws IOException
+  {
+    super(parseImmediately, inFile, type);
+  }
+
+  /**
    * Parse GFF or sequence features file using case-independent matching,
    * discarding URLs
    * 
@@ -131,6 +169,27 @@ public class FeaturesFile extends AlignFile
     return parse(align, colours, featureLink, removeHTML, false);
   }
 
+  @Override
+  public void addAnnotations(AlignmentI al)
+  {
+    // TODO Auto-generated method stub
+    super.addAnnotations(al);
+  }
+
+  @Override
+  public void addProperties(AlignmentI al)
+  {
+    // TODO Auto-generated method stub
+    super.addProperties(al);
+  }
+
+  @Override
+  public void addSeqGroups(AlignmentI al)
+  {
+    // TODO Auto-generated method stub
+    super.addSeqGroups(al);
+  }
+
   /**
    * Parse GFF or sequence features file
    * 
@@ -154,6 +213,10 @@ public class FeaturesFile extends AlignFile
     try
     {
       SequenceI seq = null;
+      /**
+       * keep track of any sequences we try to create from the data if it is a GFF3 file
+       */
+      ArrayList<SequenceI> newseqs = new ArrayList<SequenceI>();
       String type, desc, token = null;
 
       int index, start, end;
@@ -166,10 +229,18 @@ public class FeaturesFile extends AlignFile
        * when true, assume GFF style features rather than Jalview style.
        */
       boolean GFFFile = true;
+      Map<String, String> gffProps = new HashMap<String, String>();
       while ((line = nextLine()) != null)
       {
+        // skip comments/process pragmas
         if (line.startsWith("#"))
         {
+          if (line.startsWith("##"))
+          {
+            // possibly GFF2/3 version and metadata header
+            processGffPragma(line, gffProps, align, newseqs);
+            line = "";
+          }
           continue;
         }
 
@@ -427,7 +498,7 @@ public class FeaturesFile extends AlignFile
             // Still possible this is an old Jalview file,
             // which does not have type colours at the beginning
             seqId = token = st.nextToken();
-            seq = findName(align, seqId, relaxedIdmatching);
+            seq = findName(align, seqId, relaxedIdmatching, newseqs);
             if (seq != null)
             {
               desc = st.nextToken();
@@ -496,9 +567,11 @@ public class FeaturesFile extends AlignFile
               if (st.hasMoreTokens())
               {
                 StringBuffer attributes = new StringBuffer();
+                boolean sep = false;
                 while (st.hasMoreTokens())
                 {
-                  attributes.append("\t" + st.nextElement());
+                  attributes.append((sep ? "\t" : "") + st.nextElement());
+                  sep = true;
                 }
                 // TODO validate and split GFF2 attributes field ? parse out
                 // ([A-Za-z][A-Za-z0-9_]*) <value> ; and add as
@@ -506,10 +579,15 @@ public class FeaturesFile extends AlignFile
                 sf.setValue("ATTRIBUTES", attributes.toString());
               }
 
-              seq.addSequenceFeature(sf);
-              while ((seq = align.findName(seq, seqId, true)) != null)
+              if (processOrAddSeqFeature(align, newseqs, seq, sf, GFFFile,
+                      relaxedIdmatching))
               {
-                seq.addSequenceFeature(new SequenceFeature(sf));
+                // check whether we should add the sequence feature to any other
+                // sequences in the alignment with the same or similar
+                while ((seq = align.findName(seq, seqId, true)) != null)
+                {
+                  seq.addSequenceFeature(new SequenceFeature(sf));
+                }
               }
               break;
             }
@@ -536,7 +614,7 @@ public class FeaturesFile extends AlignFile
 
           if (!token.equals("ID_NOT_SPECIFIED"))
           {
-            seq = findName(align, seqId = token, relaxedIdmatching);
+            seq = findName(align, seqId = token, relaxedIdmatching, null);
             st.nextToken();
           }
           else
@@ -609,6 +687,9 @@ public class FeaturesFile extends AlignFile
       resetMatcher();
     } catch (Exception ex)
     {
+      // should report somewhere useful for UI if necessary
+      warningMessage = ((warningMessage == null) ? "" : warningMessage)
+              + "Parsing error at\n" + line;
       System.out.println("Error parsing feature file: " + ex + "\n" + line);
       ex.printStackTrace(System.err);
       resetMatcher();
@@ -618,6 +699,398 @@ public class FeaturesFile extends AlignFile
     return true;
   }
 
+  private enum GffPragmas
+  {
+    gff_version, sequence_region, feature_ontology, attribute_ontology, source_ontology, species_build, fasta, hash
+  };
+
+  private static Map<String, GffPragmas> GFFPRAGMA;
+  static
+  {
+    GFFPRAGMA = new HashMap<String, GffPragmas>();
+    GFFPRAGMA.put("sequence-region", GffPragmas.sequence_region);
+    GFFPRAGMA.put("feature-ontology", GffPragmas.feature_ontology);
+    GFFPRAGMA.put("#", GffPragmas.hash);
+    GFFPRAGMA.put("fasta", GffPragmas.fasta);
+    GFFPRAGMA.put("species-build", GffPragmas.species_build);
+    GFFPRAGMA.put("source-ontology", GffPragmas.source_ontology);
+    GFFPRAGMA.put("attribute-ontology", GffPragmas.attribute_ontology);
+  }
+
+  private void processGffPragma(String line, Map<String, String> gffProps,
+          AlignmentI align, ArrayList<SequenceI> newseqs)
+          throws IOException
+  {
+    // line starts with ##
+    int spacepos = line.indexOf(' ');
+    String pragma = spacepos == -1 ? line.substring(2).trim() : line
+            .substring(2, spacepos);
+    GffPragmas gffpragma = GFFPRAGMA.get(pragma.toLowerCase());
+    if (gffpragma == null)
+    {
+      return;
+    }
+    switch (gffpragma)
+    {
+    case gff_version:
+      try
+      {
+        gffversion = Integer.parseInt(line.substring(spacepos + 1));
+      } finally
+      {
+
+      }
+      break;
+    case feature_ontology:
+      // resolve against specific feature ontology
+      break;
+    case attribute_ontology:
+      // resolve against specific attribute ontology
+      break;
+    case source_ontology:
+      // resolve against specific source ontology
+      break;
+    case species_build:
+      // resolve against specific NCBI taxon version
+      break;
+    case hash:
+      // close off any open feature hierarchies
+      break;
+    case fasta:
+      // process the rest of the file as a fasta file and replace any dummy
+      // sequence IDs
+      process_as_fasta(align, newseqs);
+      break;
+    default:
+      // we do nothing ?
+      System.err.println("Ignoring unknown pragma:\n" + line);
+    }
+  }
+
+  private void process_as_fasta(AlignmentI align, List<SequenceI> newseqs)
+          throws IOException
+  {
+    try
+    {
+      mark();
+    } catch (IOException q)
+    {
+    }
+    FastaFile parser = new FastaFile(this);
+    List<SequenceI> includedseqs = parser.getSeqs();
+    SequenceIdMatcher smatcher = new SequenceIdMatcher(newseqs);
+    // iterate over includedseqs, and replacing matching ones with newseqs
+    // sequences. Generic iterator not used here because we modify includedseqs
+    // as we go
+    for (int p = 0, pSize = includedseqs.size(); p < pSize; p++)
+    {
+      // search for any dummy seqs that this sequence can be used to update
+      SequenceI dummyseq = smatcher.findIdMatch(includedseqs.get(p));
+      if (dummyseq != null)
+      {
+        // dummyseq was created so it could be annotated and referred to in
+        // alignments/codon mappings
+
+        SequenceI mseq = includedseqs.get(p);
+        // mseq is the 'template' imported from the FASTA file which we'll use
+        // to coomplete dummyseq
+        if (dummyseq instanceof SequenceDummy)
+        {
+          // probably have the pattern wrong
+          // idea is that a flyweight proxy for a sequence ID can be created for
+          // 1. stable reference creation
+          // 2. addition of annotation
+          // 3. future replacement by a real sequence
+          // current pattern is to create SequenceDummy objects - a convenience
+          // constructor for a Sequence.
+          // problem is that when promoted to a real sequence, all references
+          // need
+          // to be updated somehow.
+          ((SequenceDummy) dummyseq).become(mseq);
+          includedseqs.set(p, dummyseq); // template is no longer needed
+        }
+      }
+    }
+    // finally add sequences to the dataset
+    for (SequenceI seq : includedseqs)
+    {
+      align.addSequence(seq);
+    }
+  }
+
+  /**
+   * take a sequence feature and examine its attributes to decide how it should
+   * be added to a sequence
+   * 
+   * @param seq
+   *          - the destination sequence constructed or discovered in the
+   *          current context
+   * @param sf
+   *          - the base feature with ATTRIBUTES property containing any
+   *          additional attributes
+   * @param gFFFile
+   *          - true if we are processing a GFF annotation file
+   * @return true if sf was actually added to the sequence, false if it was
+   *         processed in another way
+   */
+  public boolean processOrAddSeqFeature(AlignmentI align, List<SequenceI> newseqs, SequenceI seq, SequenceFeature sf,
+          boolean gFFFile, boolean relaxedIdMatching)
+  {
+    String attr = (String) sf.getValue("ATTRIBUTES");
+    boolean add = true;
+    if (gFFFile && attr != null)
+    {
+      int nattr=8;
+
+      for (String attset : attr.split("\t"))
+      {
+        if (attset==null || attset.trim().length()==0)
+        {
+          continue;
+        }
+        nattr++;
+        Map<String, List<String>> set = new HashMap<String, List<String>>();
+        // normally, only expect one column - 9 - in this field
+        // the attributes (Gff3) or groups (gff2) field
+        for (String pair : attset.trim().split(";"))
+        {
+          pair = pair.trim();
+          if (pair.length() == 0)
+          {
+            continue;
+          }
+
+          // expect either space seperated (gff2) or '=' separated (gff3) 
+          // key/value pairs here
+
+          int eqpos = pair.indexOf('='),sppos = pair.indexOf(' ');
+          String key = null, value = null;
+
+          if (sppos > -1 && (eqpos == -1 || sppos < eqpos))
+          {
+            key = pair.substring(0, sppos);
+            value = pair.substring(sppos + 1);
+          } else {
+            if (eqpos > -1 && (sppos == -1 || eqpos < sppos))
+            {
+              key = pair.substring(0, eqpos);
+              value = pair.substring(eqpos + 1);
+            } else
+            {
+              key = pair;
+            }
+          }
+          if (key != null)
+          {
+            List<String> vals = set.get(key);
+            if (vals == null)
+            {
+              vals = new ArrayList<String>();
+              set.put(key, vals);
+            }
+            if (value != null)
+            {
+              vals.add(value.trim());
+            }
+          }
+        }
+        try
+        {
+          add &= processGffKey(set, nattr, seq, sf, align, newseqs,
+                  relaxedIdMatching); // process decides if
+                                                     // feature is actually
+                                                     // added
+        } catch (InvalidGFF3FieldException ivfe)
+        {
+          System.err.println(ivfe);
+        }
+      }
+    }
+    if (add)
+    {
+      seq.addSequenceFeature(sf);
+    }
+    return add;
+  }
+
+  public class InvalidGFF3FieldException extends Exception
+  {
+    String field, value;
+
+    public InvalidGFF3FieldException(String field,
+            Map<String, List<String>> set, String message)
+    {
+      super(message + " (Field was " + field + " and value was "
+              + set.get(field).toString());
+      this.field = field;
+      this.value = set.get(field).toString();
+    }
+
+  }
+
+  /**
+   * take a set of keys for a feature and interpret them
+   * 
+   * @param set
+   * @param nattr
+   * @param seq
+   * @param sf
+   * @return
+   */
+  public boolean processGffKey(Map<String, List<String>> set, int nattr,
+          SequenceI seq, SequenceFeature sf, AlignmentI align,
+          List<SequenceI> newseqs, boolean relaxedIdMatching)
+          throws InvalidGFF3FieldException
+  {
+    String attr;
+    // decide how to interpret according to type
+    if (sf.getType().equals("similarity"))
+    {
+      int strand = sf.getStrand();
+      // exonerate cdna/protein map
+      // look for fields 
+      List<SequenceI> querySeq = findNames(align, newseqs,
+              relaxedIdMatching, set.get(attr="Query"));
+      if (querySeq==null || querySeq.size()!=1)
+      {
+        throw new InvalidGFF3FieldException( attr, set,
+                "Expecting exactly one sequence in Query field (got "
+                        + set.get(attr) + ")");
+      }
+      if (set.containsKey(attr="Align"))
+      {
+        // process the align maps and create cdna/protein maps
+        // ideally, the query sequences are in the alignment, but maybe not...
+        
+        AlignedCodonFrame alco = new AlignedCodonFrame();
+        MapList codonmapping = constructCodonMappingFromAlign(set, attr,
+                strand);
+
+        // add codon mapping, and hope!
+        alco.addMap(seq, querySeq.get(0), codonmapping);
+        align.addCodonFrame(alco);
+        // everything that's needed to be done is done
+        // no features to create here !
+        return false;
+      }
+
+    }
+    return true;
+  }
+
+  private MapList constructCodonMappingFromAlign(
+          Map<String, List<String>> set,
+          String attr, int strand) throws InvalidGFF3FieldException
+  {
+    if (strand == 0)
+    {
+      throw new InvalidGFF3FieldException(attr, set,
+              "Invalid strand for a codon mapping (cannot be 0)");
+    }
+    List<Integer> fromrange = new ArrayList<Integer>(), torange = new ArrayList<Integer>();
+    int lastppos = 0, lastpframe = 0;
+    for (String range : set.get(attr))
+    {
+      List<Integer> ints = new ArrayList<Integer>();
+      StringTokenizer st = new StringTokenizer(range, " ");
+      while (st.hasMoreTokens())
+      {
+        String num = st.nextToken();
+        try
+        {
+          ints.add(new Integer(num));
+        } catch (NumberFormatException nfe)
+        {
+          throw new InvalidGFF3FieldException(attr, set,
+                  "Invalid number in field " + num);
+        }
+      }
+      // Align positionInRef positionInQuery LengthInRef
+      // contig_1146 exonerate:protein2genome:local similarity 8534 11269
+      // 3652 - . alignment_id 0 ;
+      // Query DDB_G0269124
+      // Align 11270 143 120
+      // corresponds to : 120 bases align at pos 143 in protein to 11270 on
+      // dna in strand direction
+      // Align 11150 187 282
+      // corresponds to : 282 bases align at pos 187 in protein to 11150 on
+      // dna in strand direction
+      //
+      // Align 10865 281 888
+      // Align 9977 578 1068
+      // Align 8909 935 375
+      //
+      if (ints.size() != 3)
+      {
+        throw new InvalidGFF3FieldException(attr, set,
+                "Invalid number of fields for this attribute ("
+                        + ints.size() + ")");
+      }
+      fromrange.add(new Integer(ints.get(0).intValue()));
+      fromrange.add(new Integer(ints.get(0).intValue() + strand
+              * ints.get(2).intValue()));
+      // how are intron/exon boundaries that do not align in codons
+      // represented
+      if (ints.get(1).equals(lastppos) && lastpframe > 0)
+      {
+        // extend existing to map
+        lastppos += ints.get(2) / 3;
+        lastpframe = ints.get(2) % 3;
+        torange.set(torange.size() - 1, new Integer(lastppos));
+      }
+      else
+      {
+        // new to map range
+        torange.add(ints.get(1));
+        lastppos = ints.get(1) + ints.get(2) / 3;
+        lastpframe = ints.get(2) % 3;
+        torange.add(new Integer(lastppos));
+      }
+    }
+    // from and to ranges must end up being a series of start/end intervals
+    if (fromrange.size() % 2 == 1)
+    {
+      throw new InvalidGFF3FieldException(attr, set,
+              "Couldn't parse the DNA alignment range correctly");
+    }
+    if (torange.size() % 2 == 1)
+    {
+      throw new InvalidGFF3FieldException(attr, set,
+              "Couldn't parse the protein alignment range correctly");
+    }
+    // finally, build the map
+    int[] frommap = new int[fromrange.size()], tomap = new int[torange
+            .size()];
+    int p = 0;
+    for (Integer ip : fromrange)
+    {
+      frommap[p++] = ip.intValue();
+    }
+    p = 0;
+    for (Integer ip : torange)
+    {
+      tomap[p++] = ip.intValue();
+    }
+
+    return new MapList(frommap, tomap, 3, 1);
+  }
+
+  private List<SequenceI> findNames(AlignmentI align,
+          List<SequenceI> newseqs, boolean relaxedIdMatching,
+          List<String> list)
+  {
+    List<SequenceI> found = new ArrayList<SequenceI>();
+    for (String seqId : list)
+    {
+      SequenceI seq = findName(align, seqId, relaxedIdMatching, newseqs);
+      if (seq != null)
+      {
+        found.add(seq);
+      }
+    }
+    return found;
+  }
+
   private AlignmentI lastmatchedAl = null;
 
   private SequenceIdMatcher matcher = null;
@@ -632,7 +1105,7 @@ public class FeaturesFile extends AlignFile
   }
 
   private SequenceI findName(AlignmentI align, String seqId,
-          boolean relaxedIdMatching)
+          boolean relaxedIdMatching, List<SequenceI> newseqs)
   {
     SequenceI match = null;
     if (relaxedIdMatching)
@@ -641,16 +1114,41 @@ public class FeaturesFile extends AlignFile
       {
         matcher = new SequenceIdMatcher(
                 (lastmatchedAl = align).getSequencesArray());
+        if (newseqs != null)
+        {
+          matcher.addAll(newseqs);
+        }
       }
       match = matcher.findIdMatch(seqId);
     }
     else
     {
       match = align.findName(seqId, true);
+      if (match == null && newseqs != null)
+      {
+        for (SequenceI m : newseqs)
+        {
+          if (seqId.equals(m.getName()))
+          {
+            return m;
+          }
+        }
+      }
+      
+    }
+    if (match==null && newseqs!=null)
+    {
+      match = new SequenceDummy(seqId);
+      if (relaxedIdMatching)
+      {
+        matcher.addAll(Arrays.asList(new SequenceI[]
+        { match }));
+      }
+      // add dummy sequence to the newseqs list
+      newseqs.add(match);
     }
     return match;
   }
-
   public void parseDescriptionHTML(SequenceFeature sf, boolean removeHTML)
   {
     if (sf.getDescription() == null)
index 0cd2987..7387fa2 100755 (executable)
@@ -406,7 +406,9 @@ public class FileLoader implements Runnable
 
           final String errorMessage = "Couldn't load file " + title + "\n"
                   + error;
-          if (raiseGUI)
+          // TODO: refactor FileLoader to be independent of Desktop / Applet GUI
+          // bits ?
+          if (raiseGUI && Desktop.desktop != null)
           {
             javax.swing.SwingUtilities.invokeLater(new Runnable()
             {
index f9c717d..9228257 100755 (executable)
@@ -20,7 +20,9 @@
  */
 package jalview.io;
 
+import jalview.api.AlignExportSettingI;
 import jalview.api.AlignViewportI;
+import jalview.api.AlignmentViewPanel;
 import jalview.util.MessageManager;
 
 import java.io.BufferedReader;
@@ -49,12 +51,26 @@ public class FileParse
 
   public File inFile = null;
 
+  /**
+   * a viewport associated with the current file operation. May be null. May
+   * move to different object.
+   */
   private AlignViewportI viewport;
 
-  public int index = 1; // sequence counter for FileParse object created from
+  /**
+   * specific settings for exporting data from the current context
+   */
+  private AlignExportSettingI exportSettings;
 
-  // same data source
+  /**
+   * sequence counter for FileParse object created from same data source
+   */
+  public int index = 1;
 
+  /**
+   * separator for extracting specific 'frame' of a datasource for formats that
+   * support multiple records (e.g. BLC, Stockholm, etc)
+   */
   protected char suffixSeparator = '#';
 
   /**
@@ -395,6 +411,19 @@ public class FileParse
     throw new IOException(MessageManager.formatMessage("exception.invalid_source_stream", new String[]{errormessage}));
   }
 
+  /**
+   * 
+   * @return true if this FileParse is configured for Export only
+   */
+  public boolean isExporting()
+  {
+    return !error && dataIn == null;
+  }
+
+  /**
+   * 
+   * @return true if the data source is valid
+   */
   public boolean isValid()
   {
     return !error;
@@ -501,4 +530,37 @@ public class FileParse
   {
     this.viewport = viewport;
   }
+
+  /**
+   * @return the currently configured exportSettings for writing data.
+   */
+  public AlignExportSettingI getExportSettings()
+  {
+    return exportSettings;
+  }
+
+  /**
+   * Set configuration for export of data.
+   * 
+   * @param exportSettings
+   *          the exportSettings to set
+   */
+  public void setExportSettings(AlignExportSettingI exportSettings)
+  {
+    this.exportSettings = exportSettings;
+  }
+
+  /**
+   * method overridden by complex file exporter/importers which support
+   * exporting visualisation and layout settings for a view
+   * 
+   * @param avpanel
+   */
+  public void configureForView(AlignmentViewPanel avpanel)
+  {
+    if (avpanel!=null) {
+      setViewport(avpanel.getAlignViewport());
+    }
+    // could also set export/import settings
+  }
 }
index d241308..e795925 100755 (executable)
@@ -20,7 +20,8 @@
  */
 package jalview.io;
 
-import jalview.api.AlignViewportI;
+import jalview.api.AlignExportSettingI;
+import jalview.api.AlignmentViewPanel;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
@@ -28,6 +29,7 @@ import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.gui.AlignmentPanel;
 
 /**
  * Additional formatting methods used by the application in a number of places.
@@ -37,9 +39,9 @@ import jalview.datamodel.SequenceI;
  */
 public class FormatAdapter extends AppletFormatAdapter
 {
-  public FormatAdapter(AlignViewportI viewport)
+  public FormatAdapter(AlignmentViewPanel viewpanel)
   {
-    super(viewport);
+    super(viewpanel);
     init();
   }
 
@@ -49,6 +51,12 @@ public class FormatAdapter extends AppletFormatAdapter
     init();
   }
 
+  public FormatAdapter(AlignmentPanel alignPanel,
+          AlignExportSettingI settings)
+  {
+    super(alignPanel, settings);
+  }
+
   private void init()
   {
     if (jalview.bin.Cache.getDefault("STRUCT_FROM_PDB", true))
@@ -304,17 +312,17 @@ public class FormatAdapter extends AppletFormatAdapter
     return this.formatSequences(format, alignment, suffix);
   }
 
-  public Alignment readFile(String inFile, String type, String format)
+  public AlignmentI readFile(String inFile, String type, String format)
           throws java.io.IOException
   {
-    Alignment al = super.readFile(inFile, type, format);
+    AlignmentI al = super.readFile(inFile, type, format);
     return al;
   }
 
   public AlignmentI readFromFile(FileParse source, String format)
           throws java.io.IOException
   {
-    Alignment al = (Alignment) super.readFromFile(source, format);
+    AlignmentI al = super.readFromFile(source, format);
     return al;
   }
 
@@ -341,14 +349,19 @@ public class FormatAdapter extends AppletFormatAdapter
   }
 
   /**
-   * Create a flat file representation of a given view or selected region of a view
+   * Create a flat file representation of a given view or selected region of a
+   * view
+   * 
    * @param format
-   * @param av
+   * @param ap
+   *          alignment panel originating the view
    * @return String containing flat file
    */
-  public String formatSequences(String format, AlignViewportI av, boolean selectedOnly)
+  public String formatSequences(String format, AlignmentViewPanel ap,
+          boolean selectedOnly)
   {
-    return formatSequences(format, getCacheSuffixDefault(format), av, selectedOnly);
+    return formatSequences(format, getCacheSuffixDefault(format), ap,
+            selectedOnly);
   }
 
 
diff --git a/src/jalview/io/Gff3File.java b/src/jalview/io/Gff3File.java
new file mode 100644 (file)
index 0000000..1f8c3be
--- /dev/null
@@ -0,0 +1,154 @@
+package jalview.io;
+
+import jalview.api.AlignViewportI;
+import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * A GFF3 File parsing wrapper for the tangled mess that is FeaturesFile.
+ * 
+ * This class implements the methods relied on by FileLoader/FormatAdapter in
+ * order to allow them to load alignments directly from GFF2 and GFF3 files that
+ * contain sequence data and alignment information.
+ * 
+ * Major issues:
+ * 
+ * 1. GFF3 files commonly include mappings between DNA, RNA and Protein - so
+ * this class needs a dataset AlignmentI context to create alignment codon
+ * mappings.
+ * 
+ * 2. A single GFF3 file can generate many distinct alignments. Support will be
+ * needed to allow several AlignmentI instances to be generated from a single
+ * file.
+ * 
+ * 
+ * @author jprocter
+ *
+ */
+public class Gff3File extends FeaturesFile
+{
+
+  /**
+   * 
+   */
+  public Gff3File()
+  {
+    super();
+  }
+
+  /**
+   * @param source
+   * @throws IOException
+   */
+  public Gff3File(FileParse source) throws IOException
+  {
+    super(source);
+  }
+
+  /**
+   * @param inFile
+   * @param type
+   * @throws IOException
+   */
+  public Gff3File(String inFile, String type) throws IOException
+  {
+    super(inFile, type);
+  }
+
+  /**
+   * @param parseImmediately
+   * @param source
+   * @throws IOException
+   */
+  public Gff3File(boolean parseImmediately, FileParse source)
+          throws IOException
+  {
+    super(parseImmediately, source);
+  }
+
+  /**
+   * @param parseImmediately
+   * @param inFile
+   * @param type
+   * @throws IOException
+   */
+  public Gff3File(boolean parseImmediately, String inFile, String type)
+          throws IOException
+  {
+    super(parseImmediately, inFile, type);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.io.FeaturesFile#print()
+   */
+  @Override
+  public String print()
+  {
+    // TODO GFF3 writer with sensible defaults for writing alignment data
+
+    // return super.printGFFFormat(seqs, visible);
+    return ("Not yet implemented.");
+  }
+
+  AlignmentI dataset;
+
+  List<AlignmentI> alignments;
+  @Override
+  public void parse()
+  {
+    AlignViewportI av = getViewport();
+    if (av != null)
+    {
+      if (av.getAlignment() != null)
+      {
+        dataset = av.getAlignment().getDataset();
+      }
+      if (dataset == null)
+      {
+        // working in the applet context ?
+        dataset = av.getAlignment();
+      }
+    }
+    else
+    {
+      dataset = new Alignment(new SequenceI[]
+      {});
+    }
+
+    boolean parseResult = parse(dataset, null, null, false, true);
+    if (!parseResult)
+    {
+      // pass error up somehow
+    }
+    if (av != null)
+    {
+      // update viewport with the dataset data ?
+    }
+    else
+    {
+      setSeqs(dataset.getSequencesArray());
+    }
+
+  }
+
+  @Override
+  public void addProperties(AlignmentI al)
+  {
+    super.addProperties(al);
+    if (dataset.getCodonFrames() != null)
+    {
+      AlignmentI ds = (al.getDataset() == null) ? al : al.getDataset();
+      for (AlignedCodonFrame codons : dataset.getCodonFrames())
+      {
+        ds.addCodonFrame(codons);
+      }
+    }
+  }
+}
index 73aa5d2..a4e9bf4 100644 (file)
@@ -22,6 +22,7 @@
 package jalview.io;
 
 import java.io.IOException;
+import java.io.StringReader;
 
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
@@ -66,18 +67,24 @@ public class HtmlFile extends AlignFile implements ComplexAlignFile
   {
     try
     {
-      StringBuilder htmlData = new StringBuilder();
-      String currentLine;
-      while ((currentLine = nextLine()) != null)
-      {
-        htmlData.append(currentLine);
+      Element content = null;
+      Document doc = null;
+      try {
+         StringBuilder htmlData = new StringBuilder();
+          String currentLine;
+          while ((currentLine = nextLine()) != null)
+          {
+            htmlData.append(currentLine);
+          }
+
+          doc = Jsoup.parse(htmlData.toString());
+      } catch (OutOfMemoryError oom) {
+         errormessage = "Not enough memory to process HTML document";
+         throw new IOException(errormessage);
       }
-
-      Document doc = Jsoup.parse(htmlData.toString());
-      Element content = doc.getElementById("seqData");
-      String alignmentJsonString = content.val();
-
-      JSONFile jsonFile = new JSONFile().parse(alignmentJsonString);
+      content = doc.getElementById("seqData");
+      
+      JSONFile jsonFile = new JSONFile().parse(new StringReader(content.val()));
       this.seqs = jsonFile.getSeqs();
       this.seqGroups = jsonFile.getSeqGroups();
       this.annotations = jsonFile.getAnnotations();
@@ -87,7 +94,8 @@ public class HtmlFile extends AlignFile implements ComplexAlignFile
       this.columnSelection = jsonFile.getColumnSelection();
     } catch (Exception e)
     {
-      e.printStackTrace();
+      errormessage = "Failed to extract data from HTML document.";
+      throw new IOException("Unexpected exception whilst extracting JSon from HTML.",e);
     }
   }
 
index db34c2f..7e02118 100644 (file)
@@ -1,10 +1,9 @@
 package jalview.io;
 
+import jalview.api.FeatureRenderer;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignViewport;
 import jalview.gui.AlignmentPanel;
-import jalview.gui.AnnotationPanel;
-import jalview.gui.FeatureRenderer;
 import jalview.gui.HTMLOptions;
 import jalview.math.AlignmentDimension;
 import jalview.util.MessageManager;
@@ -27,15 +26,12 @@ public class HtmlSvgOutput
   FeatureRenderer fr;
   AlignmentPanel ap;
 
-  AnnotationPanel annotationPanel;
 
   public HtmlSvgOutput(File file, AlignmentPanel ap)
   {
-
-      this.av = ap.av;
-      this.ap = ap;
-    av.setFeatureRenderer(new FeatureRenderer(ap));
-      this.annotationPanel = ap.getAnnotationPanel();
+    this.av = ap.av;
+    this.ap = ap;
+    fr = ap.cloneFeatureRenderer();
     generateHtmlSvgOutput(file);
   }
 
@@ -101,7 +97,7 @@ public class HtmlSvgOutput
 
       String titleSvgData = g1.getSVGDocument();
       String alignSvgData = g2.getSVGDocument();
-      String jsonData = JSONFile.getJSONData(av);
+      String jsonData = JSONFile.getJSONData(ap);
       String htmlData = getHtml(titleSvgData, alignSvgData, jsonData);
 
       out.write(htmlData.getBytes());
index f1089ec..27f08ae 100755 (executable)
@@ -30,6 +30,8 @@ import java.io.IOException;
  */
 public class IdentifyFile
 {
+  public static final String GFF3File = "GFF v2 or v3";
+
   /**
    * Identify a datasource's file content.
    *
@@ -130,7 +132,12 @@ public class IdentifyFile
         }
         data = data.toUpperCase();
 
-        if ((data.indexOf("# STOCKHOLM") > -1))
+        if (data.startsWith("##GFF-VERSION"))
+        {
+          reply = GFF3File;
+          break;
+        }
+        if (data.indexOf("# STOCKHOLM") > -1)
         {
           reply = "STH";
           break;
index d2b8412..ce70ea5 100644 (file)
 
 package jalview.io;
 
-import java.awt.Color;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Vector;
-
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.json.simple.parser.JSONParser;
-
-import jalview.api.AlignViewportI;
+import jalview.api.AlignmentViewPanel;
 import jalview.api.ComplexAlignFile;
 import jalview.api.FeatureRenderer;
 import jalview.api.FeaturesDisplayedI;
@@ -55,6 +43,19 @@ import jalview.json.binding.v1.SequencePojo;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
 
+import java.awt.Color;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+
 public class JSONFile extends AlignFile implements ComplexAlignFile
 {
   private ColourSchemeI colourScheme;
@@ -79,8 +80,6 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
 
   private FeatureRenderer fr;
 
-  private JSONExportSettings jsonExportSettings;
-
   private List<int[]> hiddenColumns;
 
   private ColumnSelection columnSelection;
@@ -107,41 +106,16 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
   @Override
   public void parse() throws IOException
   {
-    StringBuilder jsonStringBuilder = new StringBuilder();
-    String currentLine;
-    while ((currentLine = nextLine()) != null)
-    {
-      jsonStringBuilder.append(currentLine);
-    }
-    parse(jsonStringBuilder.toString());
+    parse(getReader());
 
   }
-
   @Override
   public String print()
   {
     String jsonOutput = null;
     try
     {
-      if (getJsonExportSettings() == null)
-      {
-        jsonExportSettings = new JSONExportSettings();
-        jsonExportSettings.setExportAnnotations(true);
-        jsonExportSettings.setExportGroups(true);
-        jsonExportSettings.setExportJalviewSettings(true);
-        jsonExportSettings.setExportSequenceFeatures(true);
-      }
-
       AlignmentPojo jsonAlignmentPojo = new AlignmentPojo();
-      if (getViewport() != null)
-      {
-        globalColorScheme = ColourSchemeProperty
-                .getColourName(getViewport()
-                .getGlobalColourScheme());
-        setDisplayedFeatures(getViewport().getFeaturesDisplayed());
-        showSeqFeatures = getViewport().isShowSequenceFeatures();
-        fr = getViewport().getFeatureRenderer();
-      }
 
       int count = 0;
       for (SequenceI seq : seqs)
@@ -159,44 +133,46 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
         jsonAlignmentPojo.getSeqs().add(jsonSeqPojo);
       }
 
-      if (jsonExportSettings.isExportJalviewSettings())
+      jsonAlignmentPojo.setGlobalColorScheme(globalColorScheme);
+      jsonAlignmentPojo.getAppSettings().put("application", application);
+      jsonAlignmentPojo.getAppSettings().put("version", version);
+      jsonAlignmentPojo.getAppSettings().put("webStartUrl", webstartUrl);
+      jsonAlignmentPojo.getAppSettings().put("showSeqFeatures",
+              String.valueOf(showSeqFeatures));
+
+      String[] hiddenSections = getHiddenSections();
+      if (hiddenSections != null)
       {
-        jsonAlignmentPojo.setGlobalColorScheme(globalColorScheme);
-        jsonAlignmentPojo.getAppSettings().put("application", application);
-        jsonAlignmentPojo.getAppSettings().put("version", version);
-        jsonAlignmentPojo.getAppSettings().put("webStartUrl", webstartUrl);
-        jsonAlignmentPojo.getAppSettings().put("showSeqFeatures",
-                String.valueOf(showSeqFeatures));
-
-        String[] hiddenSections = exportHiddenSections();
-        if (hiddenSections != null && getViewport().isIncludeHiddenRegion())
+        if (hiddenSections[0] != null
+                && getExportSettings()
+                        .isExportHiddenColumns())
         {
-          if (hiddenSections[0] != null)
-          {
-            jsonAlignmentPojo.getAppSettings().put("hiddenCols",
-                    String.valueOf(hiddenSections[0]));
-          }
-          if (hiddenSections[1] != null)
-          {
-            jsonAlignmentPojo.getAppSettings().put("hiddenSeqs",
-                    String.valueOf(hiddenSections[1]));
-          }
+          jsonAlignmentPojo.getAppSettings().put("hiddenCols",
+                  String.valueOf(hiddenSections[0]));
+        }
+        if (hiddenSections[1] != null
+                && getExportSettings()
+                        .isExportHiddenSequences())
+        {
+          jsonAlignmentPojo.getAppSettings().put("hiddenSeqs",
+                  String.valueOf(hiddenSections[1]));
         }
       }
 
-      if (jsonExportSettings.isExportAnnotations())
+      if (getExportSettings().isExportAnnotations())
       {
         jsonAlignmentPojo
                 .setAlignAnnotation(annotationToJsonPojo(annotations));
       }
 
-      if (jsonExportSettings.isExportSequenceFeatures())
+      if (getExportSettings().isExportFeatures())
       {
         jsonAlignmentPojo
                 .setSeqFeatures(sequenceFeatureToJsonPojo(seqs, fr));
       }
 
-      if (jsonExportSettings.isExportGroups() && seqGroups != null
+      if (getExportSettings().isExportGroups()
+              && seqGroups != null
               && seqGroups.size() > 0)
       {
         for (SequenceGroup seqGrp : seqGroups)
@@ -231,7 +207,7 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
     return jsonOutput;
   }
 
-  public String[] exportHiddenSections()
+  public String[] getHiddenSections()
   {
     String[] hiddenSections = new String[2];
     if (getViewport() == null)
@@ -363,7 +339,7 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
   }
 
   @SuppressWarnings("unchecked")
-  public JSONFile parse(String jsonAlignmentString)
+  public JSONFile parse(Reader jsonAlignmentString)
   {
     try
     {
@@ -614,42 +590,48 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
     this.displayedFeatures = displayedFeatures;
   }
 
-  public JSONExportSettings getJsonExportSettings()
-  {
-    return jsonExportSettings;
-  }
-
-  public void setJsonExportSettings(JSONExportSettings jsonExportSettings)
+  @Override
+  public void configureForView(AlignmentViewPanel avpanel)
   {
-    this.jsonExportSettings = jsonExportSettings;
-  }
-
+    super.configureForView(avpanel);
+    if (isExporting())
+    {
+      setViewport(avpanel.getAlignViewport());
+      seqGroups = avpanel.getAlignment().getGroups();
+      setDisplayedFeatures(getViewport().getFeaturesDisplayed());
+      fr = avpanel.cloneFeatureRenderer();
 
-  public static String getJSONData(AlignViewportI av)
-  {
-    JSONFile jsonFile = new JSONFile();
-    jsonFile.setViewport(av);
-    jsonFile.seqGroups = av.getAlignment().getGroups();
-    jsonFile.setDisplayedFeatures(av.getFeaturesDisplayed());
+      for (SequenceI seq : getViewport().getAlignment().getSequences())
+      {
+        seqs.add(seq);
+      }
 
-    for (SequenceI seq : av.getAlignment().getSequences())
-    {
-      jsonFile.seqs.add(seq);
-    }
-  
-    // Add non auto calculated annotation to AlignFile
-    for (AlignmentAnnotation annot : av.getAlignment()
-            .getAlignmentAnnotation())
-    {
-      if (annot != null && !annot.autoCalculated)
+      // Add non auto calculated annotation to AlignFile
+      for (AlignmentAnnotation annot : getViewport().getAlignment()
+              .getAlignmentAnnotation())
       {
-        if (annot.label.equals("PDB.CATempFactor"))
+        if (annot != null && !annot.autoCalculated)
         {
-          continue;
+          if (annot.label.equals("PDB.CATempFactor"))
+          {
+            continue;
+          }
+          annotations.add(annot);
         }
-        jsonFile.annotations.add(annot);
       }
+
+      globalColorScheme = ColourSchemeProperty.getColourName(getViewport()
+              .getGlobalColourScheme());
+      setDisplayedFeatures(getViewport().getFeaturesDisplayed());
+      showSeqFeatures = getViewport().isShowSequenceFeatures();
     }
+  }
+
+
+  public static String getJSONData(AlignmentViewPanel av)
+  {
+    JSONFile jsonFile = new JSONFile();
+    jsonFile.configureForView(av);
     String jsonString = jsonFile.print();
     return jsonString;
   }
index ce65eea..d7f6dbc 100644 (file)
@@ -3,7 +3,6 @@
  */
 package jalview.io;
 
-import jalview.datamodel.Alignment;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 
@@ -171,13 +170,6 @@ public class PhylipFile extends AlignFile
         seqs.add(sequenceElements[i]);
       }
 
-      // create an alignment based on the sequences
-      Alignment a = new Alignment(sequenceElements);
-      // add annotations - although comments say addAnnotations
-      // is used by AppletFormatAdapter, it doesn't say other
-      // classes should/can not use it
-      addAnnotations(a);
-
     } catch (IOException e)
     {
       System.err.println("Exception parsing PHYLIP file " + e);
diff --git a/src/jalview/jbgui/GAlignExportSettings.java b/src/jalview/jbgui/GAlignExportSettings.java
new file mode 100644 (file)
index 0000000..2583b6b
--- /dev/null
@@ -0,0 +1,146 @@
+package jalview.jbgui;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JPanel;
+
+@SuppressWarnings("serial")
+public abstract class GAlignExportSettings extends JPanel
+{
+  protected JPanel hiddenRegionConfPanel = new JPanel();
+
+  protected JPanel complexExportPanel = new JPanel();
+
+  protected JPanel optionsPanel = new JPanel();
+
+  protected JPanel actionPanel = new JPanel();
+
+  protected BorderLayout hiddenRegionLayout = new BorderLayout();
+
+  protected BorderLayout complexExportLayout = new BorderLayout();
+
+  protected BorderLayout mainLayout = new BorderLayout();
+
+  protected JCheckBox chkAll = new JCheckBox("Check All");
+
+  protected JCheckBox chkHiddenSeqs = new JCheckBox(
+          "Export Hidden Sequences");
+
+  protected JCheckBox chkHiddenCols = new JCheckBox("Export Hidden Columns");
+
+  protected JCheckBox chkExportAnnots = new JCheckBox("Export Annotations");
+
+  protected JCheckBox chkExportFeats = new JCheckBox("Export Features");
+
+  protected JCheckBox chkExportGrps = new JCheckBox("Export Groups");
+
+  JButton btnOk = new JButton("Ok");
+
+  JButton btnCancel = new JButton("Cancel");
+
+  private boolean hasHiddenSeq, hasHiddenCols, isComplexAlignFile;
+
+  boolean isComplexFormat = false;
+
+  public GAlignExportSettings(boolean hasHiddenSeq, boolean hasHiddenCols,
+          String alignFileFormat)
+  {
+    this.hasHiddenSeq = hasHiddenSeq;
+    this.hasHiddenCols = hasHiddenCols;
+    String[] complexFormats =
+    { "JSON", "HTML" };
+
+    for (String format : complexFormats)
+    {
+      if (format.equalsIgnoreCase(alignFileFormat))
+      {
+        this.isComplexAlignFile = true;
+        break;
+      }
+    }
+
+    init();
+  }
+
+  public void init()
+  {
+    hiddenRegionConfPanel.setLayout(hiddenRegionLayout);
+    complexExportPanel.setLayout(complexExportLayout);
+    setLayout(mainLayout);
+
+    chkAll.addItemListener(new ItemListener()
+    {
+      public void itemStateChanged(ItemEvent e)
+      {
+        checkAllAction();
+      }
+    });
+
+    btnOk.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        ok_actionPerformed(e);
+      }
+    });
+
+    btnCancel.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        cancel_actionPerformed(e);
+      }
+    });
+
+    hiddenRegionConfPanel.add(chkAll, BorderLayout.NORTH);
+    hiddenRegionConfPanel.add(chkHiddenSeqs, BorderLayout.CENTER);
+    hiddenRegionConfPanel.add(chkHiddenCols, BorderLayout.SOUTH);
+    chkHiddenSeqs.setEnabled(hasHiddenSeq);
+    chkHiddenCols.setEnabled(hasHiddenCols);
+
+    complexExportPanel.add(chkExportAnnots, BorderLayout.NORTH);
+    complexExportPanel.add(chkExportFeats, BorderLayout.CENTER);
+    complexExportPanel.add(chkExportGrps, BorderLayout.SOUTH);
+
+    if (hasHiddenSeq || hasHiddenCols)
+    {
+      optionsPanel.add(hiddenRegionConfPanel);
+    }
+
+    if (isComplexAlignFile)
+    {
+      optionsPanel.add(complexExportPanel);
+    }
+    actionPanel.add(btnCancel);
+    actionPanel.add(btnOk);
+
+    add(optionsPanel, BorderLayout.NORTH);
+    add(actionPanel, BorderLayout.SOUTH);
+
+  }
+
+
+  
+  private void checkAllAction()
+  {
+    boolean isSelected = chkAll.isSelected();
+    chkHiddenSeqs.setSelected(chkHiddenSeqs.isEnabled() && isSelected);
+    chkHiddenCols.setSelected(chkHiddenCols.isEnabled() && isSelected);
+    chkExportAnnots.setSelected(isComplexAlignFile
+            && chkExportAnnots.isEnabled() && isSelected);
+    chkExportFeats.setSelected(isComplexAlignFile
+            && chkExportFeats.isEnabled() && isSelected);
+    chkExportGrps.setSelected(isComplexAlignFile
+            && chkExportGrps.isEnabled() && isSelected);
+  }
+
+  public abstract void ok_actionPerformed(ActionEvent e);
+
+  public abstract void cancel_actionPerformed(ActionEvent e);
+}
index 45a5957..0b2e6be 100755 (executable)
@@ -20,7 +20,7 @@
  */
 package jalview.jbgui;
 
-import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
 import jalview.io.FormatAdapter;
 import jalview.util.MessageManager;
 
@@ -211,7 +211,7 @@ public class GFinder extends JPanel
         public void run()
         {
           String str = textfield.getText();
-          Alignment al = null;
+          AlignmentI al = null;
           try
           {
             al = new FormatAdapter().readFile(str, "Paste", "FASTA");
index 399347b..5617bcf 100644 (file)
  */
 package jalview.viewmodel;
 
-import java.awt.Color;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.analysis.Conservation;
 import jalview.api.AlignCalcManagerI;
@@ -67,6 +56,17 @@ import jalview.workers.ComplementConsensusThread;
 import jalview.workers.ConsensusThread;
 import jalview.workers.StrucConsensusThread;
 
+import java.awt.Color;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 /**
  * base class holding visualization and analysis attributes and common logic for
  * an active alignment view displayed in the GUI
@@ -1055,18 +1055,12 @@ public abstract class AlignmentViewport implements AlignViewportI,
     // hasHiddenColumns = colSel.hasHiddenColumns();
   }
 
-  protected boolean hasHiddenRows = false;
-
   @Override
   public boolean hasHiddenRows()
   {
-    return hasHiddenRows;
+    return alignment.getHiddenSequences().getSize() > 0;
   }
 
-  public void setHasHiddenRows(boolean hasHiddenRows)
-  {
-    this.hasHiddenRows = hasHiddenRows;
-  }
 
   protected SequenceGroup selectionGroup;
 
@@ -1304,7 +1298,6 @@ public abstract class AlignmentViewport implements AlignViewportI,
         setSequenceAnnotationsVisible(seq, true);
       }
 
-      hasHiddenRows = false;
       hiddenRepSequences = null;
 
       firePropertyChange("alignment", null, alignment.getSequences());
@@ -1332,12 +1325,6 @@ public abstract class AlignmentViewport implements AlignViewportI,
         selectionGroup.addSequence(seq, false);
         setSequenceAnnotationsVisible(seq, true);
       }
-      // JBPNote: refactor: only update flag if we modified visiblity (used to
-      // do this regardless)
-      if (alignment.getHiddenSequences().getSize() < 1)
-      {
-        hasHiddenRows = false;
-      }
       firePropertyChange("alignment", null, alignment.getSequences());
       sendSelection();
     }
@@ -1366,7 +1353,6 @@ public abstract class AlignmentViewport implements AlignViewportI,
         alignment.getHiddenSequences().hideSequence(seq[i]);
         setSequenceAnnotationsVisible(seq[i], false);
       }
-      hasHiddenRows = true;
       firePropertyChange("alignment", null, alignment.getSequences());
     }
   }
index 57d57da..15d1da7 100644 (file)
@@ -2,7 +2,7 @@ package jalview.viewmodel.seqfeatures;
 
 import jalview.api.FeatureSettingsModelI;
 
-public class FeatureSettingsModel implements FeatureSettingsModelI
+public abstract class FeatureSettingsModel implements FeatureSettingsModelI
 {
 
 }
index e22aa12..3db663d 100644 (file)
@@ -587,7 +587,7 @@ public class DasSequenceFeatureFetcher
 
     if (af != null && af.featureSettings != null)
     {
-      af.featureSettings.setTableData();
+      af.featureSettings.discoverAllFeatureData();
     }
 
     if (getFeatSettings() != null)
index 6a871ee..4c8f3ce 100644 (file)
  */
 package jalview.ws.dbsources;
 
-import java.io.File;
-import java.io.FileReader;
-import java.io.Reader;
-import java.util.Vector;
-
-import org.exolab.castor.xml.Unmarshaller;
-
-import com.stevesoft.pat.Regex;
-
-import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
@@ -42,6 +32,15 @@ import jalview.ws.ebi.EBIFetchClient;
 import jalview.ws.seqfetcher.DbSourceProxy;
 import jalview.ws.seqfetcher.DbSourceProxyImpl;
 
+import java.io.File;
+import java.io.FileReader;
+import java.io.Reader;
+import java.util.Vector;
+
+import org.exolab.castor.xml.Unmarshaller;
+
+import com.stevesoft.pat.Regex;
+
 /**
  * @author JimP
  * 
@@ -156,7 +155,7 @@ public class Uniprot extends DbSourceProxyImpl implements DbSourceProxy
     {
       queries = queries.toUpperCase().replaceAll(
               "(UNIPROT\\|?|UNIPROT_|UNIREF\\d+_|UNIREF\\d+\\|?)", "");
-      Alignment al = null;
+      AlignmentI al = null;
       EBIFetchClient ebi = new EBIFetchClient();
       // uniprotxml parameter required since december 2007
       // uniprotkb dbname changed introduced december 2008
@@ -245,7 +244,7 @@ public class Uniprot extends DbSourceProxyImpl implements DbSourceProxy
    * @param entries
    *          a list of n uniprot entries to be analysed.
    */
-  public void addUniprotXrefs(Alignment al, Vector<UniprotEntry> entries)
+  public void addUniprotXrefs(AlignmentI al, Vector<UniprotEntry> entries)
   {
     final String dbVersion = getDbVersion();
 
index 69d0ae4..62566cf 100644 (file)
@@ -24,6 +24,7 @@ import jalview.analysis.AlignSeq;
 import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.SequenceI;
@@ -103,7 +104,7 @@ class JPredThread extends JWS1Thread implements WSClientI
       {
         return null;
       }
-      Alignment al = null;
+      AlignmentI al = null;
       ColumnSelection alcsel = null;
       int FirstSeq = -1; // the position of the query sequence in Alignment al
 
@@ -279,7 +280,7 @@ class JPredThread extends JWS1Thread implements WSClientI
      * @param al
      * @param profileseq
      */
-    private void alignToProfileSeq(Alignment al, SequenceI profileseq)
+    private void alignToProfileSeq(AlignmentI al, SequenceI profileseq)
     {
       char gc = al.getGapCharacter();
       int[] gapMap = profileseq.gapMap();
index 719027f..0785dfa 100644 (file)
@@ -20,7 +20,7 @@
  */
 package jalview.ws.seqfetcher;
 
-import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
 import jalview.io.FormatAdapter;
 import jalview.io.IdentifyFile;
 
@@ -118,9 +118,9 @@ public abstract class DbSourceProxyImpl implements DbSourceProxy
    * @return null or a valid alignment
    * @throws Exception
    */
-  protected Alignment parseResult(String result) throws Exception
+  protected AlignmentI parseResult(String result) throws Exception
   {
-    Alignment sequences = null;
+    AlignmentI sequences = null;
     String format = new IdentifyFile().Identify(result, "Paste");
     if (FormatAdapter.isValidFormat(format))
     {
index a503460..d44a6bc 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.analysis;
 
+
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertNull;
@@ -264,7 +265,7 @@ public class AlignmentUtilsTests
    */
   protected AlignmentI loadAlignment(final String data, String format) throws IOException
   {
-    Alignment a = new FormatAdapter().readFile(data,
+    AlignmentI a = new FormatAdapter().readFile(data,
             AppletFormatAdapter.PASTE, format);
     a.setDataset(null);
     return a;
index 1be9bea..036f2cf 100644 (file)
@@ -69,7 +69,7 @@ public class AlignmentTest
   protected AlignmentI loadAlignment(final String data, String format)
           throws IOException
   {
-    Alignment a = new FormatAdapter().readFile(data,
+    AlignmentI a = new FormatAdapter().readFile(data,
             AppletFormatAdapter.PASTE, format);
     a.setDataset(null);
     return a;
diff --git a/test/jalview/datamodel/SequenceDummyTest.java b/test/jalview/datamodel/SequenceDummyTest.java
new file mode 100644 (file)
index 0000000..2fc1934
--- /dev/null
@@ -0,0 +1,39 @@
+package jalview.datamodel;
+
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SequenceDummyTest
+{
+  /**
+   * test for become method
+   */
+  @Test
+  public void testBecome()
+  {
+    SequenceI seq = new Sequence("OrigSeq", "ASEQUENCE");
+    SequenceFeature ofeat = new SequenceFeature("NewFeat", "somedesc", 3,
+            12, 2.3f, "none");
+    
+    SequenceDummy dummySeq = new SequenceDummy("OrigSeq");
+    dummySeq.addSequenceFeature(ofeat);
+    dummySeq.become(seq);
+    Assert.assertFalse("Dummy sequence did not become a full sequence",
+            dummySeq.isDummy());
+    Assert.assertTrue("Sequence was not updated from template", seq
+            .getSequenceAsString().equals(dummySeq.getSequenceAsString()));
+    boolean found = false;
+    for (SequenceFeature sf : dummySeq.getSequenceFeatures())
+    {
+      if (sf == ofeat)
+      {
+        found = true;
+        break;
+      }
+    }
+    Assert.assertTrue("Didn't retain original sequence feature", found);
+
+    // todo - should test all aspect of copy constructor
+  }
+}
diff --git a/test/jalview/io/Gff3tests.java b/test/jalview/io/Gff3tests.java
new file mode 100644 (file)
index 0000000..8df44df
--- /dev/null
@@ -0,0 +1,147 @@
+package jalview.io;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceDummy;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+
+import java.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class Gff3tests
+{
+
+  private static String exonerateSeqs = "examples/testdata/exonerateseqs.fa",
+          exonerateOutput = "examples/testdata/exonerateoutput.gff",
+          simpleGff3file = "examples/testdata/simpleGff3.gff";
+
+  @Test
+  public void testExonerateImport()
+  {
+    // exonerate does not tag sequences after features, so we have a more
+    // conventional annotation import test here
+
+    FileLoader loader = new FileLoader(false);
+
+    AlignFrame af = loader.LoadFileWaitTillLoaded(exonerateSeqs,
+            FormatAdapter.FILE);
+
+    Assert.assertEquals("Unexpected number of DNA protein associations", 0,
+            af.getViewport().getAlignment().getCodonFrames().size());
+
+    af.loadJalviewDataFile(exonerateOutput, FormatAdapter.FILE, null, null);
+
+    Assert.assertNotEquals("Expected at least one DNA protein association",
+            0, af.getViewport().getAlignment().getDataset()
+                    .getCodonFrames().size());
+
+  }
+
+  @Test
+  public void simpleGff3FileIdentify()
+  {
+    Assert.assertEquals("Didn't recognise file correctly.",
+            IdentifyFile.GFF3File,
+            new IdentifyFile().Identify(simpleGff3file, FormatAdapter.FILE));
+  }
+
+  @Test
+  public void simpleGff3FileClass() throws IOException
+  {
+    AlignmentI dataset = new Alignment(new SequenceI[]
+    {});
+    FeaturesFile ffile = new FeaturesFile(simpleGff3file,
+            FormatAdapter.FILE);
+
+    boolean parseResult = ffile.parse(dataset, null, null, false, false);
+    Assert.assertTrue("return result should be true", parseResult);
+    checkDatasetfromSimpleGff3(dataset);
+  }
+
+  @Test
+  public void simpleGff3FileLoader() throws IOException
+  {
+    AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded(
+            simpleGff3file, FormatAdapter.FILE);
+    Assert.assertTrue(
+            "Didn't read the alignment into an alignframe from Gff3 File",
+            af != null);
+    checkDatasetfromSimpleGff3(af.getViewport().getAlignment().getDataset());
+  }
+
+  @Test
+  public void simpleGff3RelaxedIdMatching() throws IOException
+  {
+    AlignmentI dataset = new Alignment(new SequenceI[]
+    {});
+    FeaturesFile ffile = new FeaturesFile(simpleGff3file,
+            FormatAdapter.FILE);
+
+    boolean parseResult = ffile.parse(dataset, null, null, false, true);
+    Assert.assertTrue("return result (relaxedID matching) should be true",
+            parseResult);
+    checkDatasetfromSimpleGff3(dataset);
+  }
+
+  @Test
+  public void readGff3File() throws IOException
+  {
+    Gff3File gff3reader = new Gff3File(simpleGff3file, FormatAdapter.FILE);
+    Alignment dataset = new Alignment(gff3reader.getSeqsAsArray());
+    gff3reader.addProperties(dataset);
+    checkDatasetfromSimpleGff3(dataset);
+
+  }
+
+  private void checkDatasetfromSimpleGff3(AlignmentI dataset)
+  {
+    Assert.assertEquals("no sequences extracted from GFF3 file", 2,
+            dataset.getHeight());
+
+    SequenceI seq1 = dataset.findName("seq1"), seq2 = dataset
+            .findName("seq2");
+    Assert.assertNotNull(seq1);
+    Assert.assertNotNull(seq2);
+    Assert.assertFalse(
+            "Failed to replace dummy seq1 with real sequence",
+            seq1 instanceof SequenceDummy
+                    && ((SequenceDummy) seq1).isDummy());
+    Assert.assertFalse(
+            "Failed to replace dummy seq2 with real sequence",
+            seq2 instanceof SequenceDummy
+                    && ((SequenceDummy) seq2).isDummy());
+    String placeholderseq = new SequenceDummy("foo").getSequenceAsString();
+    Assert.assertFalse("dummy replacement buggy for seq1",
+            placeholderseq.equals(seq1.getSequenceAsString()));
+    Assert.assertNotEquals("dummy replacement buggy for seq2",
+            placeholderseq.equals(seq2.getSequenceAsString()));
+    Assert.assertNotNull("No features added to seq1",
+            seq1.getSequenceFeatures());// != null);
+    Assert.assertEquals("Wrong number of features", 3,
+            seq1.getSequenceFeatures().length);
+    Assert.assertNull(seq2.getSequenceFeatures());
+    Assert.assertEquals("Wrong number of features", 0, seq2
+            .getSequenceFeatures() == null ? 0
+            : seq2.getSequenceFeatures().length);
+    Assert.assertTrue(
+            "Expected at least one CDNA/Protein mapping for seq1",
+            dataset.getCodonFrame(seq1) != null
+                    && dataset.getCodonFrame(seq1).size() > 0);
+
+  }
+  // @Test
+  // public final void testPrintGFFFormatSequenceIArrayMapOfStringObject()
+  // {
+  // fail("Not yet implemented");
+  // }
+  //
+  // @Test
+  // public final void testAlignFileBooleanStringString()
+  // {
+  // fail("Not yet implemented");
+  // }
+
+}
index 33e67ce..2e28e3a 100644 (file)
@@ -3,7 +3,6 @@ package jalview.io;
 
 import static org.testng.AssertJUnit.assertNotNull;
 
-import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
@@ -157,7 +156,7 @@ public class JSONFileTest
   {
     String jsonFile = "examples/example.json";
     AppletFormatAdapter rf = new AppletFormatAdapter();
-    Alignment al = null;
+    AlignmentI al = null;
     try
     {
       al = rf.readFile(jsonFile, AppletFormatAdapter.FILE,
index 9db4763..d335731 100644 (file)
@@ -3,7 +3,7 @@ package jalview.io;
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 
-import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
 
 import java.io.IOException;
@@ -106,7 +106,7 @@ public class PhylipFileTests
   private void testDataExtraction(String file) throws IOException
   {
     AppletFormatAdapter rf = new AppletFormatAdapter();
-    Alignment al = rf.readFile(file, AppletFormatAdapter.FILE,
+    AlignmentI al = rf.readFile(file, AppletFormatAdapter.FILE,
             PhylipFile.FILE_DESC);
     assertNotNull("Couldn't read supplied alignment data.", al);
 
@@ -151,13 +151,13 @@ public class PhylipFileTests
   public void testIO(String file) throws IOException
   {
     AppletFormatAdapter rf = new AppletFormatAdapter();
-    Alignment al = rf.readFile(file, AppletFormatAdapter.FILE,
+    AlignmentI al = rf.readFile(file, AppletFormatAdapter.FILE,
             PhylipFile.FILE_DESC);
     assertNotNull("Couldn't read supplied alignment data.", al);
 
     String outputfile = rf.formatSequences(PhylipFile.FILE_DESC, al, true);
 
-    Alignment al_input = new AppletFormatAdapter().readFile(outputfile,
+    AlignmentI al_input = new AppletFormatAdapter().readFile(outputfile,
             AppletFormatAdapter.PASTE, PhylipFile.FILE_DESC);
     assertNotNull("Couldn't parse reimported alignment data.", al_input);
 
index 1c4825f..d684512 100644 (file)
@@ -43,7 +43,7 @@ public class RNAMLfileTest
   public void testRnamlToStockholmIO()
   {
     StockholmFileTest.testFileIOwithFormat(new File(
-            "examples/rna-alignment.xml"), "STH", -1, -1);
+            "examples/testdata/rna-alignment.xml"), "STH", -1, -1);
 
   }
 
index 1c46d1f..45de531 100644 (file)
@@ -24,7 +24,6 @@ import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 
-import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
@@ -95,7 +94,7 @@ public class StockholmFileTest
     {
       AppletFormatAdapter rf = new AppletFormatAdapter();
 
-      Alignment al = rf.readFile(ff, AppletFormatAdapter.FILE,
+      AlignmentI al = rf.readFile(ff, AppletFormatAdapter.FILE,
               new IdentifyFile().Identify(ff, AppletFormatAdapter.FILE));
 
       assertNotNull("Couldn't read supplied alignment data.", al);
@@ -109,7 +108,7 @@ public class StockholmFileTest
       System.out.println("Output file in '" + ioformat + "':\n"
               + outputfile + "\n<<EOF\n");
       // test for consistency in io
-      Alignment al_input = new AppletFormatAdapter().readFile(outputfile,
+      AlignmentI al_input = new AppletFormatAdapter().readFile(outputfile,
               AppletFormatAdapter.PASTE, ioformat);
       assertNotNull("Couldn't parse reimported alignment data.", al_input);
 
@@ -352,9 +351,11 @@ public class StockholmFileTest
                 an_new.displayCharacter.trim())
                 || !("" + an_or.secondaryStructure).trim().equals(
                         ("" + an_new.secondaryStructure).trim())
-                || (an_or.description != an_new.description && (an_or.description == null
-                        || an_new.description == null || !an_or.description
-                          .equals(an_new.description))))
+                || (an_or.description != an_new.description && !((an_or.description == null && an_new.description
+                        .trim().length() == 0)
+                        || (an_new.description == null && an_or.description
+                                .trim().length() == 0) || an_or.description
+                        .trim().equals(an_new.description.trim()))))
         {
           System.err.println("Annotation Element Mismatch\nElement " + i
                   + " in original: " + annot_or.annotations[i].toString()
index 0f2baf4..9985fb3 100644 (file)
@@ -1,12 +1,12 @@
 package jalview.util;
 
+
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.api.AlignViewportI;
 import jalview.datamodel.AlignedCodonFrame;
-import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.SearchResults;
@@ -248,7 +248,7 @@ public class MappingUtilsTest
   protected AlignmentI loadAlignment(final String data, String format)
           throws IOException
   {
-    Alignment a = new FormatAdapter().readFile(data,
+    AlignmentI a = new FormatAdapter().readFile(data,
             AppletFormatAdapter.PASTE, format);
     a.setDataset(null);
     return a;
index 6699035..98747f7 100644 (file)
  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
-import java.io.*;
-import java.util.*;
+import java.io.DataInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
 import java.util.jar.JarEntry;
 import java.util.jar.JarInputStream;
 
@@ -140,6 +143,9 @@ public class getJavaVersion
       versions.put("48.0", "1.4");
       versions.put("49.0", "1.5");
       versions.put("50.0", "1.6");
+      versions.put("51.0", "1.7");
+      versions.put("52.0", "1.8");
+
     }
     String version = (String) versions.get(major + "."
             + minor);
@@ -149,6 +155,10 @@ public class getJavaVersion
       version = (String) versions.get(major + ".0");
     }
 //    System.err.println("Version "+version);
+    if (version == null)
+    {
+      versions.put(major + "." + minor, "Class v" + major + ".0");
+    }
     return version;
   }