JAL-1503 update version in GPL header
[jalview.git] / src / jalview / gui / Jalview2XML.java
index b899ae9..dcf65b7 100644 (file)
@@ -1,19 +1,20 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
- * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.1)
+ * Copyright (C) 2014 The Jalview Authors
  * 
  * This file is part of Jalview.
  * 
  * Jalview is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License 
  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- * 
+ *  
  * Jalview is distributed in the hope that it will be useful, but 
  * WITHOUT ANY WARRANTY; without even the implied warranty 
  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
  * PURPOSE.  See the GNU General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
 package jalview.gui;
 
@@ -29,7 +30,6 @@ import javax.swing.*;
 
 import org.exolab.castor.xml.*;
 
-import uk.ac.vamsas.objects.utils.MapList;
 import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
@@ -37,8 +37,15 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
 import jalview.schemabinding.version2.*;
 import jalview.schemes.*;
-import jalview.structure.StructureSelectionManager;
+import jalview.util.Platform;
 import jalview.util.jarInputStreamProvider;
+import jalview.viewmodel.AlignmentViewport;
+import jalview.ws.jws2.Jws2Discoverer;
+import jalview.ws.jws2.dm.AAConSettings;
+import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.AutoCalcSetting;
+import jalview.ws.params.WsParamSetI;
 
 /**
  * Write out the current jalview desktop state as a Jalview XML stream.
@@ -272,6 +279,8 @@ public class Jalview2XML
       return;
     }
 
+    Hashtable<String, AlignFrame> dsses = new Hashtable<String, AlignFrame>();
+
     try
     {
 
@@ -326,6 +335,7 @@ public class Jalview2XML
           }
 
           int ap, apSize = af.alignPanels.size();
+
           for (ap = 0; ap < apSize; ap++)
           {
             AlignmentPanel apanel = (AlignmentPanel) af.alignPanels
@@ -337,9 +347,21 @@ public class Jalview2XML
             }
 
             SaveState(apanel, fileName, jout);
+
+            String dssid = getDatasetIdRef(af.getViewport().getAlignment()
+                    .getDataset());
+            if (!dsses.containsKey(dssid))
+            {
+              dsses.put(dssid, af);
+            }
+
           }
         }
       }
+
+      writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
+              jout);
+
       try
       {
         jout.flush();
@@ -369,6 +391,7 @@ public class Jalview2XML
       int ap, apSize = af.alignPanels.size();
       FileOutputStream fos = new FileOutputStream(jarFile);
       JarOutputStream jout = new JarOutputStream(fos);
+      Hashtable<String, AlignFrame> dsses = new Hashtable<String, AlignFrame>();
       for (ap = 0; ap < apSize; ap++)
       {
         AlignmentPanel apanel = (AlignmentPanel) af.alignPanels
@@ -379,8 +402,14 @@ public class Jalview2XML
           jfileName = jfileName + ".xml";
         }
         SaveState(apanel, jfileName, jout);
+        String dssid = getDatasetIdRef(af.getViewport().getAlignment()
+                .getDataset());
+        if (!dsses.containsKey(dssid))
+        {
+          dsses.put(dssid, af);
+        }
       }
-
+      writeDatasetFor(dsses, fileName, jout);
       try
       {
         jout.flush();
@@ -398,6 +427,22 @@ public class Jalview2XML
     }
   }
 
+  private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
+          String fileName, JarOutputStream jout)
+  {
+
+    for (String dssids : dsses.keySet())
+    {
+      AlignFrame _af = dsses.get(dssids);
+      String jfileName = fileName + " Dataset for " + _af.getTitle();
+      if (!jfileName.endsWith(".xml"))
+      {
+        jfileName = jfileName + ".xml";
+      }
+      SaveState(_af.alignPanel, jfileName, true, jout);
+    }
+  }
+
   /**
    * create a JalviewModel from an algnment view and marshall it to a
    * JarOutputStream
@@ -414,6 +459,28 @@ public class Jalview2XML
   public JalviewModel SaveState(AlignmentPanel ap, String fileName,
           JarOutputStream jout)
   {
+    return SaveState(ap, fileName, false, jout);
+  }
+
+  /**
+   * create a JalviewModel from an algnment view and marshall it to a
+   * JarOutputStream
+   * 
+   * @param ap
+   *          panel to create jalview model for
+   * @param fileName
+   *          name of alignment panel written to output stream
+   * @param storeDS
+   *          when true, only write the dataset for the alignment, not the data
+   *          associated with the view.
+   * @param jout
+   *          jar output stream
+   * @param out
+   *          jar entry name
+   */
+  public JalviewModel SaveState(AlignmentPanel ap, String fileName,
+          boolean storeDS, JarOutputStream jout)
+  {
     initSeqRefs();
     Vector jmolViewIds = new Vector(); //
     Vector userColours = new Vector();
@@ -424,11 +491,12 @@ public class Jalview2XML
     object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
 
     object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
-    object.setVersion(jalview.bin.Cache.getProperty("VERSION"));
+    object.setVersion(jalview.bin.Cache.getDefault("VERSION",
+            "Development Build"));
 
-    jalview.datamodel.AlignmentI jal = av.alignment;
+    jalview.datamodel.AlignmentI jal = av.getAlignment();
 
-    if (av.hasHiddenRows)
+    if (av.hasHiddenRows())
     {
       jal = jal.getHiddenSequences().getFullAlignment();
     }
@@ -443,6 +511,11 @@ public class Jalview2XML
     {
       // dataset id is the dataset's hashcode
       vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
+      if (storeDS)
+      {
+        // switch jal and the dataset
+        jal = jal.getDataset();
+      }
     }
     if (jal.getProperties() != null)
     {
@@ -458,13 +531,16 @@ public class Jalview2XML
     }
 
     JSeq jseq;
+    Set<String> calcIdSet = new HashSet<String>();
 
     // SAVE SEQUENCES
     String id = "";
-    jalview.datamodel.SequenceI jds;
+    jalview.datamodel.SequenceI jds, jdatasq;
     for (int i = 0; i < jal.getHeight(); i++)
     {
       jds = jal.getSequenceAt(i);
+      jdatasq = jds.getDatasetSequence() == null ? jds : jds
+              .getDatasetSequence();
       id = seqHash(jds);
 
       if (seqRefIds.get(id) != null)
@@ -496,30 +572,34 @@ public class Jalview2XML
       jseq.setColour(av.getSequenceColour(jds).getRGB());
 
       jseq.setId(id); // jseq id should be a string not a number
-
-      if (av.hasHiddenRows)
+      if (!storeDS)
       {
-        jseq.setHidden(av.alignment.getHiddenSequences().isHidden(jds));
-
-        if (av.hiddenRepSequences != null
-                && av.hiddenRepSequences.containsKey(jal.getSequenceAt(i)))
+        // Store any sequences this sequence represents
+        if (av.hasHiddenRows())
         {
-          jalview.datamodel.SequenceI[] reps = ((jalview.datamodel.SequenceGroup) av.hiddenRepSequences
-                  .get(jal.getSequenceAt(i))).getSequencesInOrder(jal);
+          jseq.setHidden(av.getAlignment().getHiddenSequences()
+                  .isHidden(jds));
 
-          for (int h = 0; h < reps.length; h++)
+          if (av.isHiddenRepSequence(jal.getSequenceAt(i)))
           {
-            if (reps[h] != jal.getSequenceAt(i))
+            jalview.datamodel.SequenceI[] reps = av
+                    .getRepresentedSequences(jal.getSequenceAt(i))
+                    .getSequencesInOrder(jal);
+
+            for (int h = 0; h < reps.length; h++)
             {
-              jseq.addHiddenSequences(jal.findIndex(reps[h]));
+              if (reps[h] != jal.getSequenceAt(i))
+              {
+                jseq.addHiddenSequences(jal.findIndex(reps[h]));
+              }
             }
           }
         }
       }
 
-      if (jds.getDatasetSequence().getSequenceFeatures() != null)
+      if (jdatasq.getSequenceFeatures() != null)
       {
-        jalview.datamodel.SequenceFeature[] sf = jds.getDatasetSequence()
+        jalview.datamodel.SequenceFeature[] sf = jdatasq
                 .getSequenceFeatures();
         int index = 0;
         while (index < sf.length)
@@ -561,9 +641,9 @@ public class Jalview2XML
         }
       }
 
-      if (jds.getDatasetSequence().getPDBId() != null)
+      if (jdatasq.getPDBId() != null)
       {
-        Enumeration en = jds.getDatasetSequence().getPDBId().elements();
+        Enumeration en = jdatasq.getPDBId().elements();
         while (en.hasMoreElements())
         {
           Pdbids pdb = new Pdbids();
@@ -572,7 +652,10 @@ public class Jalview2XML
 
           pdb.setId(entry.getId());
           pdb.setType(entry.getType());
-
+          //
+          // store any JMol views associated with this seqeunce
+          // this section copes with duplicate entries in the project, so a
+          // dataset only view *should* be coped with sensibly
           AppJmol jmol;
           // This must have been loaded, is it still visible?
           JInternalFrame[] frames = Desktop.desktop.getAllFrames();
@@ -612,7 +695,8 @@ public class Jalview2XML
 
                 for (int smap = 0; smap < jmol.jmb.sequence[peid].length; smap++)
                 {
-                  if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
+                  // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
+                  if (jds == jmol.jmb.sequence[peid][smap])
                   {
                     StructureState state = new StructureState();
                     state.setVisible(true);
@@ -638,6 +722,7 @@ public class Jalview2XML
                     }
                     pdb.addStructureState(state);
                   }
+
                 }
               }
             }
@@ -706,9 +791,9 @@ public class Jalview2XML
       jms.addJSeq(jseq);
     }
 
-    if (av.hasHiddenRows)
+    if (!storeDS && av.hasHiddenRows())
     {
-      jal = av.alignment;
+      jal = av.getAlignment();
     }
     // SAVE MAPPINGS
     if (jal.getCodonFrames() != null && jal.getCodonFrames().length > 0)
@@ -750,7 +835,7 @@ public class Jalview2XML
 
     // SAVE TREES
     // /////////////////////////////////
-    if (av.currentTree != null)
+    if (!storeDS && av.currentTree != null)
     {
       // FIND ANY ASSOCIATED TREES
       // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
@@ -764,7 +849,7 @@ public class Jalview2XML
           {
             TreePanel tp = (TreePanel) frames[t];
 
-            if (tp.treeCanvas.av.alignment == jal)
+            if (tp.treeCanvas.av.getAlignment() == jal)
             {
               Tree tree = new Tree();
               tree.setTitle(tp.getTitle());
@@ -792,148 +877,44 @@ public class Jalview2XML
         }
       }
     }
-
     // SAVE ANNOTATIONS
     /**
      * store forward refs from an annotationRow to any groups
      */
     IdentityHashMap groupRefs = new IdentityHashMap();
-    if (jal.getAlignmentAnnotation() != null)
+    if (storeDS)
     {
-      jalview.datamodel.AlignmentAnnotation[] aa = jal
-              .getAlignmentAnnotation();
-
-      for (int i = 0; i < aa.length; i++)
+      for (SequenceI sq : jal.getSequences())
       {
-        Annotation an = new Annotation();
-
-        if (aa[i].annotationId != null)
-        {
-          annotationIds.put(aa[i].annotationId, aa[i]);
-        }
-
-        an.setId(aa[i].annotationId);
-
-        an.setVisible(aa[i].visible);
-
-        an.setDescription(aa[i].description);
-
-        if (aa[i].sequenceRef != null)
+        // Store annotation on dataset sequences only
+        jalview.datamodel.AlignmentAnnotation[] aa = sq.getAnnotation();
+        if (aa != null && aa.length > 0)
         {
-          // TODO later annotation sequenceRef should be the XML ID of the
-          // sequence rather than its display name
-          an.setSequenceRef(aa[i].sequenceRef.getName());
+          storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
+                  vamsasSet);
         }
-        if (aa[i].groupRef != null)
-        {
-          Object groupIdr = groupRefs.get(aa[i].groupRef);
-          if (groupIdr == null)
-          {
-            // make a locally unique String
-            groupRefs.put(aa[i].groupRef,
-                    groupIdr = ("" + System.currentTimeMillis()
-                            + aa[i].groupRef.getName() + groupRefs.size()));
-          }
-          an.setGroupRef(groupIdr.toString());
-        }
-
-        // store all visualization attributes for annotation
-        an.setGraphHeight(aa[i].graphHeight);
-        an.setCentreColLabels(aa[i].centreColLabels);
-        an.setScaleColLabels(aa[i].scaleColLabel);
-        an.setShowAllColLabels(aa[i].showAllColLabels);
-
-        if (aa[i].graph > 0)
-        {
-          an.setGraph(true);
-          an.setGraphType(aa[i].graph);
-          an.setGraphGroup(aa[i].graphGroup);
-          if (aa[i].getThreshold() != null)
-          {
-            ThresholdLine line = new ThresholdLine();
-            line.setLabel(aa[i].getThreshold().label);
-            line.setValue(aa[i].getThreshold().value);
-            line.setColour(aa[i].getThreshold().colour.getRGB());
-            an.setThresholdLine(line);
-          }
-        }
-        else
-        {
-          an.setGraph(false);
-        }
-
-        an.setLabel(aa[i].label);
-
-        if (aa[i] == av.quality || aa[i] == av.conservation
-                || aa[i] == av.consensus || aa[i].autoCalculated)
-        {
-          // new way of indicating autocalculated annotation -
-          an.setAutoCalculated(aa[i].autoCalculated);
-        }
-        if (aa[i].hasScore())
-        {
-          an.setScore(aa[i].getScore());
-        }
-        AnnotationElement ae;
-        if (aa[i].annotations != null)
-        {
-          an.setScoreOnly(false);
-          for (int a = 0; a < aa[i].annotations.length; a++)
-          {
-            if ((aa[i] == null) || (aa[i].annotations[a] == null))
-            {
-              continue;
-            }
-
-            ae = new AnnotationElement();
-            if (aa[i].annotations[a].description != null)
-              ae.setDescription(aa[i].annotations[a].description);
-            if (aa[i].annotations[a].displayCharacter != null)
-              ae.setDisplayCharacter(aa[i].annotations[a].displayCharacter);
-
-            if (!Float.isNaN(aa[i].annotations[a].value))
-              ae.setValue(aa[i].annotations[a].value);
-
-            ae.setPosition(a);
-            if (aa[i].annotations[a].secondaryStructure != ' '
-                    && aa[i].annotations[a].secondaryStructure != '\0')
-              ae.setSecondaryStructure(aa[i].annotations[a].secondaryStructure
-                      + "");
-
-            if (aa[i].annotations[a].colour != null
-                    && aa[i].annotations[a].colour != java.awt.Color.black)
-            {
-              ae.setColour(aa[i].annotations[a].colour.getRGB());
-            }
-
-            an.addAnnotationElement(ae);
-            if (aa[i].autoCalculated)
-            {
-              // only write one non-null entry into the annotation row -
-              // sufficient to get the visualization attributes necessary to
-              // display data
-              continue;
-            }
-          }
-        }
-        else
-        {
-          an.setScoreOnly(true);
-        }
-        vamsasSet.addAnnotation(an);
+      }
+    }
+    else
+    {
+      if (jal.getAlignmentAnnotation() != null)
+      {
+        // Store the annotation shown on the alignment.
+        jalview.datamodel.AlignmentAnnotation[] aa = jal
+                .getAlignmentAnnotation();
+        storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
+                vamsasSet);
       }
     }
     // SAVE GROUPS
     if (jal.getGroups() != null)
     {
       JGroup[] groups = new JGroup[jal.getGroups().size()];
-
-      for (int i = 0; i < groups.length; i++)
+      int i = -1;
+      for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
       {
-        groups[i] = new JGroup();
+        groups[++i] = new JGroup();
 
-        jalview.datamodel.SequenceGroup sg = (jalview.datamodel.SequenceGroup) jal
-                .getGroups().elementAt(i);
         groups[i].setStart(sg.getStartRes());
         groups[i].setEnd(sg.getEndRes());
         groups[i].setName(sg.getName());
@@ -961,10 +942,10 @@ public class Jalview2XML
           }
           else if (sg.cs instanceof jalview.schemes.AnnotationColourGradient)
           {
-            groups[i]
-                    .setColour(ColourSchemeProperty
-                            .getColourName(((jalview.schemes.AnnotationColourGradient) sg.cs)
-                                    .getBaseColour()));
+            groups[i].setColour("AnnotationColourGradient");
+            groups[i].setAnnotationColours(constructAnnotationColours(
+                    (jalview.schemes.AnnotationColourGradient) sg.cs,
+                    userColours, jms));
           }
           else if (sg.cs instanceof jalview.schemes.UserColourScheme)
           {
@@ -990,6 +971,7 @@ public class Jalview2XML
         groups[i].setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
         groups[i].setShowConsensusHistogram(sg.isShowConsensusHistogram());
         groups[i].setShowSequenceLogo(sg.isShowSequenceLogo());
+        groups[i].setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
         for (int s = 0; s < sg.getSize(); s++)
         {
           jalview.datamodel.Sequence seq = (jalview.datamodel.Sequence) sg
@@ -1000,234 +982,238 @@ public class Jalview2XML
 
       jms.setJGroup(groups);
     }
+    if (!storeDS)
+    {
+      // /////////SAVE VIEWPORT
+      Viewport view = new Viewport();
+      view.setTitle(ap.alignFrame.getTitle());
+      view.setSequenceSetId(makeHashCode(av.getSequenceSetId(),
+              av.getSequenceSetId()));
+      view.setId(av.getViewId());
+      view.setViewName(av.viewName);
+      view.setGatheredViews(av.gatherViewsHere);
+
+      if (ap.av.explodedPosition != null)
+      {
+        view.setXpos(av.explodedPosition.x);
+        view.setYpos(av.explodedPosition.y);
+        view.setWidth(av.explodedPosition.width);
+        view.setHeight(av.explodedPosition.height);
+      }
+      else
+      {
+        view.setXpos(ap.alignFrame.getBounds().x);
+        view.setYpos(ap.alignFrame.getBounds().y);
+        view.setWidth(ap.alignFrame.getBounds().width);
+        view.setHeight(ap.alignFrame.getBounds().height);
+      }
 
-    // /////////SAVE VIEWPORT
-    Viewport view = new Viewport();
-    view.setTitle(ap.alignFrame.getTitle());
-    view.setSequenceSetId(makeHashCode(av.getSequenceSetId(),
-            av.getSequenceSetId()));
-    view.setId(av.getViewId());
-    view.setViewName(av.viewName);
-    view.setGatheredViews(av.gatherViewsHere);
-
-    if (ap.av.explodedPosition != null)
-    {
-      view.setXpos(av.explodedPosition.x);
-      view.setYpos(av.explodedPosition.y);
-      view.setWidth(av.explodedPosition.width);
-      view.setHeight(av.explodedPosition.height);
-    }
-    else
-    {
-      view.setXpos(ap.alignFrame.getBounds().x);
-      view.setYpos(ap.alignFrame.getBounds().y);
-      view.setWidth(ap.alignFrame.getBounds().width);
-      view.setHeight(ap.alignFrame.getBounds().height);
-    }
-
-    view.setStartRes(av.startRes);
-    view.setStartSeq(av.startSeq);
+      view.setStartRes(av.startRes);
+      view.setStartSeq(av.startSeq);
 
-    if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
-    {
-      view.setBgColour(SetUserColourScheme(av.getGlobalColourScheme(),
-              userColours, jms));
-    }
-    else if (av.getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
-    {
-      jalview.schemes.AnnotationColourGradient acg = (jalview.schemes.AnnotationColourGradient) av
-              .getGlobalColourScheme();
-
-      AnnotationColours ac = new AnnotationColours();
-      ac.setAboveThreshold(acg.getAboveThreshold());
-      ac.setThreshold(acg.getAnnotationThreshold());
-      ac.setAnnotation(acg.getAnnotation());
-      if (acg.getBaseColour() instanceof jalview.schemes.UserColourScheme)
+      if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
       {
-        ac.setColourScheme(SetUserColourScheme(acg.getBaseColour(),
+        view.setBgColour(SetUserColourScheme(av.getGlobalColourScheme(),
                 userColours, jms));
       }
+      else if (av.getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
+      {
+        AnnotationColours ac = constructAnnotationColours(
+                (jalview.schemes.AnnotationColourGradient) av
+                        .getGlobalColourScheme(),
+                userColours, jms);
+
+        view.setAnnotationColours(ac);
+        view.setBgColour("AnnotationColourGradient");
+      }
       else
       {
-        ac.setColourScheme(ColourSchemeProperty.getColourName(acg
-                .getBaseColour()));
+        view.setBgColour(ColourSchemeProperty.getColourName(av
+                .getGlobalColourScheme()));
       }
 
-      ac.setMaxColour(acg.getMaxColour().getRGB());
-      ac.setMinColour(acg.getMinColour().getRGB());
-      view.setAnnotationColours(ac);
-      view.setBgColour("AnnotationColourGradient");
-    }
-    else
-    {
-      view.setBgColour(ColourSchemeProperty.getColourName(av
-              .getGlobalColourScheme()));
-    }
+      ColourSchemeI cs = av.getGlobalColourScheme();
 
-    ColourSchemeI cs = av.getGlobalColourScheme();
-
-    if (cs != null)
-    {
-      if (cs.conservationApplied())
+      if (cs != null)
       {
-        view.setConsThreshold(cs.getConservationInc());
-        if (cs instanceof jalview.schemes.UserColourScheme)
+        if (cs.conservationApplied())
+        {
+          view.setConsThreshold(cs.getConservationInc());
+          if (cs instanceof jalview.schemes.UserColourScheme)
+          {
+            view.setBgColour(SetUserColourScheme(cs, userColours, jms));
+          }
+        }
+
+        if (cs instanceof ResidueColourScheme)
         {
-          view.setBgColour(SetUserColourScheme(cs, userColours, jms));
+          view.setPidThreshold(cs.getThreshold());
         }
       }
 
-      if (cs instanceof ResidueColourScheme)
+      view.setConservationSelected(av.getConservationSelected());
+      view.setPidSelected(av.getAbovePIDThreshold());
+      view.setFontName(av.font.getName());
+      view.setFontSize(av.font.getSize());
+      view.setFontStyle(av.font.getStyle());
+      view.setRenderGaps(av.renderGaps);
+      view.setShowAnnotation(av.getShowAnnotation());
+      view.setShowBoxes(av.getShowBoxes());
+      view.setShowColourText(av.getColourText());
+      view.setShowFullId(av.getShowJVSuffix());
+      view.setRightAlignIds(av.rightAlignIds);
+      view.setShowSequenceFeatures(av.showSequenceFeatures);
+      view.setShowText(av.getShowText());
+      view.setShowUnconserved(av.getShowUnconserved());
+      view.setWrapAlignment(av.getWrapAlignment());
+      view.setTextCol1(av.textColour.getRGB());
+      view.setTextCol2(av.textColour2.getRGB());
+      view.setTextColThreshold(av.thresholdTextColour);
+      view.setShowConsensusHistogram(av.isShowConsensusHistogram());
+      view.setShowSequenceLogo(av.isShowSequenceLogo());
+      view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
+      view.setShowGroupConsensus(av.isShowGroupConsensus());
+      view.setShowGroupConservation(av.isShowGroupConservation());
+      view.setShowNPfeatureTooltip(av.isShowNpFeats());
+      view.setShowDbRefTooltip(av.isShowDbRefs());
+      view.setFollowHighlight(av.followHighlight);
+      view.setFollowSelection(av.followSelection);
+      view.setIgnoreGapsinConsensus(av.getIgnoreGapsConsensus());
+      if (av.featuresDisplayed != null)
       {
-        view.setPidThreshold(cs.getThreshold());
-      }
-    }
-
-    view.setConservationSelected(av.getConservationSelected());
-    view.setPidSelected(av.getAbovePIDThreshold());
-    view.setFontName(av.font.getName());
-    view.setFontSize(av.font.getSize());
-    view.setFontStyle(av.font.getStyle());
-    view.setRenderGaps(av.renderGaps);
-    view.setShowAnnotation(av.getShowAnnotation());
-    view.setShowBoxes(av.getShowBoxes());
-    view.setShowColourText(av.getColourText());
-    view.setShowFullId(av.getShowJVSuffix());
-    view.setRightAlignIds(av.rightAlignIds);
-    view.setShowSequenceFeatures(av.showSequenceFeatures);
-    view.setShowText(av.getShowText());
-    view.setShowUnconserved(av.getShowUnconserved());
-    view.setWrapAlignment(av.getWrapAlignment());
-    view.setTextCol1(av.textColour.getRGB());
-    view.setTextCol2(av.textColour2.getRGB());
-    view.setTextColThreshold(av.thresholdTextColour);
-    view.setShowConsensusHistogram(av.isShowConsensusHistogram());
-    view.setShowSequenceLogo(av.isShowSequenceLogo());
-    view.setShowGroupConsensus(av.isShowGroupConsensus());
-    view.setShowGroupConservation(av.isShowGroupConservation());
-    view.setShowNPfeatureTooltip(av.isShowNpFeats());
-    view.setShowDbRefTooltip(av.isShowDbRefs());
-    view.setFollowHighlight(av.followHighlight);
-    view.setFollowSelection(av.followSelection);
-    view.setIgnoreGapsinConsensus(av.getIgnoreGapsConsensus());
-    if (av.featuresDisplayed != null)
-    {
-      jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings();
+        jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings();
 
-      String[] renderOrder = ap.seqPanel.seqCanvas.getFeatureRenderer().renderOrder;
+        String[] renderOrder = ap.seqPanel.seqCanvas.getFeatureRenderer().renderOrder;
 
-      Vector settingsAdded = new Vector();
-      Object gstyle = null;
-      GraduatedColor gcol = null;
-      if (renderOrder != null)
-      {
-        for (int ro = 0; ro < renderOrder.length; ro++)
+        Vector settingsAdded = new Vector();
+        Object gstyle = null;
+        GraduatedColor gcol = null;
+        if (renderOrder != null)
         {
-          gstyle = ap.seqPanel.seqCanvas.getFeatureRenderer()
-                  .getFeatureStyle(renderOrder[ro]);
-          Setting setting = new Setting();
-          setting.setType(renderOrder[ro]);
-          if (gstyle instanceof GraduatedColor)
-          {
-            gcol = (GraduatedColor) gstyle;
-            setting.setColour(gcol.getMaxColor().getRGB());
-            setting.setMincolour(gcol.getMinColor().getRGB());
-            setting.setMin(gcol.getMin());
-            setting.setMax(gcol.getMax());
-            setting.setColourByLabel(gcol.isColourByLabel());
-            setting.setAutoScale(gcol.isAutoScale());
-            setting.setThreshold(gcol.getThresh());
-            setting.setThreshstate(gcol.getThreshType());
+          for (int ro = 0; ro < renderOrder.length; ro++)
+          {
+            gstyle = ap.seqPanel.seqCanvas.getFeatureRenderer()
+                    .getFeatureStyle(renderOrder[ro]);
+            Setting setting = new Setting();
+            setting.setType(renderOrder[ro]);
+            if (gstyle instanceof GraduatedColor)
+            {
+              gcol = (GraduatedColor) gstyle;
+              setting.setColour(gcol.getMaxColor().getRGB());
+              setting.setMincolour(gcol.getMinColor().getRGB());
+              setting.setMin(gcol.getMin());
+              setting.setMax(gcol.getMax());
+              setting.setColourByLabel(gcol.isColourByLabel());
+              setting.setAutoScale(gcol.isAutoScale());
+              setting.setThreshold(gcol.getThresh());
+              setting.setThreshstate(gcol.getThreshType());
+            }
+            else
+            {
+              setting.setColour(ap.seqPanel.seqCanvas.getFeatureRenderer()
+                      .getColour(renderOrder[ro]).getRGB());
+            }
+
+            setting.setDisplay(av.featuresDisplayed
+                    .containsKey(renderOrder[ro]));
+            float rorder = ap.seqPanel.seqCanvas.getFeatureRenderer()
+                    .getOrder(renderOrder[ro]);
+            if (rorder > -1)
+            {
+              setting.setOrder(rorder);
+            }
+            fs.addSetting(setting);
+            settingsAdded.addElement(renderOrder[ro]);
           }
-          else
+        }
+
+        // Make sure we save none displayed feature settings
+        Iterator en = ap.seqPanel.seqCanvas.getFeatureRenderer().featureColours
+                .keySet().iterator();
+        while (en.hasNext())
+        {
+          String key = en.next().toString();
+          if (settingsAdded.contains(key))
           {
-            setting.setColour(ap.seqPanel.seqCanvas.getFeatureRenderer()
-                    .getColour(renderOrder[ro]).getRGB());
+            continue;
           }
 
-          setting.setDisplay(av.featuresDisplayed
-                  .containsKey(renderOrder[ro]));
+          Setting setting = new Setting();
+          setting.setType(key);
+          setting.setColour(ap.seqPanel.seqCanvas.getFeatureRenderer()
+                  .getColour(key).getRGB());
+
+          setting.setDisplay(false);
           float rorder = ap.seqPanel.seqCanvas.getFeatureRenderer()
-                  .getOrder(renderOrder[ro]);
+                  .getOrder(key);
           if (rorder > -1)
           {
             setting.setOrder(rorder);
           }
           fs.addSetting(setting);
-          settingsAdded.addElement(renderOrder[ro]);
+          settingsAdded.addElement(key);
         }
-      }
-
-      // Make sure we save none displayed feature settings
-      Enumeration en = ap.seqPanel.seqCanvas.getFeatureRenderer().featureColours
-              .keys();
-      while (en.hasMoreElements())
-      {
-        String key = en.nextElement().toString();
-        if (settingsAdded.contains(key))
+        en = ap.seqPanel.seqCanvas.getFeatureRenderer().featureGroups
+                .keySet().iterator();
+        Vector groupsAdded = new Vector();
+        while (en.hasNext())
         {
-          continue;
+          String grp = en.next().toString();
+          if (groupsAdded.contains(grp))
+          {
+            continue;
+          }
+          Group g = new Group();
+          g.setName(grp);
+          g.setDisplay(((Boolean) ap.seqPanel.seqCanvas
+                  .getFeatureRenderer().featureGroups.get(grp))
+                  .booleanValue());
+          fs.addGroup(g);
+          groupsAdded.addElement(grp);
         }
+        jms.setFeatureSettings(fs);
 
-        Setting setting = new Setting();
-        setting.setType(key);
-        setting.setColour(ap.seqPanel.seqCanvas.getFeatureRenderer()
-                .getColour(key).getRGB());
+      }
 
-        setting.setDisplay(false);
-        float rorder = ap.seqPanel.seqCanvas.getFeatureRenderer().getOrder(
-                key);
-        if (rorder > -1)
+      if (av.hasHiddenColumns())
+      {
+        if (av.getColumnSelection() == null
+                || av.getColumnSelection().getHiddenColumns() == null)
         {
-          setting.setOrder(rorder);
+          warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
         }
-        fs.addSetting(setting);
-        settingsAdded.addElement(key);
-      }
-      en = ap.seqPanel.seqCanvas.getFeatureRenderer().featureGroups.keys();
-      Vector groupsAdded = new Vector();
-      while (en.hasMoreElements())
-      {
-        String grp = en.nextElement().toString();
-        if (groupsAdded.contains(grp))
+        else
         {
-          continue;
+          for (int c = 0; c < av.getColumnSelection().getHiddenColumns()
+                  .size(); c++)
+          {
+            int[] region = (int[]) av.getColumnSelection()
+                    .getHiddenColumns().elementAt(c);
+            HiddenColumns hc = new HiddenColumns();
+            hc.setStart(region[0]);
+            hc.setEnd(region[1]);
+            view.addHiddenColumns(hc);
+          }
         }
-        Group g = new Group();
-        g.setName(grp);
-        g.setDisplay(((Boolean) ap.seqPanel.seqCanvas.getFeatureRenderer().featureGroups
-                .get(grp)).booleanValue());
-        fs.addGroup(g);
-        groupsAdded.addElement(grp);
       }
-      jms.setFeatureSettings(fs);
-
-    }
-
-    if (av.hasHiddenColumns)
-    {
-      if (av.getColumnSelection() == null
-              || av.getColumnSelection().getHiddenColumns() == null)
-      {
-        warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
-      }
-      else
+      if (calcIdSet.size() > 0)
       {
-        for (int c = 0; c < av.getColumnSelection().getHiddenColumns()
-                .size(); c++)
+        for (String calcId : calcIdSet)
         {
-          int[] region = (int[]) av.getColumnSelection().getHiddenColumns()
-                  .elementAt(c);
-          HiddenColumns hc = new HiddenColumns();
-          hc.setStart(region[0]);
-          hc.setEnd(region[1]);
-          view.addHiddenColumns(hc);
+          if (calcId.trim().length() > 0)
+          {
+            CalcIdParam cidp = createCalcIdParam(calcId, av);
+            // Some calcIds have no parameters.
+            if (cidp != null)
+            {
+              view.addCalcIdParam(cidp);
+            }
+          }
         }
       }
-    }
-
-    jms.addViewport(view);
 
+      jms.addViewport(view);
+    }
     object.setJalviewModelSequence(jms);
     object.getVamsasModel().addSequenceSet(vamsasSet);
 
@@ -1256,6 +1242,267 @@ public class Jalview2XML
     return object;
   }
 
+  private AnnotationColours constructAnnotationColours(
+          AnnotationColourGradient acg, Vector userColours,
+          JalviewModelSequence jms)
+  {
+    AnnotationColours ac = new AnnotationColours();
+    ac.setAboveThreshold(acg.getAboveThreshold());
+    ac.setThreshold(acg.getAnnotationThreshold());
+    ac.setAnnotation(acg.getAnnotation());
+    if (acg.getBaseColour() instanceof jalview.schemes.UserColourScheme)
+    {
+      ac.setColourScheme(SetUserColourScheme(acg.getBaseColour(),
+              userColours, jms));
+    }
+    else
+    {
+      ac.setColourScheme(ColourSchemeProperty.getColourName(acg
+              .getBaseColour()));
+    }
+
+    ac.setMaxColour(acg.getMaxColour().getRGB());
+    ac.setMinColour(acg.getMinColour().getRGB());
+    ac.setPerSequence(acg.isSeqAssociated());
+    ac.setPredefinedColours(acg.isPredefinedColours());
+    return ac;
+  }
+
+  private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
+          IdentityHashMap groupRefs, AlignmentViewport av,
+          Set<String> calcIdSet, boolean storeDS, SequenceSet vamsasSet)
+  {
+
+    for (int i = 0; i < aa.length; i++)
+    {
+      Annotation an = new Annotation();
+
+      if (aa[i].annotationId != null)
+      {
+        annotationIds.put(aa[i].annotationId, aa[i]);
+      }
+
+      an.setId(aa[i].annotationId);
+
+      an.setVisible(aa[i].visible);
+
+      an.setDescription(aa[i].description);
+
+      if (aa[i].sequenceRef != null)
+      {
+        // TODO later annotation sequenceRef should be the XML ID of the
+        // sequence rather than its display name
+        an.setSequenceRef(aa[i].sequenceRef.getName());
+      }
+      if (aa[i].groupRef != null)
+      {
+        Object groupIdr = groupRefs.get(aa[i].groupRef);
+        if (groupIdr == null)
+        {
+          // make a locally unique String
+          groupRefs.put(aa[i].groupRef,
+                  groupIdr = ("" + System.currentTimeMillis()
+                          + aa[i].groupRef.getName() + groupRefs.size()));
+        }
+        an.setGroupRef(groupIdr.toString());
+      }
+
+      // store all visualization attributes for annotation
+      an.setGraphHeight(aa[i].graphHeight);
+      an.setCentreColLabels(aa[i].centreColLabels);
+      an.setScaleColLabels(aa[i].scaleColLabel);
+      an.setShowAllColLabels(aa[i].showAllColLabels);
+      an.setBelowAlignment(aa[i].belowAlignment);
+
+      if (aa[i].graph > 0)
+      {
+        an.setGraph(true);
+        an.setGraphType(aa[i].graph);
+        an.setGraphGroup(aa[i].graphGroup);
+        if (aa[i].getThreshold() != null)
+        {
+          ThresholdLine line = new ThresholdLine();
+          line.setLabel(aa[i].getThreshold().label);
+          line.setValue(aa[i].getThreshold().value);
+          line.setColour(aa[i].getThreshold().colour.getRGB());
+          an.setThresholdLine(line);
+        }
+      }
+      else
+      {
+        an.setGraph(false);
+      }
+
+      an.setLabel(aa[i].label);
+
+      if (aa[i] == av.getAlignmentQualityAnnot()
+              || aa[i] == av.getAlignmentConservationAnnotation()
+              || aa[i] == av.getAlignmentConsensusAnnotation()
+              || aa[i].autoCalculated)
+      {
+        // new way of indicating autocalculated annotation -
+        an.setAutoCalculated(aa[i].autoCalculated);
+      }
+      if (aa[i].hasScore())
+      {
+        an.setScore(aa[i].getScore());
+      }
+
+      if (aa[i].getCalcId() != null)
+      {
+        calcIdSet.add(aa[i].getCalcId());
+        an.setCalcId(aa[i].getCalcId());
+      }
+
+      AnnotationElement ae;
+      if (aa[i].annotations != null)
+      {
+        an.setScoreOnly(false);
+        for (int a = 0; a < aa[i].annotations.length; a++)
+        {
+          if ((aa[i] == null) || (aa[i].annotations[a] == null))
+          {
+            continue;
+          }
+
+          ae = new AnnotationElement();
+          if (aa[i].annotations[a].description != null)
+            ae.setDescription(aa[i].annotations[a].description);
+          if (aa[i].annotations[a].displayCharacter != null)
+            ae.setDisplayCharacter(aa[i].annotations[a].displayCharacter);
+
+          if (!Float.isNaN(aa[i].annotations[a].value))
+            ae.setValue(aa[i].annotations[a].value);
+
+          ae.setPosition(a);
+          if (aa[i].annotations[a].secondaryStructure != ' '
+                  && aa[i].annotations[a].secondaryStructure != '\0')
+            ae.setSecondaryStructure(aa[i].annotations[a].secondaryStructure
+                    + "");
+
+          if (aa[i].annotations[a].colour != null
+                  && aa[i].annotations[a].colour != java.awt.Color.black)
+          {
+            ae.setColour(aa[i].annotations[a].colour.getRGB());
+          }
+
+          an.addAnnotationElement(ae);
+          if (aa[i].autoCalculated)
+          {
+            // only write one non-null entry into the annotation row -
+            // sufficient to get the visualization attributes necessary to
+            // display data
+            continue;
+          }
+        }
+      }
+      else
+      {
+        an.setScoreOnly(true);
+      }
+      if (!storeDS || (storeDS && !aa[i].autoCalculated))
+      {
+        // skip autocalculated annotation - these are only provided for
+        // alignments
+        vamsasSet.addAnnotation(an);
+      }
+    }
+
+  }
+
+  private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
+  {
+    AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
+    if (settings != null)
+    {
+      CalcIdParam vCalcIdParam = new CalcIdParam();
+      vCalcIdParam.setCalcId(calcId);
+      vCalcIdParam.addServiceURL(settings.getServiceURI());
+      // generic URI allowing a third party to resolve another instance of the
+      // service used for this calculation
+      for (String urls : settings.getServiceURLs())
+      {
+        vCalcIdParam.addServiceURL(urls);
+      }
+      vCalcIdParam.setVersion("1.0");
+      if (settings.getPreset() != null)
+      {
+        WsParamSetI setting = settings.getPreset();
+        vCalcIdParam.setName(setting.getName());
+        vCalcIdParam.setDescription(setting.getDescription());
+      }
+      else
+      {
+        vCalcIdParam.setName("");
+        vCalcIdParam.setDescription("Last used parameters");
+      }
+      // need to be able to recover 1) settings 2) user-defined presets or
+      // recreate settings from preset 3) predefined settings provided by
+      // service - or settings that can be transferred (or discarded)
+      vCalcIdParam.setParameters(settings.getWsParamFile().replace("\n",
+              "|\\n|"));
+      vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
+      // todo - decide if updateImmediately is needed for any projects.
+
+      return vCalcIdParam;
+    }
+    return null;
+  }
+
+  private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
+          AlignViewport av)
+  {
+    if (calcIdParam.getVersion().equals("1.0"))
+    {
+      Jws2Instance service = Jws2Discoverer.getDiscoverer()
+              .getPreferredServiceFor(calcIdParam.getServiceURL());
+      if (service != null)
+      {
+        WsParamSetI parmSet = null;
+        try
+        {
+          parmSet = service.getParamStore().parseServiceParameterFile(
+                  calcIdParam.getName(), calcIdParam.getDescription(),
+                  calcIdParam.getServiceURL(),
+                  calcIdParam.getParameters().replace("|\\n|", "\n"));
+        } catch (IOException x)
+        {
+          warn("Couldn't parse parameter data for "
+                  + calcIdParam.getCalcId(), x);
+          return false;
+        }
+        List<ArgumentI> argList = null;
+        if (calcIdParam.getName().length() > 0)
+        {
+          parmSet = service.getParamStore()
+                  .getPreset(calcIdParam.getName());
+          if (parmSet != null)
+          {
+            // TODO : check we have a good match with settings in AACon -
+            // otherwise we'll need to create a new preset
+          }
+        }
+        else
+        {
+          argList = parmSet.getArguments();
+          parmSet = null;
+        }
+        AAConSettings settings = new AAConSettings(
+                calcIdParam.isAutoUpdate(), service, parmSet, argList);
+        av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
+                calcIdParam.isNeedsUpdate());
+        return true;
+      }
+      else
+      {
+        warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
+        return false;
+      }
+    }
+    throw new Error("Unsupported Version for calcIdparam "
+            + calcIdParam.toString());
+  }
+
   /**
    * External mapping between jalview objects and objects yielding a valid and
    * unique object ID string. This is null for normal Jalview project IO, but
@@ -1545,6 +1792,8 @@ public class Jalview2XML
 
     try
     {
+      // create list to store references for any new Jmol viewers created
+      newStructureViewers = new Vector<AppJmol>();
       // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
       // Workaround is to make sure caller implements the JarInputStreamProvider
       // interface
@@ -1552,10 +1801,26 @@ public class Jalview2XML
 
       jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
       af = LoadJalviewAlign(jprovider);
+
     } catch (MalformedURLException e)
     {
       errorMessage = "Invalid URL format for '" + file + "'";
       reportErrors();
+    } finally
+    {
+      try
+      {
+        SwingUtilities.invokeAndWait(new Runnable()
+        {
+          public void run()
+          {
+            setLoadingFinishedForNewStructureViewers();
+          };
+        });
+      } catch (Exception x)
+      {
+
+      }
     }
     return af;
   }
@@ -1578,6 +1843,7 @@ public class Jalview2XML
     return new jarInputStreamProvider()
     {
 
+      @Override
       public JarInputStream getJarInputStream() throws IOException
       {
         if (_url != null)
@@ -1590,6 +1856,7 @@ public class Jalview2XML
         }
       }
 
+      @Override
       public String getFilename()
       {
         return file;
@@ -1626,7 +1893,7 @@ public class Jalview2XML
       frefedSequence = new Vector();
     }
 
-    jalview.gui.AlignFrame af = null;
+    jalview.gui.AlignFrame af = null, _af = null;
     Hashtable gatherToThisFrame = new Hashtable();
     final String file = jprovider.getFilename();
     try
@@ -1653,10 +1920,14 @@ public class Jalview2XML
           object = (JalviewModel) unmar.unmarshal(in);
           if (true) // !skipViewport(object))
           {
-            af = LoadFromObject(object, file, true, jprovider);
-            if (af.viewport.gatherViewsHere)
+            _af = LoadFromObject(object, file, true, jprovider);
+            if (object.getJalviewModelSequence().getViewportCount() > 0)
             {
-              gatherToThisFrame.put(af.viewport.getSequenceSetId(), af);
+              af = _af;
+              if (af.viewport.gatherViewsHere)
+              {
+                gatherToThisFrame.put(af.viewport.getSequenceSetId(), af);
+              }
             }
           }
           entryCount++;
@@ -1754,6 +2025,7 @@ public class Jalview2XML
       {
         javax.swing.SwingUtilities.invokeLater(new Runnable()
         {
+          @Override
           public void run()
           {
             JOptionPane.showInternalMessageDialog(Desktop.desktop,
@@ -1778,7 +2050,7 @@ public class Jalview2XML
    * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
    * sync if this is set to true.
    */
-  private boolean updateLocalViews = false;
+  private final boolean updateLocalViews = false;
 
   String loadPDBFile(jarInputStreamProvider jprovider, String pdbId)
   {
@@ -1822,9 +2094,9 @@ public class Jalview2XML
         }
         ;
         out.close();
-
-        alreadyLoadedPDB.put(pdbId, outFile.getAbsolutePath());
-        return outFile.getAbsolutePath();
+        String t = outFile.getAbsolutePath();
+        alreadyLoadedPDB.put(pdbId, t);
+        return t;
       }
       else
       {
@@ -1878,7 +2150,9 @@ public class Jalview2XML
 
     JalviewModelSequence jms = object.getJalviewModelSequence();
 
-    Viewport view = jms.getViewport(0);
+    Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
+            : null;
+
     // ////////////////////////////////
     // LOAD SEQUENCES
 
@@ -1897,7 +2171,7 @@ public class Jalview2XML
 
       if (seqRefIds.get(seqId) != null)
       {
-        tmpseqs.add((jalview.datamodel.Sequence) seqRefIds.get(seqId));
+        tmpseqs.add(seqRefIds.get(seqId));
         multipleView = true;
       }
       else
@@ -1920,8 +2194,7 @@ public class Jalview2XML
           hiddenSeqs = new Vector();
         }
 
-        hiddenSeqs.addElement((jalview.datamodel.Sequence) seqRefIds
-                .get(seqId));
+        hiddenSeqs.addElement(seqRefIds.get(seqId));
       }
 
     }
@@ -2142,16 +2415,19 @@ public class Jalview2XML
         // Construct new annotation from model.
         AnnotationElement[] ae = an[i].getAnnotationElement();
         jalview.datamodel.Annotation[] anot = null;
-
+        java.awt.Color firstColour = null;
+        int anpos;
         if (!an[i].getScoreOnly())
         {
           anot = new jalview.datamodel.Annotation[al.getWidth()];
           for (int aa = 0; aa < ae.length && aa < anot.length; aa++)
           {
-            if (ae[aa].getPosition() >= anot.length)
+            anpos = ae[aa].getPosition();
+
+            if (anpos >= anot.length)
               continue;
 
-            anot[ae[aa].getPosition()] = new jalview.datamodel.Annotation(
+            anot[anpos] = new jalview.datamodel.Annotation(
 
             ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
                     (ae[aa].getSecondaryStructure() == null || ae[aa]
@@ -2167,8 +2443,11 @@ public class Jalview2XML
             // {
             // anot[ae[aa].getPosition()].displayCharacter = "";
             // }
-            anot[ae[aa].getPosition()].colour = new java.awt.Color(
-                    ae[aa].getColour());
+            anot[anpos].colour = new java.awt.Color(ae[aa].getColour());
+            if (firstColour == null)
+            {
+              firstColour = anot[anpos].colour;
+            }
           }
         }
         jalview.datamodel.AlignmentAnnotation jaa = null;
@@ -2184,7 +2463,7 @@ public class Jalview2XML
                   an[i].getGraphType());
 
           jaa.graphGroup = an[i].getGraphGroup();
-
+          jaa._linecolour = firstColour;
           if (an[i].getThresholdLine() != null)
           {
             jaa.setThreshold(new jalview.datamodel.GraphLine(an[i]
@@ -2204,25 +2483,22 @@ public class Jalview2XML
         {
           jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
                   an[i].getDescription(), anot);
+          jaa._linecolour = firstColour;
         }
-        if (autoForView)
+        // register new annotation
+        if (an[i].getId() != null)
         {
-          // register new annotation
-          if (an[i].getId() != null)
-          {
-            annotationIds.put(an[i].getId(), jaa);
-            jaa.annotationId = an[i].getId();
-          }
-          // recover sequence association
-          if (an[i].getSequenceRef() != null)
+          annotationIds.put(an[i].getId(), jaa);
+          jaa.annotationId = an[i].getId();
+        }
+        // recover sequence association
+        if (an[i].getSequenceRef() != null)
+        {
+          if (al.findName(an[i].getSequenceRef()) != null)
           {
-            if (al.findName(an[i].getSequenceRef()) != null)
-            {
-              jaa.createSequenceMapping(
-                      al.findName(an[i].getSequenceRef()), 1, true);
-              al.findName(an[i].getSequenceRef()).addAlignmentAnnotation(
-                      jaa);
-            }
+            jaa.createSequenceMapping(al.findName(an[i].getSequenceRef()),
+                    1, true);
+            al.findName(an[i].getSequenceRef()).addAlignmentAnnotation(jaa);
           }
         }
         // and make a note of any group association
@@ -2263,6 +2539,12 @@ public class Jalview2XML
         {
           jaa.graphHeight = an[i].getGraphHeight();
         }
+        if (an[i].hasBelowAlignment())
+        {
+          jaa.belowAlignment = an[i].isBelowAlignment();
+        }
+        jaa.setCalcId(an[i].getCalcId());
+
         if (jaa.autoCalculated)
         {
           autoAlan.add(new JvAnnotRow(i, jaa));
@@ -2276,14 +2558,13 @@ public class Jalview2XML
         }
       }
     }
-
     // ///////////////////////
     // LOAD GROUPS
     // Create alignment markup and styles for this view
     if (jms.getJGroupCount() > 0)
     {
       JGroup[] groups = jms.getJGroup();
-
+      boolean addAnnotSchemeGroup = false;
       for (int i = 0; i < groups.length; i++)
       {
         ColourSchemeI cs = null;
@@ -2294,6 +2575,12 @@ public class Jalview2XML
           {
             cs = GetUserColourScheme(jms, groups[i].getColour());
           }
+          else if (groups[i].getColour().equals("AnnotationColourGradient")
+                  && groups[i].getAnnotationColours() != null)
+          {
+            addAnnotSchemeGroup = true;
+            cs = null;
+          }
           else
           {
             cs = ColourSchemeProperty.getColour(al, groups[i].getColour());
@@ -2345,6 +2632,10 @@ public class Jalview2XML
         {
           sg.setshowSequenceLogo(groups[i].isShowSequenceLogo());
         }
+        if (groups[i].hasNormaliseSequenceLogo())
+        {
+          sg.setNormaliseSequenceLogo(groups[i].isNormaliseSequenceLogo());
+        }
         if (groups[i].hasIgnoreGapsinConsensus())
         {
           sg.setIgnoreGapsConsensus(groups[i].getIgnoreGapsinConsensus());
@@ -2388,10 +2679,19 @@ public class Jalview2XML
           }
         }
         al.addGroup(sg);
-
+        if (addAnnotSchemeGroup)
+        {
+          // reconstruct the annotation colourscheme
+          sg.cs = constructAnnotationColour(
+                  groups[i].getAnnotationColours(), null, al, jms, false);
+        }
       }
     }
-
+    if (view == null)
+    {
+      // only dataset in this model, so just return.
+      return null;
+    }
     // ///////////////////////////////
     // LOAD VIEWPORT
 
@@ -2435,6 +2735,13 @@ public class Jalview2XML
 
       }
     }
+    /**
+     * indicate that annotation colours are applied across all groups (pre
+     * Jalview 2.8.1 behaviour)
+     */
+    boolean doGroupAnnColour = isVersionStringLaterThan("2.8.1",
+            object.getVersion());
+
     AlignmentPanel ap = null;
     boolean isnewview = true;
     if (viewId != null)
@@ -2603,7 +2910,7 @@ public class Jalview2XML
               // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
               // seqs_file 2}, boolean[] {
               // linkAlignPanel,superposeWithAlignpanel}} from hash
-              Object[] jmoldat = (Object[]) jmolViewIds.get(sviewid);
+              Object[] jmoldat = jmolViewIds.get(sviewid);
               ((boolean[]) jmoldat[3])[0] |= ids[p].getStructureState(s)
                       .hasAlignwithAlignPanel() ? ids[p].getStructureState(
                       s).getAlignwithAlignPanel() : false;
@@ -2626,12 +2933,12 @@ public class Jalview2XML
               }
               if (ids[p].getFile() != null)
               {
+                File mapkey = new File(ids[p].getFile());
                 Object[] seqstrmaps = (Object[]) ((Hashtable) jmoldat[2])
-                        .get(ids[p].getFile());
+                        .get(mapkey);
                 if (seqstrmaps == null)
                 {
-                  ((Hashtable) jmoldat[2]).put(
-                          new File(ids[p].getFile()).toString(),
+                  ((Hashtable) jmoldat[2]).put(mapkey,
                           seqstrmaps = new Object[]
                           { pdbFile, ids[p].getId(), new Vector(),
                               new Vector() });
@@ -2648,7 +2955,7 @@ public class Jalview2XML
               }
               else
               {
-                errorMessage = ("The Jmol views in the Jalview 2 project may\nnot be correctly bound to sequences in the alignment.\nIn the case of problems, see note at\nhttp://issues.jalview.org/browse/JAL-747");
+                errorMessage = ("The Jmol views in this project were imported\nfrom an older version of Jalview.\nPlease review the sequence colour associations\nin the Colour by section of the Jmol View menu.\n\nIn the case of problems, see note at\nhttp://issues.jalview.org/browse/JAL-747");
                 warn(errorMessage);
               }
             }
@@ -2664,7 +2971,7 @@ public class Jalview2XML
           Object[] svattrib = entry.getValue();
           int[] geom = (int[]) svattrib[0];
           String state = (String) svattrib[1];
-          Hashtable<String, Object[]> oldFiles = (Hashtable<String, Object[]>) svattrib[2];
+          Hashtable<File, Object[]> oldFiles = (Hashtable<File, Object[]>) svattrib[2];
           final boolean useinJmolsuperpos = ((boolean[]) svattrib[3])[0], usetoColourbyseq = ((boolean[]) svattrib[3])[1], jmolColouring = ((boolean[]) svattrib[3])[2];
           int x = geom[0], y = geom[1], width = geom[2], height = geom[3];
           // collate the pdbfile -> sequence mappings from this view
@@ -2728,23 +3035,28 @@ public class Jalview2XML
               {
                 newFileLoc = new StringBuffer();
               }
-              newFileLoc.append(state.substring(cp,
-                      ncp = (state.indexOf("\"", ncp + 1) + 1)));
-              String oldfilenam = state.substring(ncp,
-                      ecp = state.indexOf("\"", ncp));
-              // recover the new mapping data for this old filename
-              // have to normalize filename - since Jmol and jalview do filename
-              // translation differently.
-              Object[] filedat = oldFiles.get(new File(oldfilenam)
-                      .toString());
-              newFileLoc.append(((String) filedat[0]));
-              pdbfilenames.addElement((String) filedat[0]);
-              pdbids.addElement((String) filedat[1]);
-              seqmaps.addElement((SequenceI[]) ((Vector<SequenceI>) filedat[2])
-                      .toArray(new SequenceI[0]));
-              newFileLoc.append("\"");
-              cp = ecp + 1; // advance beyond last \" and set cursor so we can
-                            // look for next file statement.
+              do
+              {
+                // look for next filename in load statement
+                newFileLoc.append(state.substring(cp,
+                        ncp = (state.indexOf("\"", ncp + 1) + 1)));
+                String oldfilenam = state.substring(ncp,
+                        ecp = state.indexOf("\"", ncp));
+                // recover the new mapping data for this old filename
+                // have to normalize filename - since Jmol and jalview do
+                // filename
+                // translation differently.
+                Object[] filedat = oldFiles.get(new File(oldfilenam));
+                newFileLoc.append(Platform
+                        .escapeString((String) filedat[0]));
+                pdbfilenames.addElement((String) filedat[0]);
+                pdbids.addElement((String) filedat[1]);
+                seqmaps.addElement(((Vector<SequenceI>) filedat[2])
+                        .toArray(new SequenceI[0]));
+                newFileLoc.append("\"");
+                cp = ecp + 1; // advance beyond last \" and set cursor so we can
+                              // look for next file statement.
+              } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
             }
             if (cp > 0)
             {
@@ -2757,7 +3069,7 @@ public class Jalview2XML
                       .print("Ignoring incomplete Jmol state for PDB ids: ");
               newFileLoc = new StringBuffer(state);
               newFileLoc.append("; load append ");
-              for (String id : oldFiles.keySet())
+              for (File id : oldFiles.keySet())
               {
                 // add this and any other pdb files that should be present in
                 // the viewer
@@ -2766,7 +3078,7 @@ public class Jalview2XML
                 newFileLoc.append(((String) filedat[0]));
                 pdbfilenames.addElement((String) filedat[0]);
                 pdbids.addElement((String) filedat[1]);
-                seqmaps.addElement((SequenceI[]) ((Vector<SequenceI>) filedat[2])
+                seqmaps.addElement(((Vector<SequenceI>) filedat[2])
                         .toArray(new SequenceI[0]));
                 newFileLoc.append(" \"");
                 newFileLoc.append((String) filedat[0]);
@@ -2802,10 +3114,10 @@ public class Jalview2XML
               // TODO: assemble String[] { pdb files }, String[] { id for each
               // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
               // seqs_file 2}} from hash
-              final String[] pdbf = (String[]) pdbfilenames
-                      .toArray(new String[pdbfilenames.size()]), id = (String[]) pdbids
+              final String[] pdbf = pdbfilenames
+                      .toArray(new String[pdbfilenames.size()]), id = pdbids
                       .toArray(new String[pdbids.size()]);
-              final SequenceI[][] sq = (SequenceI[][]) seqmaps
+              final SequenceI[][] sq = seqmaps
                       .toArray(new SequenceI[seqmaps.size()][]);
               final String fileloc = newFileLoc.toString(), vid = sviewid;
               final AlignFrame alf = af;
@@ -2815,6 +3127,7 @@ public class Jalview2XML
               {
                 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
                 {
+                  @Override
                   public void run()
                   {
                     AppJmol sview = null;
@@ -2823,6 +3136,7 @@ public class Jalview2XML
                       sview = new AppJmol(pdbf, id, sq, alf.alignPanel,
                               useinJmolsuperpos, usetoColourbyseq,
                               jmolColouring, fileloc, rect, vid);
+                      addNewStructureViewer(sview);
                     } catch (OutOfMemoryError ex)
                     {
                       new OOMWarning("restoring structure view for PDB id "
@@ -2855,36 +3169,35 @@ public class Jalview2XML
 
             // add mapping for sequences in this view to an already open Jmol
             // instance
-            for (String id : oldFiles.keySet())
+            for (File id : oldFiles.keySet())
             {
               // add this and any other pdb files that should be present in the
               // viewer
               Object[] filedat = oldFiles.get(id);
               String pdbFile = (String) filedat[0];
-              SequenceI[] seq = (SequenceI[]) ((Vector<SequenceI>) filedat[2])
+              SequenceI[] seq = ((Vector<SequenceI>) filedat[2])
                       .toArray(new SequenceI[0]);
-              ((AppJmol) comp).jmb.ssm.setMapping(seq, null, pdbFile,
+              comp.jmb.ssm.setMapping(seq, null, pdbFile,
                       jalview.io.AppletFormatAdapter.FILE);
-              ((AppJmol) comp).jmb.addSequenceForStructFile(pdbFile, seq);
+              comp.jmb.addSequenceForStructFile(pdbFile, seq);
             }
             // and add the AlignmentPanel's reference to the Jmol view
-            ((AppJmol) comp).addAlignmentPanel(ap);
+            comp.addAlignmentPanel(ap);
             if (useinJmolsuperpos)
             {
-              ((AppJmol) comp).useAlignmentPanelForSuperposition(ap);
+              comp.useAlignmentPanelForSuperposition(ap);
             }
             else
             {
-              ((AppJmol) comp).excludeAlignmentPanelForSuperposition(ap);
+              comp.excludeAlignmentPanelForSuperposition(ap);
             }
             if (usetoColourbyseq)
             {
-              ((AppJmol) comp).useAlignmentPanelForColourbyseq(ap,
-                      !jmolColouring);
+              comp.useAlignmentPanelForColourbyseq(ap, !jmolColouring);
             }
             else
             {
-              ((AppJmol) comp).excludeAlignmentPanelForColourbyseq(ap);
+              comp.excludeAlignmentPanelForColourbyseq(ap);
             }
           }
         }
@@ -2894,6 +3207,83 @@ public class Jalview2XML
     return af;
   }
 
+  /**
+   * 
+   * @param supported - minimum version we are comparing against
+   * @param version - version of data being processsed.
+   * @return true if version is development/null or evaluates to the same or
+   *         later X.Y.Z (where X,Y,Z are like [0-9]+b?[0-9]*)
+   */
+  private boolean isVersionStringLaterThan(String supported, String version)
+  {
+    if (version == null || version.equalsIgnoreCase("DEVELOPMENT BUILD")
+            || version.equalsIgnoreCase("Test") || version.equalsIgnoreCase("AUTOMATED BUILD"))
+    {
+      System.err.println("Assuming project file with "
+              + (version == null ? "null" : version)
+              + " is compatible with Jalview version " + supported);
+      return true;
+    }
+    else
+    {
+      StringTokenizer currentV = new StringTokenizer(supported, "."), fileV = new StringTokenizer(
+              version, ".");
+      while (currentV.hasMoreTokens() && fileV.hasMoreTokens())
+      {
+        // convert b to decimal to catch bugfix releases within a series
+        String curT = currentV.nextToken().toLowerCase().replace('b', '.');
+        String fileT = fileV.nextToken().toLowerCase().replace('b', '.');
+        try
+        {
+          if (Float.valueOf(curT) > Float.valueOf(fileT))
+          {
+            // current version is newer than the version that wrote the file
+            return false;
+          }
+        } catch (NumberFormatException nfe)
+        {
+          System.err
+                  .println("** WARNING: Version comparison failed for tokens ("
+                          + curT
+                          + ") and ("
+                          + fileT
+                          + ")\n** Current: '"
+                          + supported + "' and Version: '" + version + "'");
+        }
+      }
+      if (currentV.hasMoreElements())
+      {
+        // fileV has no minor version but identical series to current
+        return false;
+      }
+    }
+    return true;
+  }
+
+  Vector<AppJmol> newStructureViewers = null;
+
+  protected void addNewStructureViewer(AppJmol sview)
+  {
+    if (newStructureViewers != null)
+    {
+      sview.jmb.setFinishedLoadingFromArchive(false);
+      newStructureViewers.add(sview);
+    }
+  }
+
+  protected void setLoadingFinishedForNewStructureViewers()
+  {
+    if (newStructureViewers != null)
+    {
+      for (AppJmol sview : newStructureViewers)
+      {
+        sview.jmb.setFinishedLoadingFromArchive(true);
+      }
+      newStructureViewers.clear();
+      newStructureViewers = null;
+    }
+  }
+
   AlignFrame loadViewport(String file, JSeq[] JSEQ, Vector hiddenSeqs,
           Alignment al, JalviewModelSequence jms, Viewport view,
           String uniqueSeqSetId, String viewId,
@@ -2907,8 +3297,8 @@ public class Jalview2XML
 
     for (int i = 0; i < JSEQ.length; i++)
     {
-      af.viewport.setSequenceColour(af.viewport.alignment.getSequenceAt(i),
-              new java.awt.Color(JSEQ[i].getColour()));
+      af.viewport.setSequenceColour(af.viewport.getAlignment()
+              .getSequenceAt(i), new java.awt.Color(JSEQ[i].getColour()));
     }
 
     af.viewport.gatherViewsHere = view.getGatheredViews();
@@ -2918,7 +3308,7 @@ public class Jalview2XML
       jalview.gui.AlignViewport av = (jalview.gui.AlignViewport) viewportsAdded
               .get(uniqueSeqSetId);
 
-      af.viewport.sequenceSetID = uniqueSeqSetId;
+      af.viewport.setSequenceSetId(uniqueSeqSetId);
       if (av != null)
       {
         // propagate shared settings to this new view
@@ -3007,93 +3397,11 @@ public class Jalview2XML
       }
       else if (view.getBgColour().startsWith("Annotation"))
       {
-        // int find annotation
-        if (af.viewport.alignment.getAlignmentAnnotation() != null)
-        {
-          for (int i = 0; i < af.viewport.alignment
-                  .getAlignmentAnnotation().length; i++)
-          {
-            if (af.viewport.alignment.getAlignmentAnnotation()[i].label
-                    .equals(view.getAnnotationColours().getAnnotation()))
-            {
-              if (af.viewport.alignment.getAlignmentAnnotation()[i]
-                      .getThreshold() == null)
-              {
-                af.viewport.alignment.getAlignmentAnnotation()[i]
-                        .setThreshold(new jalview.datamodel.GraphLine(view
-                                .getAnnotationColours().getThreshold(),
-                                "Threshold", java.awt.Color.black)
+        AnnotationColours viewAnnColour = view.getAnnotationColours();
+        cs = constructAnnotationColour(viewAnnColour, af, al, jms, true);
 
-                        );
-              }
-
-              if (view.getAnnotationColours().getColourScheme()
-                      .equals("None"))
-              {
-                cs = new AnnotationColourGradient(
-                        af.viewport.alignment.getAlignmentAnnotation()[i],
-                        new java.awt.Color(view.getAnnotationColours()
-                                .getMinColour()), new java.awt.Color(view
-                                .getAnnotationColours().getMaxColour()),
-                        view.getAnnotationColours().getAboveThreshold());
-              }
-              else if (view.getAnnotationColours().getColourScheme()
-                      .startsWith("ucs"))
-              {
-                cs = new AnnotationColourGradient(
-                        af.viewport.alignment.getAlignmentAnnotation()[i],
-                        GetUserColourScheme(jms, view
-                                .getAnnotationColours().getColourScheme()),
-                        view.getAnnotationColours().getAboveThreshold());
-              }
-              else
-              {
-                cs = new AnnotationColourGradient(
-                        af.viewport.alignment.getAlignmentAnnotation()[i],
-                        ColourSchemeProperty.getColour(al, view
-                                .getAnnotationColours().getColourScheme()),
-                        view.getAnnotationColours().getAboveThreshold());
-              }
-
-              // Also use these settings for all the groups
-              if (al.getGroups() != null)
-              {
-                for (int g = 0; g < al.getGroups().size(); g++)
-                {
-                  jalview.datamodel.SequenceGroup sg = (jalview.datamodel.SequenceGroup) al
-                          .getGroups().elementAt(g);
-
-                  if (sg.cs == null)
-                  {
-                    continue;
-                  }
+        // annpos
 
-                  /*
-                   * if
-                   * (view.getAnnotationColours().getColourScheme().equals("None"
-                   * )) { sg.cs = new AnnotationColourGradient(
-                   * af.viewport.alignment.getAlignmentAnnotation()[i], new
-                   * java.awt.Color(view.getAnnotationColours().
-                   * getMinColour()), new
-                   * java.awt.Color(view.getAnnotationColours().
-                   * getMaxColour()),
-                   * view.getAnnotationColours().getAboveThreshold()); } else
-                   */
-                  {
-                    sg.cs = new AnnotationColourGradient(
-                            af.viewport.alignment.getAlignmentAnnotation()[i],
-                            sg.cs, view.getAnnotationColours()
-                                    .getAboveThreshold());
-                  }
-
-                }
-              }
-
-              break;
-            }
-
-          }
-        }
       }
       else
       {
@@ -3103,7 +3411,7 @@ public class Jalview2XML
       if (cs != null)
       {
         cs.setThreshold(view.getPidThreshold(), true);
-        cs.setConsensus(af.viewport.hconsensus);
+        cs.setConsensus(af.viewport.getSequenceConsensusHash());
       }
     }
 
@@ -3129,8 +3437,8 @@ public class Jalview2XML
     }
     if (view.hasIgnoreGapsinConsensus())
     {
-      af.viewport.ignoreGapsInConsensusCalculation = view
-              .getIgnoreGapsinConsensus();
+      af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
+              null);
     }
     if (view.hasFollowHighlight())
     {
@@ -3151,11 +3459,15 @@ public class Jalview2XML
     }
     if (view.hasShowSequenceLogo())
     {
-      af.viewport.showSequenceLogo = view.getShowSequenceLogo();
+      af.viewport.setShowSequenceLogo(view.getShowSequenceLogo());
     }
     else
     {
-      af.viewport.showSequenceLogo = false;
+      af.viewport.setShowSequenceLogo(false);
+    }
+    if (view.hasNormaliseSequenceLogo())
+    {
+      af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo());
     }
     if (view.hasShowDbRefTooltip())
     {
@@ -3256,16 +3568,158 @@ public class Jalview2XML
                 );
       }
     }
-
+    if (view.getCalcIdParam() != null)
+    {
+      for (CalcIdParam calcIdParam : view.getCalcIdParam())
+      {
+        if (calcIdParam != null)
+        {
+          if (recoverCalcIdParam(calcIdParam, af.viewport))
+          {
+          }
+          else
+          {
+            warn("Couldn't recover parameters for "
+                    + calcIdParam.getCalcId());
+          }
+        }
+      }
+    }
     af.setMenusFromViewport(af.viewport);
     // TODO: we don't need to do this if the viewport is aready visible.
     Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
             view.getHeight());
-    af.alignPanel.updateAnnotation(false); // recompute any autoannotation
+    af.alignPanel.updateAnnotation(false, true); // recompute any autoannotation
     reorderAutoannotation(af, al, autoAlan);
+    af.alignPanel.alignmentChanged();
     return af;
   }
 
+  private ColourSchemeI constructAnnotationColour(
+          AnnotationColours viewAnnColour, AlignFrame af, Alignment al,
+          JalviewModelSequence jms, boolean checkGroupAnnColour)
+  {
+    boolean propagateAnnColour = false;
+    ColourSchemeI cs = null;
+    AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al;
+    if (checkGroupAnnColour && al.getGroups() != null
+            && al.getGroups().size() > 0)
+    {
+      // pre 2.8.1 behaviour
+      // check to see if we should transfer annotation colours
+      propagateAnnColour = true;
+      for (jalview.datamodel.SequenceGroup sg : al.getGroups())
+      {
+        if (sg.cs instanceof AnnotationColourGradient)
+        {
+          propagateAnnColour = false;
+        }
+      }
+    }
+    // int find annotation
+    if (annAlignment.getAlignmentAnnotation() != null)
+    {
+      for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
+      {
+        if (annAlignment.getAlignmentAnnotation()[i].label
+                .equals(viewAnnColour.getAnnotation()))
+        {
+          if (annAlignment.getAlignmentAnnotation()[i].getThreshold() == null)
+          {
+            annAlignment.getAlignmentAnnotation()[i]
+                    .setThreshold(new jalview.datamodel.GraphLine(
+                            viewAnnColour.getThreshold(), "Threshold",
+                            java.awt.Color.black)
+
+                    );
+          }
+
+          if (viewAnnColour.getColourScheme().equals("None"))
+          {
+            cs = new AnnotationColourGradient(
+                    annAlignment.getAlignmentAnnotation()[i],
+                    new java.awt.Color(viewAnnColour.getMinColour()),
+                    new java.awt.Color(viewAnnColour.getMaxColour()),
+                    viewAnnColour.getAboveThreshold());
+          }
+          else if (viewAnnColour.getColourScheme().startsWith("ucs"))
+          {
+            cs = new AnnotationColourGradient(
+                    annAlignment.getAlignmentAnnotation()[i],
+                    GetUserColourScheme(jms,
+                            viewAnnColour.getColourScheme()),
+                    viewAnnColour.getAboveThreshold());
+          }
+          else
+          {
+            cs = new AnnotationColourGradient(
+                    annAlignment.getAlignmentAnnotation()[i],
+                    ColourSchemeProperty.getColour(al,
+                            viewAnnColour.getColourScheme()),
+                    viewAnnColour.getAboveThreshold());
+          }
+          if (viewAnnColour.hasPerSequence())
+          {
+            ((AnnotationColourGradient) cs).setSeqAssociated(viewAnnColour
+                    .isPerSequence());
+          }
+          if (viewAnnColour.hasPredefinedColours())
+          {
+            ((AnnotationColourGradient) cs)
+                    .setPredefinedColours(viewAnnColour
+                            .isPredefinedColours());
+          }
+          if (propagateAnnColour && al.getGroups() != null)
+          {
+            // Also use these settings for all the groups
+            for (int g = 0; g < al.getGroups().size(); g++)
+            {
+              jalview.datamodel.SequenceGroup sg = al.getGroups().get(g);
+
+              if (sg.cs == null)
+              {
+                continue;
+              }
+
+              /*
+               * if (viewAnnColour.getColourScheme().equals("None" )) { sg.cs =
+               * new AnnotationColourGradient(
+               * annAlignment.getAlignmentAnnotation()[i], new
+               * java.awt.Color(viewAnnColour. getMinColour()), new
+               * java.awt.Color(viewAnnColour. getMaxColour()),
+               * viewAnnColour.getAboveThreshold()); } else
+               */
+              {
+                sg.cs = new AnnotationColourGradient(
+                        annAlignment.getAlignmentAnnotation()[i], sg.cs,
+                        viewAnnColour.getAboveThreshold());
+                if (cs instanceof AnnotationColourGradient)
+                {
+                  if (viewAnnColour.hasPerSequence())
+                  {
+                    ((AnnotationColourGradient) cs)
+                            .setSeqAssociated(viewAnnColour.isPerSequence());
+                  }
+                  if (viewAnnColour.hasPredefinedColours())
+                  {
+                    ((AnnotationColourGradient) cs)
+                            .setPredefinedColours(viewAnnColour
+                                    .isPredefinedColours());
+                  }
+                }
+              }
+
+            }
+          }
+
+          break;
+        }
+
+      }
+    }
+    return cs;
+  }
+
   private void reorderAutoannotation(AlignFrame af, Alignment al,
           ArrayList<JvAnnotRow> autoAlan)
   {
@@ -3286,21 +3740,34 @@ public class Jalview2XML
       }
       for (JvAnnotRow auan : autoAlan)
       {
-        visan.put(auan.template.label, auan);
+        visan.put(auan.template.label
+                + (auan.template.getCalcId() == null ? "" : "\t"
+                        + auan.template.getCalcId()), auan);
       }
       int hSize = al.getAlignmentAnnotation().length;
       ArrayList<JvAnnotRow> reorder = new ArrayList<JvAnnotRow>();
+      // work through any autoCalculated annotation already on the view
+      // removing it if it should be placed in a different location on the
+      // annotation panel.
+      List<String> remains = new ArrayList(visan.keySet());
       for (int h = 0; h < hSize; h++)
       {
         jalview.datamodel.AlignmentAnnotation jalan = al
                 .getAlignmentAnnotation()[h];
         if (jalan.autoCalculated)
         {
-          JvAnnotRow valan = visan.get(jalan.label);
+          String k;
+          JvAnnotRow valan = visan.get(k = jalan.label);
+          if (jalan.getCalcId() != null)
+          {
+            valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
+          }
+
           if (valan != null)
           {
             // delete the auto calculated row from the alignment
-            al.deleteAnnotation(al.getAlignmentAnnotation()[h], false);
+            al.deleteAnnotation(jalan, false);
+            remains.remove(k);
             hSize--;
             h--;
             if (valan != nullAnnot)
@@ -3322,6 +3789,18 @@ public class Jalview2XML
           }
         }
       }
+      // Add any (possibly stale) autocalculated rows that were not appended to
+      // the view during construction
+      for (String other : remains)
+      {
+        JvAnnotRow othera = visan.get(other);
+        if (othera != nullAnnot && othera.template.getCalcId() != null
+                && othera.template.getCalcId().length() > 0)
+        {
+          reorder.add(othera);
+        }
+      }
+      // now put the automatic annotation in its correct place
       int s = 0, srt[] = new int[reorder.size()];
       JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
       for (JvAnnotRow jvar : reorder)
@@ -3446,7 +3925,7 @@ public class Jalview2XML
     jalview.datamodel.SequenceI dsq = null;
     if (sq != null && sq.getDatasetSequence() != null)
     {
-      dsq = (jalview.datamodel.SequenceI) sq.getDatasetSequence();
+      dsq = sq.getDatasetSequence();
     }
 
     String sqid = vamsasSeq.getDsseqid();
@@ -3486,6 +3965,24 @@ public class Jalview2XML
         if (sq != dsq)
         { // make this dataset sequence sq's dataset sequence
           sq.setDatasetSequence(dsq);
+          // and update the current dataset alignment
+          if (ds == null)
+          {
+            if (dseqs != null)
+            {
+              if (!dseqs.contains(dsq))
+              {
+                dseqs.add(dsq);
+              }
+            }
+            else
+            {
+              if (ds.findIndex(dsq) < 0)
+              {
+                ds.addSequence(dsq);
+              }
+            }
+          }
         }
       }
     }
@@ -3512,11 +4009,12 @@ public class Jalview2XML
            * sb.append(newres.substring(newres.length() - sq.getEnd() -
            * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
            */
-          dsq.setSequence(sb.toString());
+          dsq.setSequence(newres);
         }
         // TODO: merges will never happen if we 'know' we have the real dataset
         // sequence - this should be detected when id==dssid
-        System.err.println("DEBUG Notice:  Merged dataset sequence"); // ("
+        System.err
+                .println("DEBUG Notice:  Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
         // + (pre ? "prepended" : "") + " "
         // + (post ? "appended" : ""));
       }
@@ -3719,11 +4217,11 @@ public class Jalview2XML
     af.closeMenuItem_actionPerformed(true);
 
     /*
-     * if(ap.av.alignment.getAlignmentAnnotation()!=null) { for(int i=0;
-     * i<ap.av.alignment.getAlignmentAnnotation().length; i++) {
-     * if(!ap.av.alignment.getAlignmentAnnotation()[i].autoCalculated) {
-     * af.alignPanel.av.alignment.getAlignmentAnnotation()[i] =
-     * ap.av.alignment.getAlignmentAnnotation()[i]; } } }
+     * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
+     * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
+     * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
+     * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
+     * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
      */
 
     return af.alignPanel;
@@ -3733,7 +4231,7 @@ public class Jalview2XML
    * flag indicating if hashtables should be cleared on finalization TODO this
    * flag may not be necessary
    */
-  private boolean _cleartables = true;
+  private final boolean _cleartables = true;
 
   private Hashtable jvids2vobj;
 
@@ -3742,6 +4240,7 @@ public class Jalview2XML
    * 
    * @see java.lang.Object#finalize()
    */
+  @Override
   protected void finalize() throws Throwable
   {
     // really make sure we have no buried refs left.