Merge branch 'develop' into patch/JAL-4281_idwidthandannotHeight_in_project
[jalview.git] / test / jalview / project / Jalview2xmlTests.java
index 351cedf..76c5266 100644 (file)
@@ -32,9 +32,12 @@ import java.awt.Color;
 import java.awt.Rectangle;
 import java.io.File;
 import java.io.IOException;
+import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.BitSet;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 import javax.swing.JInternalFrame;
@@ -44,6 +47,7 @@ import org.testng.AssertJUnit;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import jalview.analysis.AlignmentUtils;
 import jalview.analysis.scoremodels.SimilarityParams;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
@@ -52,12 +56,18 @@ import jalview.api.ViewStyleI;
 import jalview.bin.Cache;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactMatrix;
+import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.GeneLocus;
+import jalview.datamodel.GroupSet;
 import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.Mapping;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.PDBEntry.Type;
+import jalview.datamodel.Sequence;
 import jalview.datamodel.Sequence.DBModList;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceFeature;
@@ -95,6 +105,8 @@ import jalview.util.MapList;
 import jalview.util.matcher.Condition;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
+import jalview.ws.datamodel.MappableContactMatrixI;
+import jalview.ws.datamodel.alphafold.PAEContactMatrix;
 
 @Test(singleThreaded = true)
 public class Jalview2xmlTests extends Jalview2xmlBase
@@ -104,6 +116,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase
   @BeforeClass(alwaysRun = true)
   public void setUpJvOptionPane()
   {
+    if (Desktop.instance != null)
+      Desktop.instance.closeAll_actionPerformed(null);
     JvOptionPane.setInteractiveMode(false);
     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
   }
@@ -275,12 +289,12 @@ public class Jalview2xmlTests extends Jalview2xmlBase
   @Test(groups = { "Functional" })
   public void gatherViewsHere() throws Exception
   {
-    int origCount = Desktop.getAlignFrames() == null ? 0
-            : Desktop.getAlignFrames().length;
+    int origCount = Desktop.getDesktopAlignFrames() == null ? 0
+            : Desktop.getDesktopAlignFrames().length;
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
     assertNotNull(af, "Didn't read in the example file correctly.");
-    assertTrue(Desktop.getAlignFrames().length == 1 + origCount,
+    assertTrue(Desktop.getDesktopAlignFrames().length == 1 + origCount,
             "Didn't gather the views in the example file.");
 
   }
@@ -418,7 +432,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase
 
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
-    Assert.assertEquals(Desktop.getAlignFrames().length, 1);
+    Assert.assertEquals(Desktop.getDesktopAlignFrames().length, 1);
     String afid = af.getViewport().getSequenceSetId();
 
     // check FileLoader returned a reference to the one alignFrame that is
@@ -428,8 +442,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase
 
     Desktop.explodeViews(af);
 
-    int oldviews = Desktop.getAlignFrames().length;
-    Assert.assertEquals(Desktop.getAlignFrames().length,
+    int oldviews = Desktop.getDesktopAlignFrames().length;
+    Assert.assertEquals(Desktop.getDesktopAlignFrames().length,
             Desktop.getAlignmentPanels(afid).length);
     File tfile = File.createTempFile("testStoreAndRecoverExpanded", ".jvp");
     try
@@ -443,14 +457,14 @@ public class Jalview2xmlTests extends Jalview2xmlBase
       Assert.fail("Didn't save the expanded view state", e);
     }
     Desktop.instance.closeAll_actionPerformed(null);
-    if (Desktop.getAlignFrames() != null)
+    if (Desktop.getDesktopAlignFrames() != null)
     {
-      Assert.assertEquals(Desktop.getAlignFrames().length, 0);
+      Assert.assertEquals(Desktop.getDesktopAlignFrames().length, 0);
     }
     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
             DataSourceType.FILE);
     Assert.assertNotNull(af);
-    Assert.assertEquals(Desktop.getAlignFrames().length,
+    Assert.assertEquals(Desktop.getDesktopAlignFrames().length,
             Desktop.getAlignmentPanels(
                     af.getViewport().getSequenceSetId()).length);
     Assert.assertEquals(Desktop
@@ -507,9 +521,9 @@ public class Jalview2xmlTests extends Jalview2xmlBase
       Assert.fail("Didn't save the expanded view state", e);
     }
     Desktop.instance.closeAll_actionPerformed(null);
-    if (Desktop.getAlignFrames() != null)
+    if (Desktop.getDesktopAlignFrames() != null)
     {
-      Assert.assertEquals(Desktop.getAlignFrames().length, 0);
+      Assert.assertEquals(Desktop.getDesktopAlignFrames().length, 0);
     }
 
     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
@@ -589,6 +603,16 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.3b1", "2.8.3"));
     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8.2b1"));
     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.0b2", "2.8.0b1"));
+    /*
+     * test for patch release versions
+     */
+    assertFalse(Jalview2XML.isVersionStringLaterThan("2.11.3.0", "2.11.2"));
+    assertTrue(Jalview2XML.isVersionStringLaterThan("2.11.3.0", "2.11.4"));
+    assertFalse(
+            Jalview2XML.isVersionStringLaterThan("2.12.2.0b1", "2.12.2.0"));
+    assertFalse(
+            Jalview2XML.isVersionStringLaterThan("2.12.2.3", "2.12.2.2"));
+
   }
 
   /**
@@ -676,9 +700,9 @@ public class Jalview2xmlTests extends Jalview2xmlBase
       Assert.fail("Didn't save the expanded view state", e);
     }
     Desktop.instance.closeAll_actionPerformed(null);
-    if (Desktop.getAlignFrames() != null)
+    if (Desktop.getDesktopAlignFrames() != null)
     {
-      Assert.assertEquals(Desktop.getAlignFrames().length, 0);
+      Assert.assertEquals(Desktop.getDesktopAlignFrames().length, 0);
     }
 
     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
@@ -770,9 +794,9 @@ public class Jalview2xmlTests extends Jalview2xmlBase
       Assert.fail("Didn't save the state", e);
     }
     Desktop.instance.closeAll_actionPerformed(null);
-    if (Desktop.getAlignFrames() != null)
+    if (Desktop.getDesktopAlignFrames() != null)
     {
-      Assert.assertEquals(Desktop.getAlignFrames().length, 0);
+      Assert.assertEquals(Desktop.getDesktopAlignFrames().length, 0);
     }
 
     AlignFrame restoredFrame = new FileLoader().LoadFileWaitTillLoaded(
@@ -807,7 +831,101 @@ public class Jalview2xmlTests extends Jalview2xmlBase
               "Mismatch PDBEntry 'Type'");
       Assert.assertNotNull(recov.getFile(),
               "Recovered PDBEntry should have a non-null file entry");
+      Assert.assertEquals(
+              recov.getFile().toLowerCase(Locale.ENGLISH)
+                      .lastIndexOf("pdb"),
+              recov.getFile().length() - 3,
+              "Recovered PDBEntry file should have PDB suffix");
+    }
+  }
+
+  /**
+   * Configure an alignment and a sub-group each with distinct colour schemes,
+   * Conservation and PID thresholds, and confirm these are restored from the
+   * saved project.
+   * 
+   * @throws IOException
+   */
+  @Test(groups = { "Functional" })
+  public void testStoreAndRecoverAnnotationRowElementColours()
+          throws IOException
+  {
+    Desktop.instance.closeAll_actionPerformed(null);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded("SEQ\tMNQ",
+            DataSourceType.PASTE);
+
+    AlignViewport av = af.getViewport();
+    AlignmentI al = av.getAlignment();
+    SequenceI fsq;
+    fsq = al.getSequenceAt(0);
+    Annotation annots[] = new Annotation[fsq.getLength()];
+    AlignmentAnnotation ala = new AlignmentAnnotation("Colour", "Annots",
+            annots);
+    annots[0] = new Annotation(1.0f);
+    annots[1] = new Annotation(2.0f);
+    annots[2] = new Annotation(3.0f);
+    annots[0].colour = Color.RED;
+    annots[1].colour = Color.GREEN;
+    annots[2].colour = Color.BLUE;
+    ala.validateRangeAndDisplay();
+    al.getSequenceAt(0).addAlignmentAnnotation(ala);
+    al.addAnnotation(ala);
+    /*
+     * and colour by annotation
+     */
+    AnnotationColourGradient acg = new AnnotationColourGradient(ala,
+            af.alignPanel.av.getGlobalColourScheme(), 0);
+    acg.setSeqAssociated(true);
+    acg.setPredefinedColours(true);
+    af.changeColour(acg);
+    Color seqcol[] = new Color[3];
+    for (int iStart = fsq.findIndex(fsq.getStart()), i = 0; i < 3; i++)
+    {
+      seqcol[i] = af.alignPanel.getSeqPanel().seqCanvas
+              .getSequenceRenderer()
+              .getResidueColour(fsq, iStart + i, null);
+    }
+    /*
+     * save project, close windows, reload project, verify
+     */
+    File tfile = File.createTempFile(
+            "testStoreAndRecoverAnnotRowElemColors", ".jvp");
+    tfile.deleteOnExit();
+    new Jalview2XML(false).saveState(tfile);
+    // Desktop.instance.closeAll_actionPerformed(null);
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
+            DataSourceType.FILE);
+    Assert.assertNotNull(af, "Failed to reload project");
+    /*
+     * verify alignment annotation has colors
+     */
+    av = af.getViewport();
+
+    ColourSchemeI loadedCscheme = av.getGlobalColourScheme();
+    Assert.assertTrue(loadedCscheme instanceof AnnotationColourGradient,
+            "Didn't apply Annotation colour gradient");
+    acg = (AnnotationColourGradient) loadedCscheme;
+    assertTrue(acg.isSeqAssociated());
+    assertTrue(acg.isPredefinedColours());
+
+    al = av.getAlignment();
+    fsq = al.getSequenceAt(0);
+    ala = fsq.getAnnotation()[0];
+    Assert.assertNotNull(ala, "No annotation row recovered");
+    Assert.assertNotNull(ala.annotations);
+    for (int iStart = al.getSequenceAt(0)
+            .findIndex(al.getSequenceAt(0).getStart()), i = 0; i < 3; i++)
+    {
+      Assert.assertTrue(ala.annotations[i].colour != null);
+      Assert.assertTrue(ala.annotations[i].colour.equals(annots[i].colour));
+      Color newseqcol = af.alignPanel.getSeqPanel().seqCanvas
+              .getSequenceRenderer()
+              .getResidueColour(fsq, iStart + i, null);
+      Assert.assertTrue(seqcol[i].equals(newseqcol),
+              "Sequence shading is different");
+
     }
+
   }
 
   /**
@@ -1101,7 +1219,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     assertNotNull(af);
 
     AlignmentI ds = null;
-    for (AlignFrame alignFrame : Desktop.getAlignFrames())
+    for (AlignFrame alignFrame : Desktop.getDesktopAlignFrames())
     {
       if (ds == null)
       {
@@ -1386,4 +1504,301 @@ public class Jalview2xmlTests extends Jalview2xmlBase
 
     assertNull(af.alignPanel.getOverviewPanel());
   }
+
+  /**
+   * Test that a view from an older version of Jalview is restored with Overview
+   * automatically shown when the preference is set
+   * 
+   * @throws Exception
+   */
+  @Test(groups = { "Functional" }, enabled = true)
+  public void testAutoShowOverviewForLegacyProjects() throws Exception
+  {
+    Desktop.instance.closeAll_actionPerformed(null);
+    Cache.setProperty("SHOW_OVERVIEW", "true");
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/exampleFile.jvp", DataSourceType.FILE);
+
+    Cache.setProperty("SHOW_OVERVIEW", "false");
+    assertNotNull(af.alignPanel.getOverviewPanel());
+  }
+
+  /**
+   * Test that loading example.jvp, doing some stuff, then hitting reload
+   * doesn't leave the modified window still open
+   * 
+   * See JAL-4127 - interactively performing the same actions and reloading
+   * works fine, but programmatically they do not
+   * 
+   * @throws Exception
+   */
+  @Test(groups = { "Functional" }, enabled = false)
+  public void testReloadActuallyReloads() throws Exception
+  {
+    Desktop.instance.closeAll_actionPerformed(null);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/exampleFile.jvp", DataSourceType.FILE);
+    af.getViewport().getColumnSelection().addElement(3);
+    af.hideSelColumns_actionPerformed(null);
+    af.newView("new", true);
+    af.reload_actionPerformed(null);
+    Thread.sleep(30);
+    // af exists still but isn't shown
+    assertTrue(af.isClosed());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testMatrixToFloatsAndBack()
+  {
+    int imax=2000;
+    int i=imax;
+    SequenceI sq = new Sequence("dummy","SEQ");
+    while (sq.getLength()<i)
+    {
+      sq.setSequence(sq.getSequenceAsString()+'Q');
+    }
+    float[][] paevals = new float[i][i];
+    for (i = imax - 1; i >= 0; i--)
+    {
+      for (int j = 0; j <= i; j++)
+      {
+        paevals[i][j] = ((i - j < 2)
+                || ((i > 1 && i < 5) && (j > 1 && i < 5))) ? 1 : 0f;
+        paevals[j][i] = -paevals[i][j];
+      }
+    }
+    PAEContactMatrix dummyMat = new PAEContactMatrix(sq, paevals);
+    String content = ContactMatrix.contactToFloatString(dummyMat);
+    Assert.assertTrue(content.contains("\t1.")); // at least one element must be
+                                                 // 1
+    float[][] vals = ContactMatrix.fromFloatStringToContacts(content,
+            sq.getLength(), sq.getLength());
+    assertEquals(vals[3][4], paevals[3][4]);
+    assertEquals(vals[4][3], paevals[4][3]);
+    
+    // test recovery
+    for (i=0;i<imax;i++)
+    {
+      for (int j=0;j<imax;j++)
+      {
+        assertEquals(vals[i][j],paevals[i][j]);
+      }
+    }
+  }
+  @Test(groups = { "Functional" })
+  public void testPAEsaveRestore() throws Exception
+  {
+    Desktop.instance.closeAll_actionPerformed(null);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            ">seq1\nMATRSQFLVNF\n", DataSourceType.PASTE);
+    AlignmentI al = af.getViewport().getAlignment();
+    // PAE matrices are added as reference annotation to the dataset sequence
+    // at least for now.
+    SequenceI sq = al.getSequenceAt(0).getDatasetSequence();
+    int i = sq.getLength();
+    float[][] paevals = new float[i][i];
+    for (i = i - 1; i >= 0; i--)
+    {
+      for (int j = 0; j <= i; j++)
+      {
+        paevals[i][j] = ((i - j < 2)
+                || ((i > 1 && i < 5) && (j > 1 && i < 5))) ? 1 : 0f;
+        paevals[j][i] = -paevals[i][j];
+      }
+    }
+    PAEContactMatrix dummyMat = new PAEContactMatrix(sq, paevals);
+    String content = ContactMatrix.contactToFloatString(dummyMat);
+    Assert.assertTrue(content.contains("\t1.")); // at least one element must be
+                                                 // 1
+    float[][] vals = ContactMatrix.fromFloatStringToContacts(content,
+            sq.getLength(), sq.getLength());
+    assertEquals(vals[3][4], paevals[3][4]);
+    assertEquals(vals[4][3], paevals[4][3]);
+    dummyMat.setGroupSet(GroupSet.makeGroups(dummyMat, false,0.5f, false));
+    Assert.assertNotSame(dummyMat.getNewick(), "");
+    AlignmentAnnotation paeCm = sq.addContactList(dummyMat);
+    al.addAnnotation(paeCm);
+    // verify store/restore of group bitsets
+    for (BitSet gp : dummyMat.getGroups())
+    {
+      StringBuilder sb = new StringBuilder();
+      for (long val : gp.toLongArray())
+      {
+        if (sb.length() > 0)
+        {
+          sb.append(",");
+        }
+        sb.append(val);
+      }
+      String[] longvals = sb.toString().split(",");
+      long[] newlongvals = new long[longvals.length];
+      for (int lv = 0; lv < longvals.length; lv++)
+      {
+        try
+        {
+          newlongvals[lv] = Long.valueOf(longvals[lv]);
+        } catch (Exception x)
+        {
+          Assert.fail("failed to deserialise bitset element ");
+        }
+      }
+      BitSet newGp = BitSet.valueOf(newlongvals);
+      assertTrue(gp.equals(newGp));
+    }
+    File tfile = File.createTempFile("testStoreAndRecoverPAEmatrix",
+            ".jvp");
+    new Jalview2XML(false).saveState(tfile);
+    Desktop.instance.closeAll_actionPerformed(null);
+
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
+            DataSourceType.FILE);
+    AlignmentI newAl = af.getViewport().getAlignment();
+    SequenceI newSeq = newAl.getSequenceAt(0).getDatasetSequence();
+    // check annotation of the expected type exists
+    Assert.assertEquals(newSeq.getAnnotation().length, 1);
+    Assert.assertEquals(newSeq.getAnnotation()[0].graph, paeCm.graph);
+
+    // check a contact matrix was recovered
+    Assert.assertEquals(newSeq.getContactMaps().size(), 1);
+    // and can be found for the annotation on the sequence
+    ContactMatrixI restoredMat = newSeq
+            .getContactMatrixFor(newSeq.getAnnotation()[0]);
+    Assert.assertNotNull(restoredMat);
+    MapList oldMap = ((MappableContactMatrixI) dummyMat).getMapFor(sq);
+    MapList newMap = ((MappableContactMatrixI) restoredMat)
+            .getMapFor(newSeq);
+    Assert.assertEquals(oldMap.getFromRanges(), newMap.getFromRanges());
+    Assert.assertEquals(oldMap.getToRanges(), newMap.getToRanges());
+    Assert.assertEquals(oldMap.getFromRatio(), newMap.getFromRatio());
+    Assert.assertEquals(oldMap.getToRatio(), newMap.getToRatio());
+    for (i = sq.getLength() - 1; i >= 0; i--)
+    {
+      ContactListI oldCM = dummyMat.getContactList(i),
+              newCM = restoredMat.getContactList(i);
+      for (int j = oldCM.getContactHeight(); j >= 0; j--)
+      {
+        double old_j = oldCM.getContactAt(j);
+        double new_j = newCM.getContactAt(j);
+        Assert.assertEquals(old_j, new_j);
+      }
+    }
+    Assert.assertEquals(restoredMat.hasGroups(), dummyMat.hasGroups());
+    Assert.assertEquals(restoredMat.getGroups(), dummyMat.getGroups());
+    Assert.assertEquals(restoredMat.hasTree(), dummyMat.hasTree());
+    Assert.assertEquals(restoredMat.getNewick(), dummyMat.getNewick());
+
+    // verify no duplicate PAE matrix data when new view created and saved
+    
+    // add reference annotations to view first, then copy
+    AlignmentUtils.addReferenceAnnotationTo(newAl, newAl.getSequenceAt(0), newSeq.getAnnotation()[0],null);
+    
+    AlignmentViewPanel newview = af.newView("copy of PAE", true);
+    
+    // redundant asserts here check all is good with the new view firest...
+    AlignmentI newviewAl = newview.getAlignment();
+    SequenceI newviewSeq = newviewAl.getSequenceAt(0);
+    // check annotation of the expected type exists
+    Assert.assertEquals(newviewSeq.getAnnotation().length, 1);
+    Assert.assertEquals(newviewSeq.getAnnotation()[0].graph, paeCm.graph);
+    // check we have just one contact matrix mapping
+    Assert.assertEquals(newviewSeq.getContactMaps().size(), 1);
+    
+    // and can be found for the annotation on the sequence
+    ContactMatrixI newviewMat = newviewSeq
+            .getContactMatrixFor(newviewSeq.getAnnotation()[0]);
+    Assert.assertNotNull(newviewMat);
+
+    Assert.assertTrue(newviewMat == restoredMat);
+    
+    // save the two views and restore. Now look at visible annotation to check all views have shared refs.
+    
+    tfile = File.createTempFile("testStoreAndRecoverPAEmatrixTwoViews",
+            ".jvp");
+    new Jalview2XML(false).saveState(tfile);
+    Desktop.instance.closeAll_actionPerformed(null);
+
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
+            DataSourceType.FILE);
+    newAl = af.getAlignPanels().get(0).getAlignment();
+    AlignmentAnnotation view1aa = newAl.getSequenceAt(0).getAnnotation()[0];
+
+    newviewAl = af.getAlignPanels().get(1).getAlignment();
+    AlignmentAnnotation view2aa = newviewAl.getSequenceAt(0).getAnnotation()[0];
+
+    // annotations are shared across alignment views - so should still have an identical pair of annotations.
+    Assert.assertTrue(view1aa==view2aa);
+    // identical annotations means identical contact matrix mappings
+    Assert.assertEquals(newAl.getDataset().getSequenceAt(0).getContactMaps().size(), 1);
+
+    // TODO Verify when distinct mappable PAEs are created, only one PAE dataset is actually held.
+    // Assert.assertTrue(view1aa!=view2aa);
+    // restoredMat = newAl.getContactMatrixFor(view1aa);
+    // newviewMat = newviewAl.getContactMatrixFor(view2aa);
+    // Assert.assertTrue(restoredMat!=newviewMat);
+    
+  }
+
+  @Test(groups = "Functional")
+  public void testStoreAndRestoreIDwidthAndAnnotationHeight() throws IOException
+  {
+    Desktop.instance.closeAll_actionPerformed(null);
+    final String SECONDVIEW = "With Diffferent IDwidth";
+    // create a new tempfile
+    File tempfile = File.createTempFile("jvIdWidthStoreRestore", "jvp");
+
+
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded("examples/exampleFile.jvp",
+              DataSourceType.FILE);
+      assertNotNull(af, "Didn't read in the example file correctly.");
+      assertEquals(af.alignPanel.getAlignViewport().getIdWidth(), 144,
+              "Legacy project import should have fixed ID width");
+      assertTrue(af.alignPanel.getIdPanel().getIdCanvas().isManuallyAdjusted());
+      
+      
+      af.alignPanel.getAlignViewport().setIdWidth(100);
+      af.alignPanel.updateLayout();
+      assertTrue(af.alignPanel.getIdPanel().getIdCanvas().isManuallyAdjusted());
+      
+      Jalview2XML jv2xml = new jalview.project.Jalview2XML(false);
+      tempfile.delete();
+      jv2xml.saveState(tempfile);
+      assertTrue(jv2xml.errorMessage == null,
+              "Failed to save dummy project with PCA: test broken");
+      af = null;
+      // load again.
+      Desktop.instance.closeAll_actionPerformed(null);
+      af = new FileLoader().LoadFileWaitTillLoaded(
+              tempfile.getCanonicalPath(), DataSourceType.FILE);
+      assertTrue(af.alignPanel.getIdPanel().getIdCanvas()
+              .isManuallyAdjusted());
+      assertEquals(af.alignPanel.getAlignViewport().getIdWidth(), 100,
+              "New project exported and import should have adjusted ID width");
+
+      af.alignPanel.getAlignViewport().setIdWidth(100);
+      af.alignPanel.updateLayout();
+      assertTrue(af.alignPanel.getIdPanel().getIdCanvas().isManuallyAdjusted());
+      
+      // now make it autoadjusted
+      af.alignPanel.getAlignViewport().setIdWidth(-1);
+      af.alignPanel.getIdPanel().getIdCanvas().setManuallyAdjusted(false);
+      af.alignPanel.updateLayout();
+      assertFalse(af.alignPanel.getIdPanel().getIdCanvas().isManuallyAdjusted());
+      assertTrue(af.alignPanel.getAlignViewport().getIdWidth()>-1,
+              "New project exported and import should have adjusted ID width");
+      
+      jv2xml = new jalview.project.Jalview2XML(false);
+      tempfile.delete();
+      jv2xml.saveState(tempfile);
+      assertTrue(jv2xml.errorMessage == null,
+              "Failed to save dummy project with PCA: test broken");
+      af = null;
+      // load again.
+      Desktop.instance.closeAll_actionPerformed(null);
+      af = new FileLoader().LoadFileWaitTillLoaded(
+              tempfile.getCanonicalPath(), DataSourceType.FILE);
+      assertFalse(af.alignPanel.getIdPanel().getIdCanvas().isManuallyAdjusted());
+      assertTrue(af.alignPanel.getAlignViewport().getIdWidth()>-1,
+              "New project exported and import should have adjusted ID width");
+  }
+
 }