JAL-1474 note about buggy 'merge sequence' operation pointing to relevant issue
[jalview.git] / src / jalview / gui / Jalview2XML.java
old mode 100755 (executable)
new mode 100644 (file)
index 147a68d..8bbf735
@@ -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.0b1)
+ * 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,14 @@ 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.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.
@@ -48,7 +54,7 @@ import jalview.util.jarInputStreamProvider;
  * will be :)
  * 
  * @author $author$
- * @version $Revision$
+ * @version $Revision: 1.134 $
  */
 public class Jalview2XML
 {
@@ -424,11 +430,11 @@ 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();
     }
@@ -458,6 +464,7 @@ public class Jalview2XML
     }
 
     JSeq jseq;
+    Set<String> calcIdSet = new HashSet<String>();
 
     // SAVE SEQUENCES
     String id = "";
@@ -497,15 +504,14 @@ public class Jalview2XML
 
       jseq.setId(id); // jseq id should be a string not a number
 
-      if (av.hasHiddenRows)
+      if (av.hasHiddenRows())
       {
-        jseq.setHidden(av.alignment.getHiddenSequences().isHidden(jds));
+        jseq.setHidden(av.getAlignment().getHiddenSequences().isHidden(jds));
 
-        if (av.hiddenRepSequences != null
-                && av.hiddenRepSequences.containsKey(jal.getSequenceAt(i)))
+        if (av.isHiddenRepSequence(jal.getSequenceAt(i)))
         {
-          jalview.datamodel.SequenceI[] reps = ((jalview.datamodel.SequenceGroup) av.hiddenRepSequences
-                  .get(jal.getSequenceAt(i))).getSequencesInOrder(jal);
+          jalview.datamodel.SequenceI[] reps = av.getRepresentedSequences(
+                  jal.getSequenceAt(i)).getSequencesInOrder(jal);
 
           for (int h = 0; h < reps.length; h++)
           {
@@ -612,7 +618,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);
@@ -624,6 +631,7 @@ public class Jalview2XML
                     state.setAlignwithAlignPanel(jmol.isUsedforaligment(ap));
                     state.setColourwithAlignPanel(jmol
                             .isUsedforcolourby(ap));
+                    state.setColourByJmol(jmol.isColouredByJmol());
                     if (!jmolViewIds.contains(state.getViewId()))
                     {
                       // Make sure we only store a Jmol state once in each XML
@@ -705,9 +713,9 @@ public class Jalview2XML
       jms.addJSeq(jseq);
     }
 
-    if (av.hasHiddenRows)
+    if (av.hasHiddenRows())
     {
-      jal = av.alignment;
+      jal = av.getAlignment();
     }
     // SAVE MAPPINGS
     if (jal.getCodonFrames() != null && jal.getCodonFrames().length > 0)
@@ -763,7 +771,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());
@@ -791,7 +799,6 @@ public class Jalview2XML
         }
       }
     }
-
     // SAVE ANNOTATIONS
     /**
      * store forward refs from an annotationRow to any groups
@@ -841,7 +848,8 @@ public class Jalview2XML
         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);
@@ -863,8 +871,10 @@ public class Jalview2XML
 
         an.setLabel(aa[i].label);
 
-        if (aa[i] == av.quality || aa[i] == av.conservation
-                || aa[i] == av.consensus || aa[i].autoCalculated)
+        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);
@@ -873,6 +883,13 @@ public class Jalview2XML
         {
           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)
         {
@@ -908,7 +925,9 @@ public class Jalview2XML
             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
+              // only write one non-null entry into the annotation row -
+              // sufficient to get the visualization attributes necessary to
+              // display data
               continue;
             }
           }
@@ -924,13 +943,11 @@ public class Jalview2XML
     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());
@@ -987,6 +1004,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
@@ -1052,6 +1070,8 @@ public class Jalview2XML
 
       ac.setMaxColour(acg.getMaxColour().getRGB());
       ac.setMinColour(acg.getMinColour().getRGB());
+      ac.setPerSequence(acg.isSeqAssociated());
+      ac.setPredefinedColours(acg.isPredefinedColours());
       view.setAnnotationColours(ac);
       view.setBgColour("AnnotationColourGradient");
     }
@@ -1100,6 +1120,7 @@ public class Jalview2XML
     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());
@@ -1116,48 +1137,51 @@ public class Jalview2XML
       Vector settingsAdded = new Vector();
       Object gstyle = null;
       GraduatedColor gcol = null;
-      for (int ro = 0; ro < renderOrder.length; ro++)
+      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());
-        }
-        else
+        for (int ro = 0; ro < renderOrder.length; ro++)
         {
-          setting.setColour(ap.seqPanel.seqCanvas.getFeatureRenderer()
-                  .getColour(renderOrder[ro]).getRGB());
-        }
+          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);
+          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]);
         }
-        fs.addSetting(setting);
-        settingsAdded.addElement(renderOrder[ro]);
       }
 
       // Make sure we save none displayed feature settings
-      Enumeration en = ap.seqPanel.seqCanvas.getFeatureRenderer().featureColours
-              .keys();
-      while (en.hasMoreElements())
+      Iterator en = ap.seqPanel.seqCanvas.getFeatureRenderer().featureColours
+              .keySet().iterator();
+      while (en.hasNext())
       {
-        String key = en.nextElement().toString();
+        String key = en.next().toString();
         if (settingsAdded.contains(key))
         {
           continue;
@@ -1178,11 +1202,12 @@ public class Jalview2XML
         fs.addSetting(setting);
         settingsAdded.addElement(key);
       }
-      en = ap.seqPanel.seqCanvas.getFeatureRenderer().featureGroups.keys();
+      en = ap.seqPanel.seqCanvas.getFeatureRenderer().featureGroups
+              .keySet().iterator();
       Vector groupsAdded = new Vector();
-      while (en.hasMoreElements())
+      while (en.hasNext())
       {
-        String grp = en.nextElement().toString();
+        String grp = en.next().toString();
         if (groupsAdded.contains(grp))
         {
           continue;
@@ -1198,7 +1223,7 @@ public class Jalview2XML
 
     }
 
-    if (av.hasHiddenColumns)
+    if (av.hasHiddenColumns())
     {
       if (av.getColumnSelection() == null
               || av.getColumnSelection().getHiddenColumns() == null)
@@ -1219,6 +1244,21 @@ public class Jalview2XML
         }
       }
     }
+    if (calcIdSet.size() > 0)
+    {
+      for (String calcId : calcIdSet)
+      {
+        if (calcId.trim().length() > 0)
+        {
+          CalcIdParam cidp = createCalcIdParam(calcId, av);
+          // Some calcIds have no parameters.
+          if (cidp != null)
+          {
+            view.addCalcIdParam(cidp);
+          }
+        }
+      }
+    }
 
     jms.addViewport(view);
 
@@ -1250,6 +1290,99 @@ public class Jalview2XML
     return object;
   }
 
+  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
@@ -1539,6 +1672,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
@@ -1546,11 +1681,27 @@ 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;
   }
 
@@ -1572,6 +1723,7 @@ public class Jalview2XML
     return new jarInputStreamProvider()
     {
 
+      @Override
       public JarInputStream getJarInputStream() throws IOException
       {
         if (_url != null)
@@ -1584,6 +1736,7 @@ public class Jalview2XML
         }
       }
 
+      @Override
       public String getFilename()
       {
         return file;
@@ -1748,6 +1901,7 @@ public class Jalview2XML
       {
         javax.swing.SwingUtilities.invokeLater(new Runnable()
         {
+          @Override
           public void run()
           {
             JOptionPane.showInternalMessageDialog(Desktop.desktop,
@@ -1772,7 +1926,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)
   {
@@ -1816,9 +1970,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
       {
@@ -1891,7 +2045,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
@@ -1914,8 +2068,7 @@ public class Jalview2XML
           hiddenSeqs = new Vector();
         }
 
-        hiddenSeqs.addElement((jalview.datamodel.Sequence) seqRefIds
-                .get(seqId));
+        hiddenSeqs.addElement(seqRefIds.get(seqId));
       }
 
     }
@@ -2087,7 +2240,7 @@ public class Jalview2XML
     /**
      * store any annotations which forward reference a group's ID
      */
-    Hashtable<String,ArrayList<jalview.datamodel.AlignmentAnnotation>> groupAnnotRefs = new Hashtable<String,ArrayList<jalview.datamodel.AlignmentAnnotation>>();
+    Hashtable<String, ArrayList<jalview.datamodel.AlignmentAnnotation>> groupAnnotRefs = new Hashtable<String, ArrayList<jalview.datamodel.AlignmentAnnotation>>();
 
     if (vamsasSet.getAnnotationCount() > 0)
     {
@@ -2110,7 +2263,9 @@ public class Jalview2XML
             an[i].setAutoCalculated(true);
           }
         }
-        if (autoForView  || (an[i].hasAutoCalculated() && an[i].isAutoCalculated())) {
+        if (autoForView
+                || (an[i].hasAutoCalculated() && an[i].isAutoCalculated()))
+        {
           // remove ID - we don't recover annotation from other views for
           // view-specific annotation
           an[i].setId(null);
@@ -2134,16 +2289,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]
@@ -2159,23 +2317,27 @@ 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;
 
         if (an[i].getGraph())
         {
-          float llim=0,hlim=0;
- //         if (autoForView || an[i].isAutoCalculated()) {
-  //          hlim=11f;
-   //       }
+          float llim = 0, hlim = 0;
+          // if (autoForView || an[i].isAutoCalculated()) {
+          // hlim=11f;
+          // }
           jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
-                  an[i].getDescription(), anot, llim, hlim, an[i].getGraphType());
+                  an[i].getDescription(), anot, llim, hlim,
+                  an[i].getGraphType());
 
           jaa.graphGroup = an[i].getGraphGroup();
-
+          jaa._linecolour = firstColour;
           if (an[i].getThresholdLine() != null)
           {
             jaa.setThreshold(new jalview.datamodel.GraphLine(an[i]
@@ -2184,43 +2346,44 @@ public class Jalview2XML
                     an[i].getThresholdLine().getColour())));
 
           }
-          if (autoForView || an[i].isAutoCalculated()) {
-            // Hardwire the symbol display line to ensure that labels for histograms are displayed
-            jaa.hasText=true;
+          if (autoForView || an[i].isAutoCalculated())
+          {
+            // Hardwire the symbol display line to ensure that labels for
+            // histograms are displayed
+            jaa.hasText = true;
           }
         }
         else
         {
           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
         if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0)
         {
-          ArrayList<jalview.datamodel.AlignmentAnnotation> aal=groupAnnotRefs.get(an[i].getGroupRef());
-          if (aal==null) { 
+          ArrayList<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
+                  .get(an[i].getGroupRef());
+          if (aal == null)
+          {
             aal = new ArrayList<jalview.datamodel.AlignmentAnnotation>();
-            groupAnnotRefs.put(an[i].getGroupRef(),aal);
+            groupAnnotRefs.put(an[i].getGroupRef(), aal);
           }
           aal.add(jaa);
         }
@@ -2250,13 +2413,21 @@ 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));
-        } else 
+        }
+        else
         // if (!autoForView)
         {
-          // add autocalculated group annotation and any user created annotation for the view
+          // add autocalculated group annotation and any user created annotation
+          // for the view
           al.addAnnotation(jaa);
         }
       }
@@ -2330,6 +2501,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());
@@ -2351,19 +2526,24 @@ public class Jalview2XML
                   .get(groups[i].getId());
           if (jaal != null)
           {
-            for (jalview.datamodel.AlignmentAnnotation jaa:jaal) {
+            for (jalview.datamodel.AlignmentAnnotation jaa : jaal)
+            {
               jaa.groupRef = sg;
               if (jaa.autoCalculated)
               {
-                // match up and try to set group autocalc alignment row for this annotation
-                if (jaa.label.startsWith("Consensus for ")) {
+                // match up and try to set group autocalc alignment row for this
+                // annotation
+                if (jaa.label.startsWith("Consensus for "))
+                {
                   sg.setConsensus(jaa);
                 }
-                // match up and try to set group autocalc alignment row for this annotation
-                if (jaa.label.startsWith("Conservation for ")) {
+                // match up and try to set group autocalc alignment row for this
+                // annotation
+                if (jaa.label.startsWith("Conservation for "))
+                {
                   sg.setConservationRow(jaa);
-                }              
                 }
+              }
             }
           }
         }
@@ -2573,25 +2753,29 @@ public class Jalview2XML
                 { new int[]
                 { x, y, width, height }, "",
                     new Hashtable<String, Object[]>(), new boolean[]
-                    { false, false } });
-                // Legacy->2.7 conversion: if there is no attribute for
-                // colouring with the alignPanel then by default we set the
-                // first encountered view to be the default source of colour
-                // information.
+                    { false, false, true } });
+                // Legacy pre-2.7 conversion JAL-823 :
+                // do not assume any view has to be linked for colour by
+                // sequence
               }
-              // TODO: assemble String[] { pdb files }, String[] { id for each
+
+              // assemble String[] { pdb files }, String[] { id for each
               // 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;
-              // always colour by linked panel if not specified
+              // never colour by linked panel if not specified
               ((boolean[]) jmoldat[3])[1] |= ids[p].getStructureState(s)
                       .hasColourwithAlignPanel() ? ids[p]
                       .getStructureState(s).getColourwithAlignPanel()
                       : false;
+              // default for pre-2.7 projects is that Jmol colouring is enabled
+              ((boolean[]) jmoldat[3])[2] &= ids[p].getStructureState(s)
+                      .hasColourByJmol() ? ids[p].getStructureState(s)
+                      .getColourByJmol() : true;
 
               if (((String) jmoldat[1]).length() < ids[p]
                       .getStructureState(s).getContent().length())
@@ -2600,22 +2784,32 @@ public class Jalview2XML
                   jmoldat[1] = ids[p].getStructureState(s).getContent();
                 }
               }
-              Object[] seqstrmaps = (Object[]) ((Hashtable) jmoldat[2])
-                      .get(ids[p].getFile());
-              if (seqstrmaps == null)
+              if (ids[p].getFile() != null)
               {
-                ((Hashtable) jmoldat[2]).put(
-                        new File(ids[p].getFile()).toString(),
-                        seqstrmaps = new Object[]
-                        { pdbFile, ids[p].getId(), new Vector(),
-                            new Vector() });
+                File mapkey = new File(ids[p].getFile());
+                Object[] seqstrmaps = (Object[]) ((Hashtable) jmoldat[2])
+                        .get(mapkey);
+                if (seqstrmaps == null)
+                {
+                  ((Hashtable) jmoldat[2]).put(mapkey,
+                          seqstrmaps = new Object[]
+                          { pdbFile, ids[p].getId(), new Vector(),
+                              new Vector() });
+                }
+                if (!((Vector) seqstrmaps[2]).contains(seq))
+                {
+                  ((Vector) seqstrmaps[2]).addElement(seq);
+                  // ((Vector)seqstrmaps[3]).addElement(n) :
+                  // in principle, chains
+                  // should be stored here : do we need to
+                  // TODO: store and recover seq/pdb_id :
+                  // chain mappings
+                }
               }
-              if (!((Vector) seqstrmaps[2]).contains(seq))
+              else
               {
-                ((Vector) seqstrmaps[2]).addElement(seq);
-                // ((Vector)seqstrmaps[3]).addElement(n) : in principle, chains
-                // should be stored here : do we need to
-                // TODO: store and recover seq/pdb_id : chain mappings
+                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);
               }
             }
           }
@@ -2630,8 +2824,8 @@ 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];
-          final boolean useinJmolsuperpos = ((boolean[]) svattrib[3])[0], usetoColourbyseq = ((boolean[]) svattrib[3])[1];
+          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
           Vector<String> pdbfilenames = new Vector<String>();
@@ -2694,23 +2888,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)
             {
@@ -2723,7 +2922,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
@@ -2732,7 +2931,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]);
@@ -2768,10 +2967,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;
@@ -2781,14 +2980,16 @@ public class Jalview2XML
               {
                 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
                 {
+                  @Override
                   public void run()
                   {
                     AppJmol sview = null;
                     try
                     {
                       sview = new AppJmol(pdbf, id, sq, alf.alignPanel,
-                              useinJmolsuperpos, usetoColourbyseq, fileloc,
-                              rect, vid);
+                              useinJmolsuperpos, usetoColourbyseq,
+                              jmolColouring, fileloc, rect, vid);
+                      addNewStructureViewer(sview);
                     } catch (OutOfMemoryError ex)
                     {
                       new OOMWarning("restoring structure view for PDB id "
@@ -2821,36 +3022,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]);
-              StructureSelectionManager.getStructureSelectionManager()
-                      .setMapping(seq, null, pdbFile,
-                              jalview.io.AppletFormatAdapter.FILE);
-              ((AppJmol) comp).jmb.addSequenceForStructFile(pdbFile, seq);
+              comp.jmb.ssm.setMapping(seq, null, pdbFile,
+                      jalview.io.AppletFormatAdapter.FILE);
+              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);
+              comp.useAlignmentPanelForColourbyseq(ap, !jmolColouring);
             }
             else
             {
-              ((AppJmol) comp).excludeAlignmentPanelForColourbyseq(ap);
+              comp.excludeAlignmentPanelForColourbyseq(ap);
             }
           }
         }
@@ -2859,6 +3059,27 @@ public class Jalview2XML
     // and finally return.
     return af;
   }
+  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,
@@ -2873,8 +3094,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();
@@ -2884,7 +3105,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
@@ -2974,18 +3195,18 @@ public class Jalview2XML
       else if (view.getBgColour().startsWith("Annotation"))
       {
         // int find annotation
-        if (af.viewport.alignment.getAlignmentAnnotation() != null)
+        if (af.viewport.getAlignment().getAlignmentAnnotation() != null)
         {
-          for (int i = 0; i < af.viewport.alignment
+          for (int i = 0; i < af.viewport.getAlignment()
                   .getAlignmentAnnotation().length; i++)
           {
-            if (af.viewport.alignment.getAlignmentAnnotation()[i].label
+            if (af.viewport.getAlignment().getAlignmentAnnotation()[i].label
                     .equals(view.getAnnotationColours().getAnnotation()))
             {
-              if (af.viewport.alignment.getAlignmentAnnotation()[i]
+              if (af.viewport.getAlignment().getAlignmentAnnotation()[i]
                       .getThreshold() == null)
               {
-                af.viewport.alignment.getAlignmentAnnotation()[i]
+                af.viewport.getAlignment().getAlignmentAnnotation()[i]
                         .setThreshold(new jalview.datamodel.GraphLine(view
                                 .getAnnotationColours().getThreshold(),
                                 "Threshold", java.awt.Color.black)
@@ -2996,8 +3217,8 @@ public class Jalview2XML
               if (view.getAnnotationColours().getColourScheme()
                       .equals("None"))
               {
-                cs = new AnnotationColourGradient(
-                        af.viewport.alignment.getAlignmentAnnotation()[i],
+                cs = new AnnotationColourGradient(af.viewport
+                        .getAlignment().getAlignmentAnnotation()[i],
                         new java.awt.Color(view.getAnnotationColours()
                                 .getMinColour()), new java.awt.Color(view
                                 .getAnnotationColours().getMaxColour()),
@@ -3006,28 +3227,35 @@ public class Jalview2XML
               else if (view.getAnnotationColours().getColourScheme()
                       .startsWith("ucs"))
               {
-                cs = new AnnotationColourGradient(
-                        af.viewport.alignment.getAlignmentAnnotation()[i],
+                cs = new AnnotationColourGradient(af.viewport
+                        .getAlignment().getAlignmentAnnotation()[i],
                         GetUserColourScheme(jms, view
                                 .getAnnotationColours().getColourScheme()),
                         view.getAnnotationColours().getAboveThreshold());
               }
               else
               {
-                cs = new AnnotationColourGradient(
-                        af.viewport.alignment.getAlignmentAnnotation()[i],
+                cs = new AnnotationColourGradient(af.viewport
+                        .getAlignment().getAlignmentAnnotation()[i],
                         ColourSchemeProperty.getColour(al, view
                                 .getAnnotationColours().getColourScheme()),
                         view.getAnnotationColours().getAboveThreshold());
               }
-
+              if (view.getAnnotationColours().hasPerSequence())
+              {
+                ((AnnotationColourGradient)cs).setSeqAssociated(view.getAnnotationColours().isPerSequence());
+              }
+              if (view.getAnnotationColours().hasPredefinedColours())
+              {
+                ((AnnotationColourGradient)cs).setPredefinedColours(view.getAnnotationColours().isPredefinedColours());
+              }
               // 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);
+                  jalview.datamodel.SequenceGroup sg = al.getGroups()
+                          .get(g);
 
                   if (sg.cs == null)
                   {
@@ -3038,7 +3266,7 @@ public class Jalview2XML
                    * if
                    * (view.getAnnotationColours().getColourScheme().equals("None"
                    * )) { sg.cs = new AnnotationColourGradient(
-                   * af.viewport.alignment.getAlignmentAnnotation()[i], new
+                   * af.viewport.getAlignment().getAlignmentAnnotation()[i], new
                    * java.awt.Color(view.getAnnotationColours().
                    * getMinColour()), new
                    * java.awt.Color(view.getAnnotationColours().
@@ -3046,10 +3274,21 @@ public class Jalview2XML
                    * view.getAnnotationColours().getAboveThreshold()); } else
                    */
                   {
-                    sg.cs = new AnnotationColourGradient(
-                            af.viewport.alignment.getAlignmentAnnotation()[i],
+                    sg.cs = new AnnotationColourGradient(af.viewport
+                            .getAlignment().getAlignmentAnnotation()[i],
                             sg.cs, view.getAnnotationColours()
                                     .getAboveThreshold());
+                    if (cs instanceof AnnotationColourGradient) 
+                    {
+                      if (view.getAnnotationColours().hasPerSequence())
+                      { 
+                        ((AnnotationColourGradient)cs).setSeqAssociated(view.getAnnotationColours().isPerSequence());
+                      }
+                      if (view.getAnnotationColours().hasPredefinedColours())
+                      {
+                        ((AnnotationColourGradient)cs).setPredefinedColours(view.getAnnotationColours().isPredefinedColours());
+                      }
+                    }
                   }
 
                 }
@@ -3069,7 +3308,7 @@ public class Jalview2XML
       if (cs != null)
       {
         cs.setThreshold(view.getPidThreshold(), true);
-        cs.setConsensus(af.viewport.hconsensus);
+        cs.setConsensus(af.viewport.getSequenceConsensusHash());
       }
     }
 
@@ -3095,8 +3334,8 @@ public class Jalview2XML
     }
     if (view.hasIgnoreGapsinConsensus())
     {
-      af.viewport.ignoreGapsInConsensusCalculation = view
-              .getIgnoreGapsinConsensus();
+      af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
+              null);
     }
     if (view.hasFollowHighlight())
     {
@@ -3117,11 +3356,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())
     {
@@ -3222,20 +3465,37 @@ 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
-    reorderAutoannotation(af,al,autoAlan);
+    af.alignPanel.updateAnnotation(false, true); // recompute any autoannotation
+    reorderAutoannotation(af, al, autoAlan);
+    af.alignPanel.alignmentChanged();
     return af;
   }
 
   private void reorderAutoannotation(AlignFrame af, Alignment al,
           ArrayList<JvAnnotRow> autoAlan)
   {
- // copy over visualization settings for autocalculated annotation in the
+    // copy over visualization settings for autocalculated annotation in the
     // view
     if (al.getAlignmentAnnotation() != null)
     {
@@ -3252,46 +3512,73 @@ 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)
             {
-              if (jalan!=valan.template) { 
+              if (jalan != valan.template)
+              {
                 // newly created autoannotation row instance
                 // so keep a reference to the visible annotation row
                 // and copy over all relevant attributes
-                  if (valan.template.graphHeight >= 0)
-              
-              {
-                jalan.graphHeight = valan.template.graphHeight;
-              }
-              jalan.visible = valan.template.visible;
+                if (valan.template.graphHeight >= 0)
+
+                {
+                  jalan.graphHeight = valan.template.graphHeight;
+                }
+                jalan.visible = valan.template.visible;
               }
               reorder.add(new JvAnnotRow(valan.order, jalan));
             }
           }
         }
       }
-      int s=0,srt[] = new int[reorder.size()];
+      // 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) {
+      for (JvAnnotRow jvar : reorder)
+      {
         rws[s] = jvar;
-        srt[s++]=jvar.order;
+        srt[s++] = jvar.order;
       }
       reorder.clear();
       jalview.util.QuickSort.sort(srt, rws);
@@ -3410,7 +3697,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();
@@ -3480,7 +3767,7 @@ public class Jalview2XML
         }
         // 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" : ""));
       }
@@ -3683,11 +3970,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;
@@ -3697,7 +3984,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;
 
@@ -3706,6 +3993,7 @@ public class Jalview2XML
    * 
    * @see java.lang.Object#finalize()
    */
+  @Override
   protected void finalize() throws Throwable
   {
     // really make sure we have no buried refs left.