76c526670ea54347e1bfd7c245c1869940091996
[jalview.git] / test / jalview / project / Jalview2xmlTests.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.project;
22
23 import static org.testng.Assert.assertEquals;
24 import static org.testng.Assert.assertFalse;
25 import static org.testng.Assert.assertNotNull;
26 import static org.testng.Assert.assertNotSame;
27 import static org.testng.Assert.assertNull;
28 import static org.testng.Assert.assertSame;
29 import static org.testng.Assert.assertTrue;
30
31 import java.awt.Color;
32 import java.awt.Rectangle;
33 import java.io.File;
34 import java.io.IOException;
35 import java.math.BigInteger;
36 import java.util.ArrayList;
37 import java.util.BitSet;
38 import java.util.HashMap;
39 import java.util.List;
40 import java.util.Locale;
41 import java.util.Map;
42
43 import javax.swing.JInternalFrame;
44
45 import org.testng.Assert;
46 import org.testng.AssertJUnit;
47 import org.testng.annotations.BeforeClass;
48 import org.testng.annotations.Test;
49
50 import jalview.analysis.AlignmentUtils;
51 import jalview.analysis.scoremodels.SimilarityParams;
52 import jalview.api.AlignViewportI;
53 import jalview.api.AlignmentViewPanel;
54 import jalview.api.FeatureColourI;
55 import jalview.api.ViewStyleI;
56 import jalview.bin.Cache;
57 import jalview.datamodel.AlignmentAnnotation;
58 import jalview.datamodel.AlignmentI;
59 import jalview.datamodel.Annotation;
60 import jalview.datamodel.ContactListI;
61 import jalview.datamodel.ContactMatrix;
62 import jalview.datamodel.ContactMatrixI;
63 import jalview.datamodel.DBRefEntry;
64 import jalview.datamodel.GeneLocus;
65 import jalview.datamodel.GroupSet;
66 import jalview.datamodel.HiddenSequences;
67 import jalview.datamodel.Mapping;
68 import jalview.datamodel.PDBEntry;
69 import jalview.datamodel.PDBEntry.Type;
70 import jalview.datamodel.Sequence;
71 import jalview.datamodel.Sequence.DBModList;
72 import jalview.datamodel.SequenceCollectionI;
73 import jalview.datamodel.SequenceFeature;
74 import jalview.datamodel.SequenceGroup;
75 import jalview.datamodel.SequenceI;
76 import jalview.datamodel.features.FeatureMatcher;
77 import jalview.datamodel.features.FeatureMatcherSet;
78 import jalview.datamodel.features.FeatureMatcherSetI;
79 import jalview.gui.AlignFrame;
80 import jalview.gui.AlignViewport;
81 import jalview.gui.AlignmentPanel;
82 import jalview.gui.Desktop;
83 import jalview.gui.JvOptionPane;
84 import jalview.gui.OverviewPanel;
85 import jalview.gui.PCAPanel;
86 import jalview.gui.PopupMenu;
87 import jalview.gui.Preferences;
88 import jalview.gui.SliderPanel;
89 import jalview.io.DataSourceType;
90 import jalview.io.FileFormat;
91 import jalview.io.FileLoader;
92 import jalview.io.Jalview2xmlBase;
93 import jalview.renderer.ResidueShaderI;
94 import jalview.schemes.AnnotationColourGradient;
95 import jalview.schemes.BuriedColourScheme;
96 import jalview.schemes.ColourSchemeI;
97 import jalview.schemes.ColourSchemeProperty;
98 import jalview.schemes.FeatureColour;
99 import jalview.schemes.JalviewColourScheme;
100 import jalview.schemes.RNAHelicesColour;
101 import jalview.schemes.StrandColourScheme;
102 import jalview.schemes.TCoffeeColourScheme;
103 import jalview.structure.StructureImportSettings;
104 import jalview.util.MapList;
105 import jalview.util.matcher.Condition;
106 import jalview.viewmodel.AlignmentViewport;
107 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
108 import jalview.ws.datamodel.MappableContactMatrixI;
109 import jalview.ws.datamodel.alphafold.PAEContactMatrix;
110
111 @Test(singleThreaded = true)
112 public class Jalview2xmlTests extends Jalview2xmlBase
113 {
114
115   @Override
116   @BeforeClass(alwaysRun = true)
117   public void setUpJvOptionPane()
118   {
119     if (Desktop.instance != null)
120       Desktop.instance.closeAll_actionPerformed(null);
121     JvOptionPane.setInteractiveMode(false);
122     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
123   }
124
125   @Test(groups = { "Functional" })
126   public void testRNAStructureRecovery() throws Exception
127   {
128     String inFile = "examples/RF00031_folded.stk";
129     String tfile = File.createTempFile("JalviewTest", ".jvp")
130             .getAbsolutePath();
131     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
132             DataSourceType.FILE);
133     assertNotNull(af, "Didn't read input file " + inFile);
134     int olddsann = countDsAnn(af.getViewport());
135     assertTrue(olddsann > 0, "Didn't find any dataset annotations");
136     af.changeColour_actionPerformed(
137             JalviewColourScheme.RNAHelices.toString());
138     assertTrue(
139             af.getViewport()
140                     .getGlobalColourScheme() instanceof RNAHelicesColour,
141             "Couldn't apply RNA helices colourscheme");
142     af.saveAlignment(tfile, FileFormat.Jalview);
143     assertTrue(af.isSaveAlignmentSuccessful(),
144             "Failed to store as a project.");
145     af.closeMenuItem_actionPerformed(true);
146     af = null;
147     af = new FileLoader().LoadFileWaitTillLoaded(tfile,
148             DataSourceType.FILE);
149     assertNotNull(af, "Failed to import new project");
150     int newdsann = countDsAnn(af.getViewport());
151     assertEquals(olddsann, newdsann,
152             "Differing numbers of dataset sequence annotation\nOriginally "
153                     + olddsann + " and now " + newdsann);
154     System.out.println(
155             "Read in same number of annotations as originally present ("
156                     + olddsann + ")");
157     assertTrue(
158
159             af.getViewport()
160                     .getGlobalColourScheme() instanceof RNAHelicesColour,
161             "RNA helices colourscheme was not applied on import.");
162   }
163
164   @Test(groups = { "Functional" })
165   public void testTCoffeeScores() throws Exception
166   {
167     String inFile = "examples/uniref50.fa",
168             inAnnot = "examples/uniref50.score_ascii";
169     String tfile = File.createTempFile("JalviewTest", ".jvp")
170             .getAbsolutePath();
171     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
172             DataSourceType.FILE);
173     assertNotNull(af, "Didn't read input file " + inFile);
174     af.loadJalviewDataFile(inAnnot, DataSourceType.FILE, null, null);
175     AlignViewport viewport = af.getViewport();
176     assertSame(viewport.getGlobalColourScheme().getClass(),
177             TCoffeeColourScheme.class, "Didn't set T-coffee colourscheme");
178     assertNotNull(
179             ColourSchemeProperty.getColourScheme(viewport,
180                     viewport.getAlignment(),
181                     viewport.getGlobalColourScheme().getSchemeName()),
182             "Recognise T-Coffee score from string");
183
184     af.saveAlignment(tfile, FileFormat.Jalview);
185     assertTrue(af.isSaveAlignmentSuccessful(),
186             "Failed to store as a project.");
187     af.closeMenuItem_actionPerformed(true);
188     af = null;
189     af = new FileLoader().LoadFileWaitTillLoaded(tfile,
190             DataSourceType.FILE);
191     assertNotNull(af, "Failed to import new project");
192     assertSame(af.getViewport().getGlobalColourScheme().getClass(),
193             TCoffeeColourScheme.class,
194             "Didn't set T-coffee colourscheme for imported project.");
195     System.out.println(
196             "T-Coffee score shading successfully recovered from project.");
197   }
198
199   @Test(groups = { "Functional" })
200   public void testColourByAnnotScores() throws Exception
201   {
202     String inFile = "examples/uniref50.fa",
203             inAnnot = "examples/testdata/uniref50_iupred.jva";
204     String tfile = File.createTempFile("JalviewTest", ".jvp")
205             .getAbsolutePath();
206     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
207             DataSourceType.FILE);
208     assertNotNull(af, "Didn't read input file " + inFile);
209     af.loadJalviewDataFile(inAnnot, DataSourceType.FILE, null, null);
210     AlignmentAnnotation[] aa = af.getViewport().getAlignment()
211             .getSequenceAt(0).getAnnotation("IUPredWS (Short)");
212     assertTrue(
213
214             aa != null && aa.length > 0,
215             "Didn't find any IUPred annotation to use to shade alignment.");
216     AnnotationColourGradient cs = new AnnotationColourGradient(aa[0], null,
217             AnnotationColourGradient.ABOVE_THRESHOLD);
218     AnnotationColourGradient gcs = new AnnotationColourGradient(aa[0], null,
219             AnnotationColourGradient.BELOW_THRESHOLD);
220     cs.setSeqAssociated(true);
221     gcs.setSeqAssociated(true);
222     af.changeColour(cs);
223     SequenceGroup sg = new SequenceGroup();
224     sg.setStartRes(57);
225     sg.setEndRes(92);
226     sg.cs.setColourScheme(gcs);
227     af.getViewport().getAlignment().addGroup(sg);
228     sg.addSequence(af.getViewport().getAlignment().getSequenceAt(1), false);
229     sg.addSequence(af.getViewport().getAlignment().getSequenceAt(2), true);
230     af.alignPanel.alignmentChanged();
231     af.saveAlignment(tfile, FileFormat.Jalview);
232     assertTrue(af.isSaveAlignmentSuccessful(),
233             "Failed to store as a project.");
234     af.closeMenuItem_actionPerformed(true);
235     af = null;
236     af = new FileLoader().LoadFileWaitTillLoaded(tfile,
237             DataSourceType.FILE);
238     assertNotNull(af, "Failed to import new project");
239
240     // check for group and alignment colourschemes
241
242     ColourSchemeI _rcs = af.getViewport().getGlobalColourScheme();
243     ColourSchemeI _rgcs = af.getViewport().getAlignment().getGroups().get(0)
244             .getColourScheme();
245     assertNotNull(_rcs, "Didn't recover global colourscheme");
246     assertTrue(_rcs instanceof AnnotationColourGradient,
247             "Didn't recover annotation colour global scheme");
248     AnnotationColourGradient __rcs = (AnnotationColourGradient) _rcs;
249     assertTrue(__rcs.isSeqAssociated(),
250             "Annotation colourscheme wasn't sequence associated");
251
252     boolean diffseqcols = false, diffgseqcols = false;
253     SequenceI[] sqs = af.getViewport().getAlignment().getSequencesArray();
254     for (int p = 0, pSize = af.getViewport().getAlignment()
255             .getWidth(); p < pSize && (!diffseqcols || !diffgseqcols); p++)
256     {
257       if (_rcs.findColour(sqs[0].getCharAt(p), p, sqs[0], null, 0f) != _rcs
258               .findColour(sqs[5].getCharAt(p), p, sqs[5], null, 0f))
259       {
260         diffseqcols = true;
261       }
262     }
263     assertTrue(diffseqcols, "Got Different sequence colours");
264     System.out.println(
265             "Per sequence colourscheme (Background) successfully applied and recovered.");
266
267     assertNotNull(_rgcs, "Didn't recover group colourscheme");
268     assertTrue(_rgcs instanceof AnnotationColourGradient,
269             "Didn't recover annotation colour group colourscheme");
270     __rcs = (AnnotationColourGradient) _rgcs;
271     assertTrue(__rcs.isSeqAssociated(),
272             "Group Annotation colourscheme wasn't sequence associated");
273
274     for (int p = 0, pSize = af.getViewport().getAlignment()
275             .getWidth(); p < pSize && (!diffseqcols || !diffgseqcols); p++)
276     {
277       if (_rgcs.findColour(sqs[1].getCharAt(p), p, sqs[1], null,
278               0f) != _rgcs.findColour(sqs[2].getCharAt(p), p, sqs[2], null,
279                       0f))
280       {
281         diffgseqcols = true;
282       }
283     }
284     assertTrue(diffgseqcols, "Got Different group sequence colours");
285     System.out.println(
286             "Per sequence (Group) colourscheme successfully applied and recovered.");
287   }
288
289   @Test(groups = { "Functional" })
290   public void gatherViewsHere() throws Exception
291   {
292     int origCount = Desktop.getDesktopAlignFrames() == null ? 0
293             : Desktop.getDesktopAlignFrames().length;
294     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
295             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
296     assertNotNull(af, "Didn't read in the example file correctly.");
297     assertTrue(Desktop.getDesktopAlignFrames().length == 1 + origCount,
298             "Didn't gather the views in the example file.");
299
300   }
301
302   /**
303    * Test for JAL-2223 - multiple mappings in View Mapping report
304    * 
305    * @throws Exception
306    */
307   @Test(groups = { "Functional" })
308   public void noDuplicatePdbMappingsMade() throws Exception
309   {
310     StructureImportSettings.setProcessSecondaryStructure(true);
311     StructureImportSettings.setVisibleChainAnnotation(true);
312     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
313             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
314     assertNotNull(af, "Didn't read in the example file correctly.");
315
316     // locate Jmol viewer
317     // count number of PDB mappings the structure selection manager holds -
318     String pdbFile = af.getCurrentView().getStructureSelectionManager()
319             .findFileForPDBId("1A70");
320     assertEquals(
321             af.getCurrentView().getStructureSelectionManager()
322                     .getMapping(pdbFile).length,
323             2, "Expected only two mappings for 1A70");
324
325   }
326
327   @Test(groups = { "Functional" })
328   public void viewRefPdbAnnotation() throws Exception
329   {
330     StructureImportSettings.setProcessSecondaryStructure(true);
331     StructureImportSettings.setVisibleChainAnnotation(true);
332     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
333             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
334     assertNotNull(af, "Didn't read in the example file correctly.");
335     AlignmentViewPanel sps = null;
336     for (AlignmentViewPanel ap : af.alignPanel.alignFrame.getAlignPanels())
337     {
338       if ("Spinach Feredoxin Structure".equals(ap.getViewName()))
339       {
340         sps = ap;
341         break;
342       }
343     }
344     assertNotNull(sps, "Couldn't find the structure view");
345     AlignmentAnnotation refan = null;
346     for (AlignmentAnnotation ra : sps.getAlignment()
347             .getAlignmentAnnotation())
348     {
349       if (ra.graph != 0)
350       {
351         refan = ra;
352         break;
353       }
354     }
355     assertNotNull(refan, "Annotation secondary structure not found.");
356     SequenceI sq = sps.getAlignment().findName("1A70|");
357     assertNotNull(sq, "Couldn't find 1a70 null chain");
358     // compare the manually added temperature factor annotation
359     // to the track automatically transferred from the pdb structure on load
360     assertNotNull(sq.getDatasetSequence().getAnnotation(),
361             "1a70 has no annotation");
362     for (AlignmentAnnotation ala : sq.getDatasetSequence().getAnnotation())
363     {
364       AlignmentAnnotation alaa;
365       sq.addAlignmentAnnotation(alaa = new AlignmentAnnotation(ala));
366       alaa.adjustForAlignment();
367       if (ala.graph == refan.graph)
368       {
369         for (int p = 0; p < ala.annotations.length; p++)
370         {
371           sq.findPosition(p);
372           try
373           {
374             assertTrue((alaa.annotations[p] == null
375                     && refan.annotations[p] == null)
376                     || alaa.annotations[p].value == refan.annotations[p].value,
377                     "Mismatch at alignment position " + p);
378           } catch (NullPointerException q)
379           {
380             Assert.fail("Mismatch of alignment annotations at position " + p
381                     + " Ref seq ann: " + refan.annotations[p]
382                     + " alignment " + alaa.annotations[p]);
383           }
384         }
385       }
386     }
387
388   }
389
390   @Test(groups = { "Functional" })
391   public void testCopyViewSettings() throws Exception
392   {
393     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
394             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
395     assertNotNull(af, "Didn't read in the example file correctly.");
396     AlignmentViewPanel sps = null, groups = null;
397     for (AlignmentViewPanel ap : af.alignPanel.alignFrame.getAlignPanels())
398     {
399       if ("Spinach Feredoxin Structure".equals(ap.getViewName()))
400       {
401         sps = ap;
402       }
403       if (ap.getViewName().contains("MAFFT"))
404       {
405         groups = ap;
406       }
407     }
408     assertNotNull(sps, "Couldn't find the structure view");
409     assertNotNull(groups, "Couldn't find the MAFFT view");
410
411     ViewStyleI structureStyle = sps.getAlignViewport().getViewStyle();
412     ViewStyleI groupStyle = groups.getAlignViewport().getViewStyle();
413     AssertJUnit.assertFalse(structureStyle.sameStyle(groupStyle));
414
415     groups.getAlignViewport().setViewStyle(structureStyle);
416     AssertJUnit.assertFalse(
417             groupStyle.sameStyle(groups.getAlignViewport().getViewStyle()));
418     Assert.assertTrue(structureStyle
419             .sameStyle(groups.getAlignViewport().getViewStyle()));
420
421   }
422
423   /**
424    * test store and recovery of expanded views
425    * 
426    * @throws Exception
427    */
428   @Test(groups = { "Functional" }, enabled = true)
429   public void testStoreAndRecoverExpandedviews() throws Exception
430   {
431     Desktop.instance.closeAll_actionPerformed(null);
432
433     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
434             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
435     Assert.assertEquals(Desktop.getDesktopAlignFrames().length, 1);
436     String afid = af.getViewport().getSequenceSetId();
437
438     // check FileLoader returned a reference to the one alignFrame that is
439     // actually on the Desktop
440     assertSame(af, Desktop.getAlignFrameFor(af.getViewport()),
441             "Jalview2XML.loadAlignFrame() didn't return correct AlignFrame reference for multiple view window");
442
443     Desktop.explodeViews(af);
444
445     int oldviews = Desktop.getDesktopAlignFrames().length;
446     Assert.assertEquals(Desktop.getDesktopAlignFrames().length,
447             Desktop.getAlignmentPanels(afid).length);
448     File tfile = File.createTempFile("testStoreAndRecoverExpanded", ".jvp");
449     try
450     {
451       new Jalview2XML(false).saveState(tfile);
452     } catch (Error e)
453     {
454       Assert.fail("Didn't save the expanded view state", e);
455     } catch (Exception e)
456     {
457       Assert.fail("Didn't save the expanded view state", e);
458     }
459     Desktop.instance.closeAll_actionPerformed(null);
460     if (Desktop.getDesktopAlignFrames() != null)
461     {
462       Assert.assertEquals(Desktop.getDesktopAlignFrames().length, 0);
463     }
464     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
465             DataSourceType.FILE);
466     Assert.assertNotNull(af);
467     Assert.assertEquals(Desktop.getDesktopAlignFrames().length,
468             Desktop.getAlignmentPanels(
469                     af.getViewport().getSequenceSetId()).length);
470     Assert.assertEquals(Desktop
471             .getAlignmentPanels(af.getViewport().getSequenceSetId()).length,
472             oldviews);
473   }
474
475   /**
476    * Test save and reload of a project with a different representative sequence
477    * in each view.
478    * 
479    * @throws Exception
480    */
481   @Test(groups = { "Functional" })
482   public void testStoreAndRecoverReferenceSeqSettings() throws Exception
483   {
484     Desktop.instance.closeAll_actionPerformed(null);
485     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
486             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
487     assertNotNull(af, "Didn't read in the example file correctly.");
488     String afid = af.getViewport().getSequenceSetId();
489
490     // remember reference sequence for each panel
491     Map<String, SequenceI> refseqs = new HashMap<>();
492
493     /*
494      * mark sequence 2, 3, 4.. in panels 1, 2, 3...
495      * as reference sequence for itself and the preceding sequence
496      */
497     int n = 1;
498     for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
499     {
500       AlignViewportI av = ap.getAlignViewport();
501       AlignmentI alignment = ap.getAlignment();
502       int repIndex = n % alignment.getHeight();
503       SequenceI rep = alignment.getSequenceAt(repIndex);
504       refseqs.put(ap.getViewName(), rep);
505
506       // code from mark/unmark sequence as reference in jalview.gui.PopupMenu
507       // todo refactor this to an alignment view controller
508       av.setDisplayReferenceSeq(true);
509       av.setColourByReferenceSeq(true);
510       av.getAlignment().setSeqrep(rep);
511
512       n++;
513     }
514     File tfile = File.createTempFile("testStoreAndRecoverReferenceSeq",
515             ".jvp");
516     try
517     {
518       new Jalview2XML(false).saveState(tfile);
519     } catch (Throwable e)
520     {
521       Assert.fail("Didn't save the expanded view state", e);
522     }
523     Desktop.instance.closeAll_actionPerformed(null);
524     if (Desktop.getDesktopAlignFrames() != null)
525     {
526       Assert.assertEquals(Desktop.getDesktopAlignFrames().length, 0);
527     }
528
529     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
530             DataSourceType.FILE);
531     afid = af.getViewport().getSequenceSetId();
532
533     for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
534     {
535       // check representative
536       AlignmentI alignment = ap.getAlignment();
537       SequenceI rep = alignment.getSeqrep();
538       Assert.assertNotNull(rep,
539               "Couldn't restore sequence representative from project");
540       // can't use a strong equals here, because by definition, the sequence IDs
541       // will be different.
542       // could set vamsas session save/restore flag to preserve IDs across
543       // load/saves.
544       Assert.assertEquals(refseqs.get(ap.getViewName()).toString(),
545               rep.toString(),
546               "Representative wasn't the same when recovered.");
547       Assert.assertTrue(ap.getAlignViewport().isDisplayReferenceSeq(),
548               "Display reference sequence view setting not set.");
549       Assert.assertTrue(ap.getAlignViewport().isColourByReferenceSeq(),
550               "Colour By Reference Seq view setting not set.");
551     }
552   }
553
554   @Test(groups = { "Functional" })
555   public void testIsVersionStringLaterThan()
556   {
557     /*
558      * No version / development / test / autobuild is leniently assumed to be
559      * compatible
560      */
561     assertTrue(Jalview2XML.isVersionStringLaterThan(null, null));
562     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", null));
563     assertTrue(Jalview2XML.isVersionStringLaterThan(null, "2.8.3"));
564     assertTrue(Jalview2XML.isVersionStringLaterThan(null,
565             "Development Build"));
566     assertTrue(Jalview2XML.isVersionStringLaterThan(null,
567             "DEVELOPMENT BUILD"));
568     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3",
569             "Development Build"));
570     assertTrue(Jalview2XML.isVersionStringLaterThan(null, "Test"));
571     assertTrue(Jalview2XML.isVersionStringLaterThan(null, "TEST"));
572     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "Test"));
573     assertTrue(
574             Jalview2XML.isVersionStringLaterThan(null, "Automated Build"));
575     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3",
576             "Automated Build"));
577     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3",
578             "AUTOMATED BUILD"));
579
580     /*
581      * same version returns true i.e. compatible
582      */
583     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8", "2.8"));
584     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8.3"));
585     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3b1", "2.8.3b1"));
586     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3B1", "2.8.3b1"));
587     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3b1", "2.8.3B1"));
588
589     /*
590      * later version returns true
591      */
592     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8.4"));
593     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.9"));
594     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.9.2"));
595     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8", "2.8.3"));
596     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8.3b1"));
597
598     /*
599      * earlier version returns false
600      */
601     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8"));
602     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.4", "2.8.3"));
603     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.3b1", "2.8.3"));
604     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8.2b1"));
605     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.0b2", "2.8.0b1"));
606     /*
607      * test for patch release versions
608      */
609     assertFalse(Jalview2XML.isVersionStringLaterThan("2.11.3.0", "2.11.2"));
610     assertTrue(Jalview2XML.isVersionStringLaterThan("2.11.3.0", "2.11.4"));
611     assertFalse(
612             Jalview2XML.isVersionStringLaterThan("2.12.2.0b1", "2.12.2.0"));
613     assertFalse(
614             Jalview2XML.isVersionStringLaterThan("2.12.2.3", "2.12.2.2"));
615
616   }
617
618   /**
619    * Test save and reload of a project with a different sequence group (and
620    * representative sequence) in each view.
621    * 
622    * @throws Exception
623    */
624   @Test(groups = { "Functional" })
625   public void testStoreAndRecoverGroupRepSeqs() throws Exception
626   {
627     Desktop.instance.closeAll_actionPerformed(null);
628     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
629             "examples/uniref50.fa", DataSourceType.FILE);
630     assertNotNull(af, "Didn't read in the example file correctly.");
631     String afid = af.getViewport().getSequenceSetId();
632     // make a second view of the alignment
633     af.newView_actionPerformed(null);
634
635     /*
636      * remember representative and hidden sequences marked 
637      * on each panel
638      */
639     Map<String, SequenceI> repSeqs = new HashMap<>();
640     Map<String, List<String>> hiddenSeqNames = new HashMap<>();
641
642     /*
643      * mark sequence 2, 3, 4.. in panels 1, 2, 3...
644      * as reference sequence for itself and the preceding sequence
645      */
646     int n = 1;
647     for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
648     {
649       AlignViewportI av = ap.getAlignViewport();
650       AlignmentI alignment = ap.getAlignment();
651       int repIndex = n % alignment.getHeight();
652       // ensure at least one preceding sequence i.e. index >= 1
653       repIndex = Math.max(repIndex, 1);
654       SequenceI repSeq = alignment.getSequenceAt(repIndex);
655       repSeqs.put(ap.getViewName(), repSeq);
656       List<String> hiddenNames = new ArrayList<>();
657       hiddenSeqNames.put(ap.getViewName(), hiddenNames);
658
659       /*
660        * have rep sequence represent itself and the one before it
661        * this hides the group (except for the rep seq)
662        */
663       SequenceGroup sg = new SequenceGroup();
664       sg.addSequence(repSeq, false);
665       SequenceI precedingSeq = alignment.getSequenceAt(repIndex - 1);
666       sg.addSequence(precedingSeq, false);
667       sg.setSeqrep(repSeq);
668       assertTrue(sg.getSequences().contains(repSeq));
669       assertTrue(sg.getSequences().contains(precedingSeq));
670       av.setSelectionGroup(sg);
671       assertSame(repSeq, sg.getSeqrep());
672
673       /*
674        * represent group with sequence adds to a map of hidden rep sequences
675        * (it does not create a group on the alignment) 
676        */
677       ((AlignmentViewport) av).hideSequences(repSeq, true);
678       assertSame(repSeq, sg.getSeqrep());
679       assertTrue(sg.getSequences().contains(repSeq));
680       assertTrue(sg.getSequences().contains(precedingSeq));
681       assertTrue(alignment.getGroups().isEmpty(), "alignment has groups");
682       Map<SequenceI, SequenceCollectionI> hiddenRepSeqsMap = av
683               .getHiddenRepSequences();
684       assertNotNull(hiddenRepSeqsMap);
685       assertEquals(1, hiddenRepSeqsMap.size());
686       assertSame(sg, hiddenRepSeqsMap.get(repSeq));
687       assertTrue(alignment.getHiddenSequences().isHidden(precedingSeq));
688       assertFalse(alignment.getHiddenSequences().isHidden(repSeq));
689       hiddenNames.add(precedingSeq.getName());
690
691       n++;
692     }
693     File tfile = File.createTempFile("testStoreAndRecoverGroupReps",
694             ".jvp");
695     try
696     {
697       new Jalview2XML(false).saveState(tfile);
698     } catch (Throwable e)
699     {
700       Assert.fail("Didn't save the expanded view state", e);
701     }
702     Desktop.instance.closeAll_actionPerformed(null);
703     if (Desktop.getDesktopAlignFrames() != null)
704     {
705       Assert.assertEquals(Desktop.getDesktopAlignFrames().length, 0);
706     }
707
708     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
709             DataSourceType.FILE);
710     afid = af.getViewport().getSequenceSetId();
711
712     for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
713     {
714       String viewName = ap.getViewName();
715       AlignViewportI av = ap.getAlignViewport();
716       AlignmentI alignment = ap.getAlignment();
717       List<SequenceGroup> groups = alignment.getGroups();
718       assertNotNull(groups);
719       assertTrue(groups.isEmpty(), "Alignment has groups");
720       Map<SequenceI, SequenceCollectionI> hiddenRepSeqsMap = av
721               .getHiddenRepSequences();
722       assertNotNull(hiddenRepSeqsMap, "No hidden represented sequences");
723       assertEquals(1, hiddenRepSeqsMap.size());
724       assertEquals(repSeqs.get(viewName).getDisplayId(true),
725               hiddenRepSeqsMap.keySet().iterator().next()
726                       .getDisplayId(true));
727
728       /*
729        * verify hidden sequences in restored panel
730        */
731       List<String> hidden = hiddenSeqNames.get(ap.getViewName());
732       HiddenSequences hs = alignment.getHiddenSequences();
733       assertEquals(hidden.size(), hs.getSize(),
734               "wrong number of restored hidden sequences in "
735                       + ap.getViewName());
736     }
737   }
738
739   /**
740    * Test save and reload of PDBEntry in Jalview project
741    * 
742    * @throws Exception
743    */
744   @Test(groups = { "Functional" })
745   public void testStoreAndRecoverPDBEntry() throws Exception
746   {
747     Desktop.instance.closeAll_actionPerformed(null);
748     String exampleFile = "examples/3W5V.pdb";
749     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(exampleFile,
750             DataSourceType.FILE);
751     assertNotNull(af, "Didn't read in the example file correctly.");
752     String afid = af.getViewport().getSequenceSetId();
753
754     AlignmentPanel[] alignPanels = Desktop.getAlignmentPanels(afid);
755     System.out.println();
756     AlignmentViewPanel ap = alignPanels[0];
757     String tfileBase = new File(".").getAbsolutePath().replace(".", "");
758     String testFile = tfileBase + exampleFile;
759     AlignmentI alignment = ap.getAlignment();
760     System.out.println("blah");
761     SequenceI[] seqs = alignment.getSequencesArray();
762     Assert.assertNotNull(seqs[0]);
763     Assert.assertNotNull(seqs[1]);
764     Assert.assertNotNull(seqs[2]);
765     Assert.assertNotNull(seqs[3]);
766     Assert.assertNotNull(seqs[0].getDatasetSequence());
767     Assert.assertNotNull(seqs[1].getDatasetSequence());
768     Assert.assertNotNull(seqs[2].getDatasetSequence());
769     Assert.assertNotNull(seqs[3].getDatasetSequence());
770     PDBEntry[] pdbEntries = new PDBEntry[4];
771     pdbEntries[0] = new PDBEntry("3W5V", "A", Type.PDB, testFile);
772     pdbEntries[1] = new PDBEntry("3W5V", "B", Type.PDB, testFile);
773     pdbEntries[2] = new PDBEntry("3W5V", "C", Type.PDB, testFile);
774     pdbEntries[3] = new PDBEntry("3W5V", "D", Type.PDB, testFile);
775     Assert.assertEquals(
776             seqs[0].getDatasetSequence().getAllPDBEntries().get(0),
777             pdbEntries[0]);
778     Assert.assertEquals(
779             seqs[1].getDatasetSequence().getAllPDBEntries().get(0),
780             pdbEntries[1]);
781     Assert.assertEquals(
782             seqs[2].getDatasetSequence().getAllPDBEntries().get(0),
783             pdbEntries[2]);
784     Assert.assertEquals(
785             seqs[3].getDatasetSequence().getAllPDBEntries().get(0),
786             pdbEntries[3]);
787
788     File tfile = File.createTempFile("testStoreAndRecoverPDBEntry", ".jvp");
789     try
790     {
791       new Jalview2XML(false).saveState(tfile);
792     } catch (Throwable e)
793     {
794       Assert.fail("Didn't save the state", e);
795     }
796     Desktop.instance.closeAll_actionPerformed(null);
797     if (Desktop.getDesktopAlignFrames() != null)
798     {
799       Assert.assertEquals(Desktop.getDesktopAlignFrames().length, 0);
800     }
801
802     AlignFrame restoredFrame = new FileLoader().LoadFileWaitTillLoaded(
803             tfile.getAbsolutePath(), DataSourceType.FILE);
804     String rfid = restoredFrame.getViewport().getSequenceSetId();
805     AlignmentPanel[] rAlignPanels = Desktop.getAlignmentPanels(rfid);
806     AlignmentViewPanel rap = rAlignPanels[0];
807     AlignmentI rAlignment = rap.getAlignment();
808     System.out.println("blah");
809     SequenceI[] rseqs = rAlignment.getSequencesArray();
810     Assert.assertNotNull(rseqs[0]);
811     Assert.assertNotNull(rseqs[1]);
812     Assert.assertNotNull(rseqs[2]);
813     Assert.assertNotNull(rseqs[3]);
814     Assert.assertNotNull(rseqs[0].getDatasetSequence());
815     Assert.assertNotNull(rseqs[1].getDatasetSequence());
816     Assert.assertNotNull(rseqs[2].getDatasetSequence());
817     Assert.assertNotNull(rseqs[3].getDatasetSequence());
818
819     // The Asserts below are expected to fail until the PDB chainCode is
820     // recoverable from a Jalview projects
821     for (int chain = 0; chain < 4; chain++)
822     {
823       PDBEntry recov = rseqs[chain].getDatasetSequence().getAllPDBEntries()
824               .get(0);
825       PDBEntry expected = pdbEntries[chain];
826       Assert.assertEquals(recov.getId(), expected.getId(),
827               "Mismatch PDB ID");
828       Assert.assertEquals(recov.getChainCode(), expected.getChainCode(),
829               "Mismatch PDB ID");
830       Assert.assertEquals(recov.getType(), expected.getType(),
831               "Mismatch PDBEntry 'Type'");
832       Assert.assertNotNull(recov.getFile(),
833               "Recovered PDBEntry should have a non-null file entry");
834       Assert.assertEquals(
835               recov.getFile().toLowerCase(Locale.ENGLISH)
836                       .lastIndexOf("pdb"),
837               recov.getFile().length() - 3,
838               "Recovered PDBEntry file should have PDB suffix");
839     }
840   }
841
842   /**
843    * Configure an alignment and a sub-group each with distinct colour schemes,
844    * Conservation and PID thresholds, and confirm these are restored from the
845    * saved project.
846    * 
847    * @throws IOException
848    */
849   @Test(groups = { "Functional" })
850   public void testStoreAndRecoverAnnotationRowElementColours()
851           throws IOException
852   {
853     Desktop.instance.closeAll_actionPerformed(null);
854     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded("SEQ\tMNQ",
855             DataSourceType.PASTE);
856
857     AlignViewport av = af.getViewport();
858     AlignmentI al = av.getAlignment();
859     SequenceI fsq;
860     fsq = al.getSequenceAt(0);
861     Annotation annots[] = new Annotation[fsq.getLength()];
862     AlignmentAnnotation ala = new AlignmentAnnotation("Colour", "Annots",
863             annots);
864     annots[0] = new Annotation(1.0f);
865     annots[1] = new Annotation(2.0f);
866     annots[2] = new Annotation(3.0f);
867     annots[0].colour = Color.RED;
868     annots[1].colour = Color.GREEN;
869     annots[2].colour = Color.BLUE;
870     ala.validateRangeAndDisplay();
871     al.getSequenceAt(0).addAlignmentAnnotation(ala);
872     al.addAnnotation(ala);
873     /*
874      * and colour by annotation
875      */
876     AnnotationColourGradient acg = new AnnotationColourGradient(ala,
877             af.alignPanel.av.getGlobalColourScheme(), 0);
878     acg.setSeqAssociated(true);
879     acg.setPredefinedColours(true);
880     af.changeColour(acg);
881     Color seqcol[] = new Color[3];
882     for (int iStart = fsq.findIndex(fsq.getStart()), i = 0; i < 3; i++)
883     {
884       seqcol[i] = af.alignPanel.getSeqPanel().seqCanvas
885               .getSequenceRenderer()
886               .getResidueColour(fsq, iStart + i, null);
887     }
888     /*
889      * save project, close windows, reload project, verify
890      */
891     File tfile = File.createTempFile(
892             "testStoreAndRecoverAnnotRowElemColors", ".jvp");
893     tfile.deleteOnExit();
894     new Jalview2XML(false).saveState(tfile);
895     // Desktop.instance.closeAll_actionPerformed(null);
896     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
897             DataSourceType.FILE);
898     Assert.assertNotNull(af, "Failed to reload project");
899     /*
900      * verify alignment annotation has colors
901      */
902     av = af.getViewport();
903
904     ColourSchemeI loadedCscheme = av.getGlobalColourScheme();
905     Assert.assertTrue(loadedCscheme instanceof AnnotationColourGradient,
906             "Didn't apply Annotation colour gradient");
907     acg = (AnnotationColourGradient) loadedCscheme;
908     assertTrue(acg.isSeqAssociated());
909     assertTrue(acg.isPredefinedColours());
910
911     al = av.getAlignment();
912     fsq = al.getSequenceAt(0);
913     ala = fsq.getAnnotation()[0];
914     Assert.assertNotNull(ala, "No annotation row recovered");
915     Assert.assertNotNull(ala.annotations);
916     for (int iStart = al.getSequenceAt(0)
917             .findIndex(al.getSequenceAt(0).getStart()), i = 0; i < 3; i++)
918     {
919       Assert.assertTrue(ala.annotations[i].colour != null);
920       Assert.assertTrue(ala.annotations[i].colour.equals(annots[i].colour));
921       Color newseqcol = af.alignPanel.getSeqPanel().seqCanvas
922               .getSequenceRenderer()
923               .getResidueColour(fsq, iStart + i, null);
924       Assert.assertTrue(seqcol[i].equals(newseqcol),
925               "Sequence shading is different");
926
927     }
928
929   }
930
931   /**
932    * Configure an alignment and a sub-group each with distinct colour schemes,
933    * Conservation and PID thresholds, and confirm these are restored from the
934    * saved project.
935    * 
936    * @throws IOException
937    */
938   @Test(groups = { "Functional" })
939   public void testStoreAndRecoverColourThresholds() throws IOException
940   {
941     Desktop.instance.closeAll_actionPerformed(null);
942     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
943             "examples/uniref50.fa", DataSourceType.FILE);
944
945     AlignViewport av = af.getViewport();
946     AlignmentI al = av.getAlignment();
947
948     /*
949      * Colour alignment by Buried Index, Above 10% PID, By Conservation 20%
950      */
951     av.setColourAppliesToAllGroups(false);
952     af.changeColour_actionPerformed(JalviewColourScheme.Buried.toString());
953     assertTrue(av.getGlobalColourScheme() instanceof BuriedColourScheme);
954     af.abovePIDThreshold_actionPerformed(true);
955     SliderPanel sp = SliderPanel.getSliderPanel();
956     assertFalse(sp.isForConservation());
957     sp.valueChanged(10);
958     af.conservationMenuItem_actionPerformed(true);
959     sp = SliderPanel.getSliderPanel();
960     assertTrue(sp.isForConservation());
961     sp.valueChanged(20);
962     ResidueShaderI rs = av.getResidueShading();
963     assertEquals(rs.getThreshold(), 10);
964     assertTrue(rs.conservationApplied());
965     assertEquals(rs.getConservationInc(), 20);
966
967     /*
968      * create a group with Strand colouring, 30% Conservation
969      * and 40% PID threshold
970      * (notice menu action applies to selection group even if mouse click
971      * is at a sequence not in the group)
972      */
973     SequenceGroup sg = new SequenceGroup();
974     sg.addSequence(al.getSequenceAt(0), false);
975     sg.setStartRes(15);
976     sg.setEndRes(25);
977     av.setSelectionGroup(sg);
978     PopupMenu popupMenu = new PopupMenu(af.alignPanel, al.getSequenceAt(2),
979             null);
980     popupMenu.changeColour_actionPerformed(
981             JalviewColourScheme.Strand.toString());
982     assertTrue(sg.getColourScheme() instanceof StrandColourScheme);
983     assertEquals(al.getGroups().size(), 1);
984     assertSame(al.getGroups().get(0), sg);
985     popupMenu.conservationMenuItem_actionPerformed(true);
986     sp = SliderPanel.getSliderPanel();
987     assertTrue(sp.isForConservation());
988     sp.valueChanged(30);
989     popupMenu.abovePIDColour_actionPerformed(true);
990     sp = SliderPanel.getSliderPanel();
991     assertFalse(sp.isForConservation());
992     sp.valueChanged(40);
993     assertTrue(sg.getGroupColourScheme().conservationApplied());
994     assertEquals(sg.getGroupColourScheme().getConservationInc(), 30);
995     assertEquals(sg.getGroupColourScheme().getThreshold(), 40);
996
997     /*
998      * save project, close windows, reload project, verify
999      */
1000     File tfile = File.createTempFile("testStoreAndRecoverColourThresholds",
1001             ".jvp");
1002     tfile.deleteOnExit();
1003     new Jalview2XML(false).saveState(tfile);
1004     Desktop.instance.closeAll_actionPerformed(null);
1005     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
1006             DataSourceType.FILE);
1007     Assert.assertNotNull(af, "Failed to reload project");
1008
1009     /*
1010      * verify alignment (background) colouring
1011      */
1012     rs = af.getViewport().getResidueShading();
1013     assertTrue(rs.getColourScheme() instanceof BuriedColourScheme);
1014     assertEquals(rs.getThreshold(), 10);
1015     assertTrue(rs.conservationApplied());
1016     assertEquals(rs.getConservationInc(), 20);
1017
1018     /*
1019      * verify group colouring
1020      */
1021     assertEquals(1, af.getViewport().getAlignment().getGroups().size(), 1);
1022     rs = af.getViewport().getAlignment().getGroups().get(0)
1023             .getGroupColourScheme();
1024     assertTrue(rs.getColourScheme() instanceof StrandColourScheme);
1025     assertEquals(rs.getThreshold(), 40);
1026     assertTrue(rs.conservationApplied());
1027     assertEquals(rs.getConservationInc(), 30);
1028   }
1029
1030   /**
1031    * Test save and reload of feature colour schemes and filter settings
1032    * 
1033    * @throws IOException
1034    */
1035   @Test(groups = { "Functional" })
1036   public void testSaveLoadFeatureColoursAndFilters() throws IOException
1037   {
1038     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1039             ">Seq1\nACDEFGHIKLM", DataSourceType.PASTE);
1040     SequenceI seq1 = af.getViewport().getAlignment().getSequenceAt(0);
1041
1042     /*
1043      * add some features to the sequence
1044      */
1045     int score = 1;
1046     addFeatures(seq1, "type1", score++);
1047     addFeatures(seq1, "type2", score++);
1048     addFeatures(seq1, "type3", score++);
1049     addFeatures(seq1, "type4", score++);
1050     addFeatures(seq1, "type5", score++);
1051
1052     /*
1053      * set colour schemes for features
1054      */
1055     FeatureRendererModel fr = af.getFeatureRenderer();
1056     fr.findAllFeatures(true);
1057
1058     // type1: red
1059     fr.setColour("type1", new FeatureColour(Color.red));
1060
1061     // type2: by label
1062     FeatureColourI byLabel = new FeatureColour();
1063     byLabel.setColourByLabel(true);
1064     fr.setColour("type2", byLabel);
1065
1066     // type3: by score above threshold
1067     FeatureColourI byScore = new FeatureColour(null, Color.BLACK,
1068             Color.BLUE, null, 1, 10);
1069     byScore.setAboveThreshold(true);
1070     byScore.setThreshold(2f);
1071     fr.setColour("type3", byScore);
1072
1073     // type4: by attribute AF
1074     FeatureColourI byAF = new FeatureColour();
1075     byAF.setColourByLabel(true);
1076     byAF.setAttributeName("AF");
1077     fr.setColour("type4", byAF);
1078
1079     // type5: by attribute CSQ:PolyPhen below threshold
1080     FeatureColourI byPolyPhen = new FeatureColour(null, Color.BLACK,
1081             Color.BLUE, null, 1, 10);
1082     byPolyPhen.setBelowThreshold(true);
1083     byPolyPhen.setThreshold(3f);
1084     byPolyPhen.setAttributeName("CSQ", "PolyPhen");
1085     fr.setColour("type5", byPolyPhen);
1086
1087     /*
1088      * set filters for feature types
1089      */
1090
1091     // filter type1 features by (label contains "x")
1092     FeatureMatcherSetI filterByX = new FeatureMatcherSet();
1093     filterByX.and(FeatureMatcher.byLabel(Condition.Contains, "x"));
1094     fr.setFeatureFilter("type1", filterByX);
1095
1096     // filter type2 features by (score <= 2.4 and score > 1.1)
1097     FeatureMatcherSetI filterByScore = new FeatureMatcherSet();
1098     filterByScore.and(FeatureMatcher.byScore(Condition.LE, "2.4"));
1099     filterByScore.and(FeatureMatcher.byScore(Condition.GT, "1.1"));
1100     fr.setFeatureFilter("type2", filterByScore);
1101
1102     // filter type3 features by (AF contains X OR CSQ:PolyPhen != 0)
1103     FeatureMatcherSetI filterByXY = new FeatureMatcherSet();
1104     filterByXY
1105             .and(FeatureMatcher.byAttribute(Condition.Contains, "X", "AF"));
1106     filterByXY.or(FeatureMatcher.byAttribute(Condition.NE, "0", "CSQ",
1107             "PolyPhen"));
1108     fr.setFeatureFilter("type3", filterByXY);
1109
1110     /*
1111      * save as Jalview project
1112      */
1113     File tfile = File.createTempFile("JalviewTest", ".jvp");
1114     tfile.deleteOnExit();
1115     String filePath = tfile.getAbsolutePath();
1116     af.saveAlignment(filePath, FileFormat.Jalview);
1117     assertTrue(af.isSaveAlignmentSuccessful(),
1118             "Failed to store as a project.");
1119
1120     /*
1121      * close current alignment and load the saved project
1122      */
1123     af.closeMenuItem_actionPerformed(true);
1124     af = null;
1125     af = new FileLoader().LoadFileWaitTillLoaded(filePath,
1126             DataSourceType.FILE);
1127     assertNotNull(af, "Failed to import new project");
1128
1129     /*
1130      * verify restored feature colour schemes and filters
1131      */
1132     fr = af.getFeatureRenderer();
1133     FeatureColourI fc = fr.getFeatureStyle("type1");
1134     assertTrue(fc.isSimpleColour());
1135     assertEquals(fc.getColour(), Color.red);
1136     fc = fr.getFeatureStyle("type2");
1137     assertTrue(fc.isColourByLabel());
1138     fc = fr.getFeatureStyle("type3");
1139     assertTrue(fc.isGraduatedColour());
1140     assertNull(fc.getAttributeName());
1141     assertTrue(fc.isAboveThreshold());
1142     assertEquals(fc.getThreshold(), 2f);
1143     fc = fr.getFeatureStyle("type4");
1144     assertTrue(fc.isColourByLabel());
1145     assertTrue(fc.isColourByAttribute());
1146     assertEquals(fc.getAttributeName(), new String[] { "AF" });
1147     fc = fr.getFeatureStyle("type5");
1148     assertTrue(fc.isGraduatedColour());
1149     assertTrue(fc.isColourByAttribute());
1150     assertEquals(fc.getAttributeName(), new String[] { "CSQ", "PolyPhen" });
1151     assertTrue(fc.isBelowThreshold());
1152     assertEquals(fc.getThreshold(), 3f);
1153
1154     assertEquals(fr.getFeatureFilter("type1").toStableString(),
1155             "Label Contains x");
1156     assertEquals(fr.getFeatureFilter("type2").toStableString(),
1157             "(Score LE 2.4) AND (Score GT 1.1)");
1158     assertEquals(fr.getFeatureFilter("type3").toStableString(),
1159             "(AF Contains X) OR (CSQ:PolyPhen NE 0)");
1160   }
1161
1162   private void addFeature(SequenceI seq, String featureType, int score)
1163   {
1164     SequenceFeature sf = new SequenceFeature(featureType, "desc", 1, 2,
1165             score, "grp");
1166     sf.setValue("AF", score);
1167     sf.setValue("CSQ", new HashMap<String, String>()
1168     {
1169       {
1170         put("PolyPhen", Integer.toString(score));
1171       }
1172     });
1173     seq.addSequenceFeature(sf);
1174   }
1175
1176   /**
1177    * Adds two features of the given type to the given sequence, also setting the
1178    * score as the value of attribute "AF" and sub-attribute "CSQ:PolyPhen"
1179    * 
1180    * @param seq
1181    * @param featureType
1182    * @param score
1183    */
1184   private void addFeatures(SequenceI seq, String featureType, int score)
1185   {
1186     addFeature(seq, featureType, score++);
1187     addFeature(seq, featureType, score);
1188   }
1189
1190   /**
1191    * pre 2.11 - jalview 2.10 erroneously created new dataset entries for each
1192    * view (JAL-3171) this test ensures we can import and merge those views
1193    */
1194   @Test(groups = { "Functional" })
1195   public void testMergeDatasetsforViews() throws IOException
1196   {
1197     // simple project - two views on one alignment
1198     AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded(
1199             "examples/testdata/projects/twoViews.jvp", DataSourceType.FILE);
1200     assertNotNull(af);
1201     assertTrue(af.getAlignPanels().size() > 1);
1202     verifyDs(af);
1203   }
1204
1205   /**
1206    * pre 2.11 - jalview 2.10 erroneously created new dataset entries for each
1207    * view (JAL-3171) this test ensures we can import and merge those views This
1208    * is a more complex project
1209    */
1210   @Test(groups = { "Functional" })
1211   public void testMergeDatasetsforManyViews() throws IOException
1212   {
1213     Desktop.instance.closeAll_actionPerformed(null);
1214
1215     // complex project - one dataset, several views on several alignments
1216     AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded(
1217             "examples/testdata/projects/manyViews.jvp",
1218             DataSourceType.FILE);
1219     assertNotNull(af);
1220
1221     AlignmentI ds = null;
1222     for (AlignFrame alignFrame : Desktop.getDesktopAlignFrames())
1223     {
1224       if (ds == null)
1225       {
1226         ds = verifyDs(alignFrame);
1227       }
1228       else
1229       {
1230         // check that this frame's dataset matches the last
1231         assertTrue(ds == verifyDs(alignFrame));
1232       }
1233     }
1234   }
1235
1236   private AlignmentI verifyDs(AlignFrame af)
1237   {
1238     AlignmentI ds = null;
1239     for (AlignmentViewPanel ap : af.getAlignPanels())
1240     {
1241       if (ds == null)
1242       {
1243         ds = ap.getAlignment().getDataset();
1244       }
1245       else
1246       {
1247         assertTrue(ap.getAlignment().getDataset() == ds,
1248                 "Dataset was not the same for imported 2.10.5 project with several alignment views");
1249       }
1250     }
1251     return ds;
1252   }
1253
1254   @Test(groups = "Functional")
1255   public void testPcaViewAssociation() throws IOException
1256   {
1257     Desktop.instance.closeAll_actionPerformed(null);
1258     final String PCAVIEWNAME = "With PCA";
1259     // create a new tempfile
1260     File tempfile = File.createTempFile("jvPCAviewAssoc", "jvp");
1261
1262     {
1263       String exampleFile = "examples/uniref50.fa";
1264       AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(exampleFile,
1265               DataSourceType.FILE);
1266       assertNotNull(af, "Didn't read in the example file correctly.");
1267       AlignmentPanel origView = (AlignmentPanel) af.getAlignPanels().get(0);
1268       AlignmentPanel newview = af.newView(PCAVIEWNAME, true);
1269       // create another for good measure
1270       af.newView("Not the PCA View", true);
1271       PCAPanel pcaPanel = new PCAPanel(origView, "BLOSUM62",
1272               new SimilarityParams(true, true, true, false));
1273       // we're in the test exec thread, so we can just run synchronously here
1274       pcaPanel.run();
1275
1276       // now switch the linked view
1277       pcaPanel.selectAssociatedView(newview);
1278
1279       assertTrue(pcaPanel.getAlignViewport() == newview.getAlignViewport(),
1280               "PCA should be associated with 'With PCA' view: test is broken");
1281
1282       // now save and reload project
1283       Jalview2XML jv2xml = new jalview.project.Jalview2XML(false);
1284       tempfile.delete();
1285       jv2xml.saveState(tempfile);
1286       assertTrue(jv2xml.errorMessage == null,
1287               "Failed to save dummy project with PCA: test broken");
1288     }
1289
1290     // load again.
1291     Desktop.instance.closeAll_actionPerformed(null);
1292     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1293             tempfile.getCanonicalPath(), DataSourceType.FILE);
1294     JInternalFrame[] frames = Desktop.instance.getAllFrames();
1295     // PCA and the tabbed alignment view should be the only two windows on the
1296     // desktop
1297     assertEquals(frames.length, 2,
1298             "PCA and the tabbed alignment view should be the only two windows on the desktop");
1299     PCAPanel pcaPanel = (PCAPanel) frames[frames[0] == af ? 1 : 0];
1300
1301     AlignmentViewPanel restoredNewView = null;
1302     for (AlignmentViewPanel alignpanel : Desktop.getAlignmentPanels(null))
1303     {
1304       if (alignpanel.getAlignViewport() == pcaPanel.getAlignViewport())
1305       {
1306         restoredNewView = alignpanel;
1307       }
1308     }
1309     assertEquals(restoredNewView.getViewName(), PCAVIEWNAME);
1310     assertTrue(
1311             restoredNewView.getAlignViewport() == pcaPanel
1312                     .getAlignViewport(),
1313             "Didn't restore correct view association for the PCA view");
1314   }
1315
1316   /**
1317    * Test save and reload of DBRefEntry including GeneLocus in project
1318    * 
1319    * @throws Exception
1320    */
1321   @Test(groups = { "Functional" })
1322   public void testStoreAndRecoverGeneLocus() throws Exception
1323   {
1324     Desktop.instance.closeAll_actionPerformed(null);
1325     String seqData = ">P30419\nACDE\n>X1235\nGCCTGTGACGAA";
1326     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
1327             DataSourceType.PASTE);
1328     assertNotNull(af, "Didn't read in the example file correctly.");
1329
1330     AlignmentViewPanel ap = Desktop.getAlignmentPanels(null)[0];
1331     SequenceI pep = ap.getAlignment().getSequenceAt(0);
1332     SequenceI cds = ap.getAlignment().getSequenceAt(1);
1333
1334     /*
1335      * give 'protein' a dbref to self, a dbref with map to CDS,
1336      * and a dbref with map to gene 'locus'
1337      */
1338     DBRefEntry dbref1 = new DBRefEntry("Uniprot", "1", "P30419", null);
1339     pep.addDBRef(dbref1);
1340     Mapping cdsmap = new Mapping(cds,
1341             new MapList(new int[]
1342             { 1, 4 }, new int[] { 1, 12 }, 1, 3));
1343     DBRefEntry dbref2 = new DBRefEntry("EMBLCDS", "2", "X1235", cdsmap);
1344     pep.addDBRef(dbref2);
1345     Mapping locusmap = new Mapping(null,
1346             new MapList(new int[]
1347             { 1, 4 }, new int[] { 2674123, 2674135 }, 1, 3));
1348     DBRefEntry dbref3 = new GeneLocus("human", "GRCh38", "5", locusmap);
1349     pep.addDBRef(dbref3);
1350
1351     File tfile = File.createTempFile("testStoreAndRecoverGeneLocus",
1352             ".jvp");
1353     try
1354     {
1355       new Jalview2XML(false).saveState(tfile);
1356     } catch (Throwable e)
1357     {
1358       Assert.fail("Didn't save the state", e);
1359     }
1360     Desktop.instance.closeAll_actionPerformed(null);
1361
1362     new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
1363             DataSourceType.FILE);
1364     AlignmentViewPanel rap = Desktop.getAlignmentPanels(null)[0];
1365     SequenceI rpep = rap.getAlignment().getSequenceAt(0);
1366     DBModList<DBRefEntry> dbrefs = rpep.getDBRefs();
1367     assertEquals(rpep.getName(), "P30419");
1368     assertEquals(dbrefs.size(), 3);
1369     DBRefEntry dbRef = dbrefs.get(0);
1370     assertFalse(dbRef instanceof GeneLocus);
1371     assertNull(dbRef.getMap());
1372     assertEquals(dbRef, dbref1);
1373
1374     /*
1375      * restored dbrefs with mapping have a different 'map to'
1376      * sequence but otherwise match the original dbrefs
1377      */
1378     dbRef = dbrefs.get(1);
1379     assertFalse(dbRef instanceof GeneLocus);
1380     assertTrue(dbRef.equalRef(dbref2));
1381     assertNotNull(dbRef.getMap());
1382     SequenceI rcds = rap.getAlignment().getSequenceAt(1);
1383     assertSame(dbRef.getMap().getTo(), rcds);
1384     // compare MapList but not map.to
1385     assertEquals(dbRef.getMap().getMap(), dbref2.getMap().getMap());
1386
1387     /*
1388      * GeneLocus map.to is null so can compare Mapping objects
1389      */
1390     dbRef = dbrefs.get(2);
1391     assertTrue(dbRef instanceof GeneLocus);
1392     assertEquals(dbRef, dbref3);
1393   }
1394
1395   /**
1396    * test store and recovery of Overview windows
1397    * 
1398    * @throws Exception
1399    */
1400   @Test(groups = { "Functional" }, enabled = true)
1401   public void testStoreAndRecoverOverview() throws Exception
1402   {
1403     Desktop.instance.closeAll_actionPerformed(null);
1404
1405     Cache.setProperty("SHOW_OVERVIEW", "false");
1406     Cache.setProperty(Preferences.USE_LEGACY_GAP, "false");
1407     Cache.setColourProperty(Preferences.GAP_COLOUR, Color.green);
1408     Cache.setColourProperty(Preferences.HIDDEN_COLOUR, Color.yellow);
1409     Cache.setProperty(Preferences.SHOW_OV_HIDDEN_AT_START, "true");
1410
1411     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1412             "examples/uniref50.fa", DataSourceType.FILE);
1413
1414     /*
1415      * open and resize / reposition overview 
1416      */
1417     af.overviewMenuItem_actionPerformed(null);
1418     OverviewPanel ov1 = af.alignPanel.getOverviewPanel();
1419     assertNotNull(ov1);
1420     ov1.setFrameBounds(20, 30, 200, 400);
1421     assertEquals(ov1.getTitle(), "Overview examples/uniref50.fa");
1422     assertTrue(ov1.isShowHiddenRegions());
1423
1424     /*
1425      * open a New View and its Overview and reposition it
1426      */
1427     af.newView_actionPerformed(null);
1428     af.overviewMenuItem_actionPerformed(null);
1429     OverviewPanel ov2 = af.alignPanel.getOverviewPanel();
1430     assertNotNull(ov2);
1431     assertNotSame(ov1, ov2);
1432     ov2.setFrameBounds(25, 35, 205, 405);
1433     assertEquals(ov1.getTitle(), "Overview examples/uniref50.fa Original");
1434     assertEquals(ov2.getTitle(), "Overview examples/uniref50.fa View 1");
1435
1436     File tfile = File.createTempFile("testStoreAndRecoverOverview", ".jvp");
1437     new Jalview2XML(false).saveState(tfile);
1438     Desktop.instance.closeAll_actionPerformed(null);
1439
1440     /*
1441      * change preferences (should _not_ affect reloaded Overviews)
1442      */
1443     Cache.setProperty("SHOW_OVERVIEW", "true");
1444     Cache.setProperty(Preferences.USE_LEGACY_GAP, "true");
1445     Cache.setColourProperty(Preferences.GAP_COLOUR, Color.blue);
1446     Cache.setColourProperty(Preferences.HIDDEN_COLOUR, Color.orange);
1447     Cache.setProperty(Preferences.SHOW_OV_HIDDEN_AT_START, "false");
1448
1449     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
1450             DataSourceType.FILE);
1451
1452     /*
1453      * workaround: explicitly select View 1 (not in focus after restore)
1454      */
1455     af.tabSelectionChanged(1);
1456
1457     /*
1458      * verify restored overview for View 1
1459      */
1460     ov2 = af.alignPanel.getOverviewPanel();
1461     assertEquals(ov2.getCanvas().getGapColour(), Color.green);
1462     // 'non-legacy' colouring uses white for non-gapped residues
1463     assertEquals(ov2.getCanvas().getResidueColour(), Color.white);
1464     assertEquals(ov2.getCanvas().getHiddenColour(), Color.yellow);
1465     assertEquals(ov2.getTitle(), "Overview examples/uniref50.fa View 1");
1466     assertEquals(ov2.getFrameBounds(), new Rectangle(25, 35, 205, 405));
1467     assertTrue(ov2.isShowHiddenRegions());
1468
1469     /*
1470      * verify restored overview for Original view
1471      */
1472     af.tabSelectionChanged(0);
1473     ov1 = af.alignPanel.getOverviewPanel();
1474     assertEquals(ov1.getCanvas().getGapColour(), Color.green);
1475     // 'non-legacy' colouring uses white for non-gapped residues
1476     assertEquals(ov1.getCanvas().getResidueColour(), Color.white);
1477     assertEquals(ov1.getCanvas().getHiddenColour(), Color.yellow);
1478     assertEquals(ov1.getTitle(), "Overview examples/uniref50.fa Original");
1479     assertEquals(ov1.getFrameBounds(), new Rectangle(20, 30, 200, 400));
1480     assertTrue(ov1.isShowHiddenRegions());
1481   }
1482
1483   /**
1484    * Test that a view with no Overview is restored with no Overview, even if
1485    * 'Open Overview' is selected in Preferences
1486    * 
1487    * @throws Exception
1488    */
1489   @Test(groups = { "Functional" }, enabled = true)
1490   public void testStoreAndRecoverNoOverview() throws Exception
1491   {
1492     Cache.setProperty("SHOW_OVERVIEW", "false");
1493     Desktop.instance.closeAll_actionPerformed(null);
1494     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1495             ">seq1\nMATRSQFLVNF\n", DataSourceType.PASTE);
1496
1497     File tfile = File.createTempFile("testStoreAndRecoverOverview", ".jvp");
1498     new Jalview2XML(false).saveState(tfile);
1499     Desktop.instance.closeAll_actionPerformed(null);
1500
1501     Cache.setProperty("SHOW_OVERVIEW", "true");
1502     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
1503             DataSourceType.FILE);
1504
1505     assertNull(af.alignPanel.getOverviewPanel());
1506   }
1507
1508   /**
1509    * Test that a view from an older version of Jalview is restored with Overview
1510    * automatically shown when the preference is set
1511    * 
1512    * @throws Exception
1513    */
1514   @Test(groups = { "Functional" }, enabled = true)
1515   public void testAutoShowOverviewForLegacyProjects() throws Exception
1516   {
1517     Desktop.instance.closeAll_actionPerformed(null);
1518     Cache.setProperty("SHOW_OVERVIEW", "true");
1519     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1520             "examples/exampleFile.jvp", DataSourceType.FILE);
1521
1522     Cache.setProperty("SHOW_OVERVIEW", "false");
1523     assertNotNull(af.alignPanel.getOverviewPanel());
1524   }
1525
1526   /**
1527    * Test that loading example.jvp, doing some stuff, then hitting reload
1528    * doesn't leave the modified window still open
1529    * 
1530    * See JAL-4127 - interactively performing the same actions and reloading
1531    * works fine, but programmatically they do not
1532    * 
1533    * @throws Exception
1534    */
1535   @Test(groups = { "Functional" }, enabled = false)
1536   public void testReloadActuallyReloads() throws Exception
1537   {
1538     Desktop.instance.closeAll_actionPerformed(null);
1539     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1540             "examples/exampleFile.jvp", DataSourceType.FILE);
1541     af.getViewport().getColumnSelection().addElement(3);
1542     af.hideSelColumns_actionPerformed(null);
1543     af.newView("new", true);
1544     af.reload_actionPerformed(null);
1545     Thread.sleep(30);
1546     // af exists still but isn't shown
1547     assertTrue(af.isClosed());
1548   }
1549
1550   @Test(groups = { "Functional" })
1551   public void testMatrixToFloatsAndBack()
1552   {
1553     int imax=2000;
1554     int i=imax;
1555     SequenceI sq = new Sequence("dummy","SEQ");
1556     while (sq.getLength()<i)
1557     {
1558       sq.setSequence(sq.getSequenceAsString()+'Q');
1559     }
1560     float[][] paevals = new float[i][i];
1561     for (i = imax - 1; i >= 0; i--)
1562     {
1563       for (int j = 0; j <= i; j++)
1564       {
1565         paevals[i][j] = ((i - j < 2)
1566                 || ((i > 1 && i < 5) && (j > 1 && i < 5))) ? 1 : 0f;
1567         paevals[j][i] = -paevals[i][j];
1568       }
1569     }
1570     PAEContactMatrix dummyMat = new PAEContactMatrix(sq, paevals);
1571     String content = ContactMatrix.contactToFloatString(dummyMat);
1572     Assert.assertTrue(content.contains("\t1.")); // at least one element must be
1573                                                  // 1
1574     float[][] vals = ContactMatrix.fromFloatStringToContacts(content,
1575             sq.getLength(), sq.getLength());
1576     assertEquals(vals[3][4], paevals[3][4]);
1577     assertEquals(vals[4][3], paevals[4][3]);
1578     
1579     // test recovery
1580     for (i=0;i<imax;i++)
1581     {
1582       for (int j=0;j<imax;j++)
1583       {
1584         assertEquals(vals[i][j],paevals[i][j]);
1585       }
1586     }
1587   }
1588   @Test(groups = { "Functional" })
1589   public void testPAEsaveRestore() throws Exception
1590   {
1591     Desktop.instance.closeAll_actionPerformed(null);
1592     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1593             ">seq1\nMATRSQFLVNF\n", DataSourceType.PASTE);
1594     AlignmentI al = af.getViewport().getAlignment();
1595     // PAE matrices are added as reference annotation to the dataset sequence
1596     // at least for now.
1597     SequenceI sq = al.getSequenceAt(0).getDatasetSequence();
1598     int i = sq.getLength();
1599     float[][] paevals = new float[i][i];
1600     for (i = i - 1; i >= 0; i--)
1601     {
1602       for (int j = 0; j <= i; j++)
1603       {
1604         paevals[i][j] = ((i - j < 2)
1605                 || ((i > 1 && i < 5) && (j > 1 && i < 5))) ? 1 : 0f;
1606         paevals[j][i] = -paevals[i][j];
1607       }
1608     }
1609     PAEContactMatrix dummyMat = new PAEContactMatrix(sq, paevals);
1610     String content = ContactMatrix.contactToFloatString(dummyMat);
1611     Assert.assertTrue(content.contains("\t1.")); // at least one element must be
1612                                                  // 1
1613     float[][] vals = ContactMatrix.fromFloatStringToContacts(content,
1614             sq.getLength(), sq.getLength());
1615     assertEquals(vals[3][4], paevals[3][4]);
1616     assertEquals(vals[4][3], paevals[4][3]);
1617     dummyMat.setGroupSet(GroupSet.makeGroups(dummyMat, false,0.5f, false));
1618     Assert.assertNotSame(dummyMat.getNewick(), "");
1619     AlignmentAnnotation paeCm = sq.addContactList(dummyMat);
1620     al.addAnnotation(paeCm);
1621     // verify store/restore of group bitsets
1622     for (BitSet gp : dummyMat.getGroups())
1623     {
1624       StringBuilder sb = new StringBuilder();
1625       for (long val : gp.toLongArray())
1626       {
1627         if (sb.length() > 0)
1628         {
1629           sb.append(",");
1630         }
1631         sb.append(val);
1632       }
1633       String[] longvals = sb.toString().split(",");
1634       long[] newlongvals = new long[longvals.length];
1635       for (int lv = 0; lv < longvals.length; lv++)
1636       {
1637         try
1638         {
1639           newlongvals[lv] = Long.valueOf(longvals[lv]);
1640         } catch (Exception x)
1641         {
1642           Assert.fail("failed to deserialise bitset element ");
1643         }
1644       }
1645       BitSet newGp = BitSet.valueOf(newlongvals);
1646       assertTrue(gp.equals(newGp));
1647     }
1648     File tfile = File.createTempFile("testStoreAndRecoverPAEmatrix",
1649             ".jvp");
1650     new Jalview2XML(false).saveState(tfile);
1651     Desktop.instance.closeAll_actionPerformed(null);
1652
1653     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
1654             DataSourceType.FILE);
1655     AlignmentI newAl = af.getViewport().getAlignment();
1656     SequenceI newSeq = newAl.getSequenceAt(0).getDatasetSequence();
1657     // check annotation of the expected type exists
1658     Assert.assertEquals(newSeq.getAnnotation().length, 1);
1659     Assert.assertEquals(newSeq.getAnnotation()[0].graph, paeCm.graph);
1660
1661     // check a contact matrix was recovered
1662     Assert.assertEquals(newSeq.getContactMaps().size(), 1);
1663     // and can be found for the annotation on the sequence
1664     ContactMatrixI restoredMat = newSeq
1665             .getContactMatrixFor(newSeq.getAnnotation()[0]);
1666     Assert.assertNotNull(restoredMat);
1667     MapList oldMap = ((MappableContactMatrixI) dummyMat).getMapFor(sq);
1668     MapList newMap = ((MappableContactMatrixI) restoredMat)
1669             .getMapFor(newSeq);
1670     Assert.assertEquals(oldMap.getFromRanges(), newMap.getFromRanges());
1671     Assert.assertEquals(oldMap.getToRanges(), newMap.getToRanges());
1672     Assert.assertEquals(oldMap.getFromRatio(), newMap.getFromRatio());
1673     Assert.assertEquals(oldMap.getToRatio(), newMap.getToRatio());
1674     for (i = sq.getLength() - 1; i >= 0; i--)
1675     {
1676       ContactListI oldCM = dummyMat.getContactList(i),
1677               newCM = restoredMat.getContactList(i);
1678       for (int j = oldCM.getContactHeight(); j >= 0; j--)
1679       {
1680         double old_j = oldCM.getContactAt(j);
1681         double new_j = newCM.getContactAt(j);
1682         Assert.assertEquals(old_j, new_j);
1683       }
1684     }
1685     Assert.assertEquals(restoredMat.hasGroups(), dummyMat.hasGroups());
1686     Assert.assertEquals(restoredMat.getGroups(), dummyMat.getGroups());
1687     Assert.assertEquals(restoredMat.hasTree(), dummyMat.hasTree());
1688     Assert.assertEquals(restoredMat.getNewick(), dummyMat.getNewick());
1689
1690     // verify no duplicate PAE matrix data when new view created and saved
1691     
1692     // add reference annotations to view first, then copy
1693     AlignmentUtils.addReferenceAnnotationTo(newAl, newAl.getSequenceAt(0), newSeq.getAnnotation()[0],null);
1694     
1695     AlignmentViewPanel newview = af.newView("copy of PAE", true);
1696     
1697     // redundant asserts here check all is good with the new view firest...
1698     AlignmentI newviewAl = newview.getAlignment();
1699     SequenceI newviewSeq = newviewAl.getSequenceAt(0);
1700     // check annotation of the expected type exists
1701     Assert.assertEquals(newviewSeq.getAnnotation().length, 1);
1702     Assert.assertEquals(newviewSeq.getAnnotation()[0].graph, paeCm.graph);
1703     // check we have just one contact matrix mapping
1704     Assert.assertEquals(newviewSeq.getContactMaps().size(), 1);
1705     
1706     // and can be found for the annotation on the sequence
1707     ContactMatrixI newviewMat = newviewSeq
1708             .getContactMatrixFor(newviewSeq.getAnnotation()[0]);
1709     Assert.assertNotNull(newviewMat);
1710
1711     Assert.assertTrue(newviewMat == restoredMat);
1712     
1713     // save the two views and restore. Now look at visible annotation to check all views have shared refs.
1714     
1715     tfile = File.createTempFile("testStoreAndRecoverPAEmatrixTwoViews",
1716             ".jvp");
1717     new Jalview2XML(false).saveState(tfile);
1718     Desktop.instance.closeAll_actionPerformed(null);
1719
1720     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
1721             DataSourceType.FILE);
1722     newAl = af.getAlignPanels().get(0).getAlignment();
1723     AlignmentAnnotation view1aa = newAl.getSequenceAt(0).getAnnotation()[0];
1724
1725     newviewAl = af.getAlignPanels().get(1).getAlignment();
1726     AlignmentAnnotation view2aa = newviewAl.getSequenceAt(0).getAnnotation()[0];
1727
1728     // annotations are shared across alignment views - so should still have an identical pair of annotations.
1729     Assert.assertTrue(view1aa==view2aa);
1730     // identical annotations means identical contact matrix mappings
1731     Assert.assertEquals(newAl.getDataset().getSequenceAt(0).getContactMaps().size(), 1);
1732
1733     // TODO Verify when distinct mappable PAEs are created, only one PAE dataset is actually held.
1734     // Assert.assertTrue(view1aa!=view2aa);
1735     // restoredMat = newAl.getContactMatrixFor(view1aa);
1736     // newviewMat = newviewAl.getContactMatrixFor(view2aa);
1737     // Assert.assertTrue(restoredMat!=newviewMat);
1738     
1739   }
1740
1741   @Test(groups = "Functional")
1742   public void testStoreAndRestoreIDwidthAndAnnotationHeight() throws IOException
1743   {
1744     Desktop.instance.closeAll_actionPerformed(null);
1745     final String SECONDVIEW = "With Diffferent IDwidth";
1746     // create a new tempfile
1747     File tempfile = File.createTempFile("jvIdWidthStoreRestore", "jvp");
1748
1749
1750     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded("examples/exampleFile.jvp",
1751               DataSourceType.FILE);
1752       assertNotNull(af, "Didn't read in the example file correctly.");
1753       assertEquals(af.alignPanel.getAlignViewport().getIdWidth(), 144,
1754               "Legacy project import should have fixed ID width");
1755       assertTrue(af.alignPanel.getIdPanel().getIdCanvas().isManuallyAdjusted());
1756       
1757       
1758       af.alignPanel.getAlignViewport().setIdWidth(100);
1759       af.alignPanel.updateLayout();
1760       assertTrue(af.alignPanel.getIdPanel().getIdCanvas().isManuallyAdjusted());
1761       
1762       Jalview2XML jv2xml = new jalview.project.Jalview2XML(false);
1763       tempfile.delete();
1764       jv2xml.saveState(tempfile);
1765       assertTrue(jv2xml.errorMessage == null,
1766               "Failed to save dummy project with PCA: test broken");
1767       af = null;
1768       // load again.
1769       Desktop.instance.closeAll_actionPerformed(null);
1770       af = new FileLoader().LoadFileWaitTillLoaded(
1771               tempfile.getCanonicalPath(), DataSourceType.FILE);
1772       assertTrue(af.alignPanel.getIdPanel().getIdCanvas()
1773               .isManuallyAdjusted());
1774       assertEquals(af.alignPanel.getAlignViewport().getIdWidth(), 100,
1775               "New project exported and import should have adjusted ID width");
1776
1777       af.alignPanel.getAlignViewport().setIdWidth(100);
1778       af.alignPanel.updateLayout();
1779       assertTrue(af.alignPanel.getIdPanel().getIdCanvas().isManuallyAdjusted());
1780       
1781       // now make it autoadjusted
1782       af.alignPanel.getAlignViewport().setIdWidth(-1);
1783       af.alignPanel.getIdPanel().getIdCanvas().setManuallyAdjusted(false);
1784       af.alignPanel.updateLayout();
1785       assertFalse(af.alignPanel.getIdPanel().getIdCanvas().isManuallyAdjusted());
1786       assertTrue(af.alignPanel.getAlignViewport().getIdWidth()>-1,
1787               "New project exported and import should have adjusted ID width");
1788       
1789       jv2xml = new jalview.project.Jalview2XML(false);
1790       tempfile.delete();
1791       jv2xml.saveState(tempfile);
1792       assertTrue(jv2xml.errorMessage == null,
1793               "Failed to save dummy project with PCA: test broken");
1794       af = null;
1795       // load again.
1796       Desktop.instance.closeAll_actionPerformed(null);
1797       af = new FileLoader().LoadFileWaitTillLoaded(
1798               tempfile.getCanonicalPath(), DataSourceType.FILE);
1799       assertFalse(af.alignPanel.getIdPanel().getIdCanvas().isManuallyAdjusted());
1800       assertTrue(af.alignPanel.getAlignViewport().getIdWidth()>-1,
1801               "New project exported and import should have adjusted ID width");
1802   }
1803
1804 }