Jalview 2.6 source licence
[jalview.git] / src / jalview / gui / Jalview2XML.java
index db53d00..b28ed0e 100755 (executable)
@@ -1,27 +1,28 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
- * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
+ * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
  * 
- * This program 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 2
- * of the License, or (at your option) any later version.
+ * This file is part of Jalview.
  * 
- * This program 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.
+ * 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.
  * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ * 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/>.
  */
 package jalview.gui;
 
 import java.awt.Rectangle;
 import java.io.*;
+import java.lang.reflect.InvocationTargetException;
 import java.net.*;
 import java.util.*;
+import java.util.Map.Entry;
 import java.util.jar.*;
 
 import javax.swing.*;
@@ -401,19 +402,19 @@ public class Jalview2XML
    * JarOutputStream
    * 
    * @param ap
-   *                panel to create jalview model for
+   *          panel to create jalview model for
    * @param fileName
-   *                name of alignment panel written to output stream
+   *          name of alignment panel written to output stream
    * @param jout
-   *                jar output stream
+   *          jar output stream
    * @param out
-   *                jar entry name
+   *          jar entry name
    */
   public JalviewModel SaveState(AlignmentPanel ap, String fileName,
           JarOutputStream jout)
   {
     initSeqRefs();
-
+    Vector jmolViewIds = new Vector(); //
     Vector userColours = new Vector();
 
     AlignViewport av = ap.av;
@@ -574,41 +575,78 @@ public class Jalview2XML
           AppJmol jmol;
           // This must have been loaded, is it still visible?
           JInternalFrame[] frames = Desktop.desktop.getAllFrames();
+          String matchedFile = null;
           for (int f = frames.length - 1; f > -1; f--)
           {
             if (frames[f] instanceof AppJmol)
             {
+              // TODO: revise schema to allow many:one PDB id binding to viewer
               jmol = (AppJmol) frames[f];
-              if (!jmol.pdbentry.getId().equals(entry.getId()) 
-                      && !(entry.getId().length()>4 
-                              && entry.getId().startsWith(jmol.pdbentry.getId())))
-                continue;
-
-              StructureState state = new StructureState();
-              state.setVisible(true);
-              state.setXpos(jmol.getX());
-              state.setYpos(jmol.getY());
-              state.setWidth(jmol.getWidth());
-              state.setHeight(jmol.getHeight());
-              state.setViewId(jmol.getViewId());
-              String statestring = jmol.viewer.getStateInfo();
-              if (state != null)
+              for (int peid = 0; peid < jmol.jmb.pdbentry.length; peid++)
               {
-                state.setContent(statestring.replaceAll("\n", ""));
-              }
-              for (int s = 0; s < jmol.sequence.length; s++)
-              {
-                if (jal.findIndex(jmol.sequence[s]) > -1)
+                if (!jmol.jmb.pdbentry[peid].getId().equals(entry.getId())
+                        && !(entry.getId().length() > 4 && entry
+                                .getId()
+                                .toLowerCase()
+                                .startsWith(
+                                        jmol.jmb.pdbentry[peid].getId()
+                                                .toLowerCase())))
+                  continue;
+                if (matchedFile == null)
                 {
-                  pdb.addStructureState(state);
+                  matchedFile = jmol.jmb.pdbentry[peid].getFile();
+                }
+                else if (!matchedFile.equals(jmol.jmb.pdbentry[peid]
+                        .getFile()))
+                {
+                  Cache.log
+                          .warn("Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
+                                  + jmol.jmb.pdbentry[peid].getFile());
+                  ; // record the
+                }
+                // file so we
+                // can get at it if the ID
+                // match is ambiguous (e.g.
+                // 1QIP==1qipA)
+                String statestring = jmol.jmb.viewer.getStateInfo();
+
+                for (int smap = 0; smap < jmol.jmb.sequence[peid].length; smap++)
+                {
+                  if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
+                  {
+                    StructureState state = new StructureState();
+                    state.setVisible(true);
+                    state.setXpos(jmol.getX());
+                    state.setYpos(jmol.getY());
+                    state.setWidth(jmol.getWidth());
+                    state.setHeight(jmol.getHeight());
+                    state.setViewId(jmol.getViewId());
+                    if (!jmolViewIds.contains(state.getViewId()))
+                    {
+                      // Make sure we only store a Jmol state once in each XML
+                      // document.
+                      jmolViewIds.addElement(state.getViewId());
+                      state.setContent(statestring.replaceAll("\n", ""));
+                    }
+                    else
+                    {
+                      state.setContent("# duplicate state");
+                    }
+                    pdb.addStructureState(state);
+                  }
                 }
               }
             }
           }
 
-          if (entry.getFile() != null)
+          if (matchedFile != null || entry.getFile() != null)
           {
-            pdb.setFile(entry.getFile());
+            if (entry.getFile() != null)
+            {
+              // use entry's file
+              matchedFile = entry.getFile();
+            }
+            pdb.setFile(matchedFile); // entry.getFile());
             if (pdbfiles == null)
             {
               pdbfiles = new Vector();
@@ -619,7 +657,7 @@ public class Jalview2XML
               pdbfiles.addElement(entry.getId());
               try
               {
-                File file = new File(entry.getFile());
+                File file = new File(matchedFile);
                 if (file.exists() && jout != null)
                 {
                   byte[] data = new byte[(int) file.length()];
@@ -679,9 +717,10 @@ public class Jalview2XML
         for (int p = 0; p < jac[i].aaWidth; p++)
         {
           Alcodon cmap = new Alcodon();
-          if (jac[i].codons[p]!=null)
+          if (jac[i].codons[p] != null)
           {
-            // Null codons indicate a gapped column in the translated peptide alignment. 
+            // Null codons indicate a gapped column in the translated peptide
+            // alignment.
             cmap.setPos1(jac[i].codons[p][0]);
             cmap.setPos2(jac[i].codons[p][1]);
             cmap.setPos3(jac[i].codons[p][2]);
@@ -696,7 +735,7 @@ public class Jalview2XML
           for (int m = 0; m < pmaps.length; m++)
           {
             AlcodMap alcmap = new AlcodMap();
-            alcmap.setDnasq(seqHash(dnas[m])); 
+            alcmap.setDnasq(seqHash(dnas[m]));
             alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
                     false));
             alc.addAlcodMap(alcmap);
@@ -751,6 +790,10 @@ public class Jalview2XML
     }
 
     // SAVE ANNOTATIONS
+    /**
+     * store forward refs from an annotationRow to any groups
+     */
+    IdentityHashMap groupRefs = new IdentityHashMap();
     if (jal.getAlignmentAnnotation() != null)
     {
       jalview.datamodel.AlignmentAnnotation[] aa = jal
@@ -767,15 +810,6 @@ public class Jalview2XML
 
         an.setId(aa[i].annotationId);
 
-        if (aa[i] == av.quality || aa[i] == av.conservation
-                || aa[i] == av.consensus)
-        {
-          an.setLabel(aa[i].label);
-          an.setGraph(true);
-          vamsasSet.addAnnotation(an);
-          continue;
-        }
-
         an.setVisible(aa[i].visible);
 
         an.setDescription(aa[i].description);
@@ -786,6 +820,30 @@ public class Jalview2XML
           // 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());
+        }
+        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);
+          // write a stub for this annotation - indicate presence of autocalc
+          // rows
+          an.setLabel(aa[i].label);
+          an.setGraph(true);
+          vamsasSet.addAnnotation(an);
+          continue;
+        }
 
         if (aa[i].graph > 0)
         {
@@ -834,9 +892,8 @@ public class Jalview2XML
             ae.setPosition(a);
             if (aa[i].annotations[a].secondaryStructure != ' '
                     && aa[i].annotations[a].secondaryStructure != '\0')
-              ae
-                      .setSecondaryStructure(aa[i].annotations[a].secondaryStructure
-                              + "");
+              ae.setSecondaryStructure(aa[i].annotations[a].secondaryStructure
+                      + "");
 
             if (aa[i].annotations[a].colour != null
                     && aa[i].annotations[a].colour != java.awt.Color.black)
@@ -854,7 +911,6 @@ public class Jalview2XML
         vamsasSet.addAnnotation(an);
       }
     }
-
     // SAVE GROUPS
     if (jal.getGroups() != null)
     {
@@ -868,9 +924,12 @@ public class Jalview2XML
                 .getGroups().elementAt(i);
         groups[i].setStart(sg.getStartRes());
         groups[i].setEnd(sg.getEndRes());
-        groups[i].setName(sg.getName()); // TODO later sequence group should
-        // specify IDs of sequences, not just
-        // names
+        groups[i].setName(sg.getName());
+        if (groupRefs.containsKey(sg))
+        {
+          // group has references so set it's ID field
+          groups[i].setId(groupRefs.get(sg).toString());
+        }
         if (sg.cs != null)
         {
           if (sg.cs.conservationApplied())
@@ -915,7 +974,10 @@ public class Jalview2XML
         groups[i].setTextCol1(sg.textColour.getRGB());
         groups[i].setTextCol2(sg.textColour2.getRGB());
         groups[i].setTextColThreshold(sg.thresholdTextColour);
-        groups[i].setShowUnconserved(sg.getShowunconserved());
+        groups[i].setShowUnconserved(sg.getShowNonconserved());
+        groups[i].setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
+        groups[i].setShowConsensusHistogram(sg.isShowConsensusHistogram());
+        groups[i].setShowSequenceLogo(sg.isShowSequenceLogo());
         for (int s = 0; s < sg.getSize(); s++)
         {
           jalview.datamodel.Sequence seq = (jalview.datamodel.Sequence) sg
@@ -930,8 +992,8 @@ public class Jalview2XML
     // /////////SAVE VIEWPORT
     Viewport view = new Viewport();
     view.setTitle(ap.alignFrame.getTitle());
-    view.setSequenceSetId(makeHashCode(av.getSequenceSetId(), av
-            .getSequenceSetId()));
+    view.setSequenceSetId(makeHashCode(av.getSequenceSetId(),
+            av.getSequenceSetId()));
     view.setId(av.getViewId());
     view.setViewName(av.viewName);
     view.setGatheredViews(av.gatherViewsHere);
@@ -1027,7 +1089,15 @@ public class Jalview2XML
     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();
@@ -1035,12 +1105,31 @@ public class Jalview2XML
       String[] renderOrder = ap.seqPanel.seqCanvas.getFeatureRenderer().renderOrder;
 
       Vector settingsAdded = new Vector();
+      Object gstyle = null;
+      GraduatedColor gcol = null;
       for (int ro = 0; ro < renderOrder.length; ro++)
       {
+        gstyle = ap.seqPanel.seqCanvas.getFeatureRenderer()
+                .getFeatureStyle(renderOrder[ro]);
         Setting setting = new Setting();
         setting.setType(renderOrder[ro]);
-        setting.setColour(ap.seqPanel.seqCanvas.getFeatureRenderer()
-                .getColour(renderOrder[ro]).getRGB());
+        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]));
@@ -1091,10 +1180,8 @@ public class Jalview2XML
         }
         Group g = new Group();
         g.setName(grp);
-        g
-                .setDisplay(((Boolean) ap.seqPanel.seqCanvas
-                        .getFeatureRenderer().featureGroups.get(grp))
-                        .booleanValue());
+        g.setDisplay(((Boolean) ap.seqPanel.seqCanvas.getFeatureRenderer().featureGroups
+                .get(grp)).booleanValue());
         fs.addGroup(g);
         groupsAdded.addElement(grp);
       }
@@ -1104,14 +1191,23 @@ public class Jalview2XML
 
     if (av.hasHiddenColumns)
     {
-      for (int c = 0; c < av.getColumnSelection().getHiddenColumns().size(); c++)
+      if (av.getColumnSelection() == null
+              || av.getColumnSelection().getHiddenColumns() == null)
       {
-        int[] region = (int[]) av.getColumnSelection().getHiddenColumns()
-                .elementAt(c);
-        HiddenColumns hc = new HiddenColumns();
-        hc.setStart(region[0]);
-        hc.setEnd(region[1]);
-        view.addHiddenColumns(hc);
+        warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
+      }
+      else
+      {
+        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);
+        }
       }
     }
 
@@ -1158,7 +1254,7 @@ public class Jalview2XML
    * exist, the result of the hashcode call for the object.
    * 
    * @param jvobj
-   *                jalview data object
+   *          jalview data object
    * @return unique ID for referring to jvobj
    */
   private String makeHashCode(Object jvobj, String altCode)
@@ -1189,7 +1285,7 @@ public class Jalview2XML
    * return local jalview object mapped to ID, if it exists
    * 
    * @param idcode
-   *                (may be null)
+   *          (may be null)
    * @return null or object bound to idcode
    */
   private Object retrieveExistingObj(String idcode)
@@ -1328,11 +1424,16 @@ public class Jalview2XML
   {
     String id = null;
     jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
-
+    boolean newucs = false;
     if (!userColours.contains(ucs))
     {
       userColours.add(ucs);
-
+      newucs = true;
+    }
+    id = "ucs" + userColours.indexOf(ucs);
+    if (newucs)
+    {
+      // actually create the scheme's entry in the XML model
       java.awt.Color[] colours = ucs.getColours();
       jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours();
       jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme();
@@ -1356,7 +1457,6 @@ public class Jalview2XML
         }
       }
 
-      id = "ucs" + userColours.indexOf(ucs);
       uc.setId(id);
       uc.setUserColourScheme(jbucs);
       jms.addUserColours(uc);
@@ -1420,8 +1520,8 @@ public class Jalview2XML
   /**
    * Load a jalview project archive from a jar file
    * 
-   * @param file -
-   *                HTTP URL or filename
+   * @param file
+   *          - HTTP URL or filename
    */
   public AlignFrame LoadJalviewAlign(final String file)
   {
@@ -1597,8 +1697,10 @@ public class Jalview2XML
               + ex + "\n");
     } catch (OutOfMemoryError e)
     {
-      new jalview.gui.OOMWarning("loading jalview XML file", e,
-              Desktop.instance);
+      // Don't use the OOM Window here
+      errorMessage = "Out of memory loading jalview XML file";
+      System.err.println("Out of memory whilst loading jalview XML file");
+      e.printStackTrace();
     }
 
     if (Desktop.instance != null)
@@ -1725,13 +1827,13 @@ public class Jalview2XML
    * Load alignment frame from jalview XML DOM object
    * 
    * @param object
-   *                DOM
+   *          DOM
    * @param file
-   *                filename source string
+   *          filename source string
    * @param loadTreesAndStructures
-   *                when false only create Viewport
+   *          when false only create Viewport
    * @param jprovider
-   *                data source provider
+   *          data source provider
    * @return alignment frame created from view stored in DOM
    */
   AlignFrame LoadFromObject(JalviewModel object, String file,
@@ -1905,14 +2007,17 @@ public class Jalview2XML
           Alcodon[] alcods = alc[i].getAlcodon();
           for (int p = 0; p < cf.codons.length; p++)
           {
-            if (alcods[p].hasPos1() && alcods[p].hasPos2() && alcods[p].hasPos3())
+            if (alcods[p].hasPos1() && alcods[p].hasPos2()
+                    && alcods[p].hasPos3())
             {
               // translated codons require three valid positions
               cf.codons[p] = new int[3];
               cf.codons[p][0] = (int) alcods[p].getPos1();
               cf.codons[p][1] = (int) alcods[p].getPos2();
               cf.codons[p][2] = (int) alcods[p].getPos3();
-            } else {
+            }
+            else
+            {
               cf.codons[p] = null;
             }
           }
@@ -1951,6 +2056,10 @@ public class Jalview2XML
     // ////////////////////////////////
     // LOAD ANNOTATIONS
     boolean hideQuality = true, hideConservation = true, hideConsensus = true;
+    /**
+     * store any annotations which forward reference a group's ID
+     */
+    Hashtable groupAnnotRefs = new Hashtable();
 
     if (vamsasSet.getAnnotationCount() > 0)
     {
@@ -2004,10 +2113,11 @@ public class Jalview2XML
 
             anot[ae[aa].getPosition()] = new jalview.datamodel.Annotation(
 
-            ae[aa].getDisplayCharacter(), ae[aa].getDescription(), (ae[aa]
-                    .getSecondaryStructure() == null || ae[aa]
-                    .getSecondaryStructure().length() == 0) ? ' ' : ae[aa]
-                    .getSecondaryStructure().charAt(0), ae[aa].getValue()
+            ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
+                    (ae[aa].getSecondaryStructure() == null || ae[aa]
+                            .getSecondaryStructure().length() == 0) ? ' '
+                            : ae[aa].getSecondaryStructure().charAt(0),
+                    ae[aa].getValue()
 
             );
             // JBPNote: Consider verifying dataflow for IO of secondary
@@ -2017,8 +2127,8 @@ public class Jalview2XML
             // {
             // anot[ae[aa].getPosition()].displayCharacter = "";
             // }
-            anot[ae[aa].getPosition()].colour = new java.awt.Color(ae[aa]
-                    .getColour());
+            anot[ae[aa].getPosition()].colour = new java.awt.Color(
+                    ae[aa].getColour());
           }
         }
         jalview.datamodel.AlignmentAnnotation jaa = null;
@@ -2061,14 +2171,33 @@ public class Jalview2XML
             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)
+        {
+          groupAnnotRefs.put(an[i].getGroupRef(), jaa);
+        }
+
         if (an[i].hasScore())
         {
           jaa.setScore(an[i].getScore());
         }
-
         if (an[i].hasVisible())
           jaa.visible = an[i].getVisible();
 
+        if (an[i].hasCentreColLabels())
+          jaa.centreColLabels = an[i].getCentreColLabels();
+
+        if (an[i].hasScaleColLabels())
+        {
+          jaa.scaleColLabel = an[i].getScaleColLabels();
+        }
+        if (an[i].hasAutoCalculated() && an[i].isAutoCalculated())
+        {
+          // newer files have an 'autoCalculated' flag and store calculation
+          // state in viewport properties
+          jaa.autoCalculated = true; // means annotation will be marked for
+          // update at end of load.
+        }
         al.addAnnotation(jaa);
       }
     }
@@ -2125,26 +2254,48 @@ public class Jalview2XML
                 groups[i].getDisplayText(), groups[i].getColourText(),
                 groups[i].getStart(), groups[i].getEnd());
 
-        sg
-                .setOutlineColour(new java.awt.Color(groups[i]
-                        .getOutlineColour()));
+        sg.setOutlineColour(new java.awt.Color(groups[i].getOutlineColour()));
 
         sg.textColour = new java.awt.Color(groups[i].getTextCol1());
         sg.textColour2 = new java.awt.Color(groups[i].getTextCol2());
-        sg.setShowunconserved(groups[i].hasShowUnconserved() ? groups[i].isShowUnconserved() : false);
+        sg.setShowNonconserved(groups[i].hasShowUnconserved() ? groups[i]
+                .isShowUnconserved() : false);
         sg.thresholdTextColour = groups[i].getTextColThreshold();
-
+        if (groups[i].hasShowConsensusHistogram())
+        {
+          sg.setShowConsensusHistogram(groups[i].isShowConsensusHistogram());
+        }
+        ;
+        if (groups[i].hasShowSequenceLogo())
+        {
+          sg.setshowSequenceLogo(groups[i].isShowSequenceLogo());
+        }
+        if (groups[i].hasIgnoreGapsinConsensus())
+        {
+          sg.setIgnoreGapsConsensus(groups[i].getIgnoreGapsinConsensus());
+        }
         if (groups[i].getConsThreshold() != 0)
         {
           jalview.analysis.Conservation c = new jalview.analysis.Conservation(
-                  "All", ResidueProperties.propHash, 3, sg
-                          .getSequences(null), 0, sg.getWidth() - 1);
+                  "All", ResidueProperties.propHash, 3,
+                  sg.getSequences(null), 0, sg.getWidth() - 1);
           c.calculate();
           c.verdict(false, 25);
           sg.cs.setConservation(c);
         }
 
+        if (groups[i].getId() != null && groupAnnotRefs.size() > 0)
+        {
+          // re-instate unique group/annotation row reference
+          jalview.datamodel.AlignmentAnnotation jaa = (jalview.datamodel.AlignmentAnnotation) groupAnnotRefs
+                  .get(groups[i].getId());
+          if (jaa != null)
+          {
+            jaa.groupRef = sg;
+          }
+        }
         al.addGroup(sg);
+
       }
     }
 
@@ -2238,17 +2389,20 @@ public class Jalview2XML
           TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
           if (tp == null)
           {
-            tp = af.ShowNewickTree(new jalview.io.NewickFile(tree
-                    .getNewick()), tree.getTitle(), tree.getWidth(), tree
-                    .getHeight(), tree.getXpos(), tree.getYpos());
+            tp = af.ShowNewickTree(
+                    new jalview.io.NewickFile(tree.getNewick()),
+                    tree.getTitle(), tree.getWidth(), tree.getHeight(),
+                    tree.getXpos(), tree.getYpos());
             if (tree.getId() != null)
             {
-
+              // perhaps bind the tree id to something ?
             }
           }
           else
           {
             // update local tree attributes ?
+            // TODO: should check if tp has been manipulated by user - if so its
+            // settings shouldn't be modified
             tp.setTitle(tree.getTitle());
             tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(), tree
                     .getWidth(), tree.getHeight()));
@@ -2259,9 +2413,10 @@ public class Jalview2XML
             tp.treeCanvas.ap = ap; // af.alignPanel;
 
           }
-         if (tp==null)
+          if (tp == null)
           {
-            warn("There was a problem recovering stored Newick tree: \n"+tree.getNewick());
+            warn("There was a problem recovering stored Newick tree: \n"
+                    + tree.getNewick());
             continue;
           }
 
@@ -2300,6 +2455,10 @@ public class Jalview2XML
     // //LOAD STRUCTURES
     if (loadTreesAndStructures)
     {
+      // run through all PDB ids on the alignment, and collect mappings between
+      // jmol view ids and all sequences referring to it
+      Hashtable<String, Object[]> jmolViewIds = new Hashtable();
+
       for (int i = 0; i < JSEQ.length; i++)
       {
         if (JSEQ[i].getPdbidsCount() > 0)
@@ -2324,93 +2483,274 @@ public class Jalview2XML
               int y = ids[p].getStructureState(s).getYpos();
               int width = ids[p].getStructureState(s).getWidth();
               int height = ids[p].getStructureState(s).getHeight();
-              AppJmol comp = null;
-              JInternalFrame[] frames = null;
-              do
+
+              // Probably don't need to do this anymore...
+              // Desktop.desktop.getComponentAt(x, y);
+              // TODO: NOW: check that this recovers the PDB file correctly.
+              String pdbFile = loadPDBFile(jprovider, ids[p].getId());
+              jalview.datamodel.SequenceI seq = (jalview.datamodel.SequenceI) seqRefIds
+                      .get(JSEQ[i].getId() + "");
+              if (sviewid == null)
               {
-                try
-                {
-                  frames = Desktop.desktop.getAllFrames();
-                } catch (ArrayIndexOutOfBoundsException e)
-                {
-                  // occasional No such child exceptions are thrown here...
-                  frames = null;
-                  try
-                  {
-                    Thread.sleep(10);
-                  } catch (Exception f)
-                  {
-                  }
-                  ;
-                }
-              } while (frames == null);
-              // search for any Jmol windows already open from other
-              // alignment views that exactly match the stored structure state
-              for (int f = 0; comp == null && f < frames.length; f++)
+                sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width
+                        + "," + height;
+              }
+              if (!jmolViewIds.containsKey(sviewid))
+              {
+                jmolViewIds.put(sviewid, new Object[]
+                { new int[]
+                { x, y, width, height }, "",
+                    new Hashtable<String, Object[]>() });
+              }
+              // TODO: assemble String[] { pdb files }, String[] { id for each
+              // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
+              // seqs_file 2}} from hash
+              Object[] jmoldat = (Object[]) jmolViewIds.get(sviewid);
+              if (((String) jmoldat[1]).length() < ids[p]
+                      .getStructureState(s).getContent().length())
               {
-                if (frames[f] instanceof AppJmol)
                 {
-                  if (sviewid != null
-                          && ((AppJmol) frames[f]).getViewId().equals(
-                                  sviewid))
-                  {
-                    // post jalview 2.4 schema includes structure view id
-                    comp = (AppJmol) frames[f];
-                  }
-                  else if (frames[f].getX() == x && frames[f].getY() == y
-                          && frames[f].getHeight() == height
-                          && frames[f].getWidth() == width)
-                  {
-                    comp = (AppJmol) frames[f];
-                  }
+                  jmoldat[1] = ids[p].getStructureState(s).getContent();
                 }
               }
-              Desktop.desktop.getComponentAt(x, y);
+              Object[] seqstrmaps = (Object[]) ((Hashtable) jmoldat[2])
+                      .get(ids[p].getFile());
+              if (seqstrmaps == null)
+              {
+                ((Hashtable) jmoldat[2]).put(
+                        new File(ids[p].getFile()).toString(),
+                        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
+              }
+            }
+          }
+        }
+      }
+      {
 
-              String pdbFile = loadPDBFile(jprovider, ids[p].getId());
+        // Instantiate the associated Jmol views
+        for (Entry<String, Object[]> entry : jmolViewIds.entrySet())
+        {
+          String sviewid = entry.getKey();
+          Object[] svattrib = entry.getValue();
+          int[] geom = (int[]) svattrib[0];
+          String state = (String) svattrib[1];
+          Hashtable<String, Object[]> oldFiles = (Hashtable<String, Object[]>) svattrib[2];
 
-              jalview.datamodel.SequenceI[] seq = new jalview.datamodel.SequenceI[]
-              { (jalview.datamodel.SequenceI) seqRefIds.get(JSEQ[i].getId()
-                      + "") };
+          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>();
+          Vector<SequenceI[]> seqmaps = new Vector<SequenceI[]>();
+          Vector<String> pdbids = new Vector<String>();
 
-              if (comp == null)
+          // Search to see if we've already created this Jmol view
+          AppJmol comp = null;
+          JInternalFrame[] frames = null;
+          do
+          {
+            try
+            {
+              frames = Desktop.desktop.getAllFrames();
+            } catch (ArrayIndexOutOfBoundsException e)
+            {
+              // occasional No such child exceptions are thrown here...
+              frames = null;
+              try
               {
-                // create a new Jmol window
-                String state = ids[p].getStructureState(s).getContent();
-
-                StringBuffer newFileLoc = new StringBuffer(state.substring(
-                        0, state.indexOf("\"", state.indexOf("load")) + 1));
+                Thread.sleep(10);
+              } catch (Exception f)
+              {
+              }
+              ;
+            }
+          } while (frames == null);
+          // search for any Jmol windows already open from other
+          // alignment views that exactly match the stored structure state
+          for (int f = 0; comp == null && f < frames.length; f++)
+          {
+            if (frames[f] instanceof AppJmol)
+            {
+              if (sviewid != null
+                      && ((AppJmol) frames[f]).getViewId().equals(sviewid))
+              {
+                // post jalview 2.4 schema includes structure view id
+                comp = (AppJmol) frames[f];
+              }
+              else if (frames[f].getX() == x && frames[f].getY() == y
+                      && frames[f].getHeight() == height
+                      && frames[f].getWidth() == width)
+              {
+                comp = (AppJmol) frames[f];
+              }
+            }
+          }
 
-                newFileLoc.append(jpdb.getFile());
-                newFileLoc.append(state.substring(state.indexOf("\"", state
-                        .indexOf("load \"") + 6)));
+          if (comp == null)
+          {
+            // create a new Jmol window.
+            // First parse the Jmol state to translate filenames loaded into the
+            // view, and record the order in which files are shown in the Jmol
+            // view, so we can add the sequence mappings in same order.
+            StringBuffer newFileLoc = null;
+            int cp = 0, ncp, ecp;
+            while ((ncp = state.indexOf("load ", cp)) > -1)
+            {
+              if (newFileLoc == null)
+              {
+                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.
+            }
+            if (cp > 0)
+            {
+              // just append rest of state
+              newFileLoc.append(state.substring(cp));
+            }
+            else
+            {
+              System.err
+                      .print("Ignoring incomplete Jmol state for PDB ids: ");
+              newFileLoc = new StringBuffer(state);
+              newFileLoc.append("; load append ");
+              for (String id : oldFiles.keySet())
+              {
+                // add this and any other pdb files that should be present in
+                // the viewer
+                Object[] filedat = oldFiles.get(id);
+                String nfilename;
+                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(" \"");
+                newFileLoc.append((String) filedat[0]);
+                newFileLoc.append("\"");
 
-                new AppJmol(pdbFile, ids[p].getId(), seq, af.alignPanel,
-                        newFileLoc.toString(), new java.awt.Rectangle(x, y,
-                                width, height), sviewid);
+              }
+              newFileLoc.append(";");
+            }
 
+            if (newFileLoc != null)
+            {
+              int histbug = newFileLoc.indexOf("history = ");
+              histbug += 10;
+              int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";",
+                      histbug);
+              String val = (diff == -1) ? null : newFileLoc.substring(
+                      histbug, diff);
+              if (val != null && val.length() >= 4)
+              {
+                if (val.contains("e"))
+                {
+                  if (val.trim().equals("true"))
+                  {
+                    val = "1";
+                  }
+                  else
+                  {
+                    val = "0";
+                  }
+                  newFileLoc.replace(histbug, diff, val);
+                }
               }
-              else
-              // if (comp != null)
+              // 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
+                      .toArray(new String[pdbids.size()]);
+              final SequenceI[][] sq = (SequenceI[][]) seqmaps
+                      .toArray(new SequenceI[seqmaps.size()][]);
+              final String fileloc = newFileLoc.toString(), vid = sviewid;
+              final AlignFrame alf = af;
+              final java.awt.Rectangle rect = new java.awt.Rectangle(x, y,
+                      width, height);
+              try
+              {
+                javax.swing.SwingUtilities.invokeAndWait(new Runnable()
+                {
+                  public void run()
+                  {
+                    AppJmol sview=null;
+                    try {
+                      sview=new AppJmol(pdbf, id, sq, alf.alignPanel, fileloc,
+                    
+                            rect, vid);
+                    }
+                    catch (OutOfMemoryError ex)
+                    {
+                      new OOMWarning("restoring structure view for PDB id "+id,(OutOfMemoryError) ex.getCause());
+                      if (sview!=null && sview.isVisible())
+                      {
+                        sview.closeViewer();
+                        sview.setVisible(false);
+                        sview.dispose();
+                      }
+                    }
+                  }
+                });
+              } catch (InvocationTargetException ex)
+              {
+                warn("Unexpected error when opening Jmol view.",ex);
+                
+              } catch (InterruptedException e)
               {
-                // NOTE: if the jalview project is part of a shared session then
-                // view synchronization should/could be done here.
+                // e.printStackTrace();
+              }
+            }
 
-                // add mapping for this sequence to the already open Jmol
-                // instance (if it doesn't already exist)
-                // These
-                StructureSelectionManager.getStructureSelectionManager()
-                        .setMapping(seq, null, pdbFile,
-                                jalview.io.AppletFormatAdapter.FILE);
+          }
+          else
+          // if (comp != null)
+          {
+            // NOTE: if the jalview project is part of a shared session then
+            // view synchronization should/could be done here.
 
-                ((AppJmol) comp).addSequence(seq);
-              }
+            // add mapping for sequences in this view to an already open Jmol
+            // instance
+            for (String 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])
+                      .toArray(new SequenceI[0]);
+              StructureSelectionManager.getStructureSelectionManager()
+                      .setMapping(seq, null, pdbFile,
+                              jalview.io.AppletFormatAdapter.FILE);
+              ((AppJmol) comp).jmb.addSequenceForStructFile(pdbFile, seq);
             }
           }
         }
       }
     }
-
+    // and finally return.
     return af;
   }
 
@@ -2462,8 +2802,8 @@ public class Jalview2XML
 
         for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
         {
-          hidden.addSequence(al
-                  .getSequenceAt(JSEQ[s].getHiddenSequences(r)), false);
+          hidden.addSequence(
+                  al.getSequenceAt(JSEQ[s].getHiddenSequences(r)), false);
         }
         af.viewport.hideRepSequences(al.getSequenceAt(s), hidden);
       }
@@ -2506,8 +2846,8 @@ public class Jalview2XML
       af.viewport.viewName = view.getViewName();
       af.setInitialTabVisible();
     }
-    af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(), view
-            .getHeight());
+    af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
+            view.getHeight());
 
     af.viewport.setShowAnnotation(view.getShowAnnotation());
     af.viewport.setAbovePIDThreshold(view.getPidSelected());
@@ -2533,7 +2873,8 @@ public class Jalview2XML
     af.viewport.textColour = new java.awt.Color(view.getTextCol1());
     af.viewport.textColour2 = new java.awt.Color(view.getTextCol2());
     af.viewport.thresholdTextColour = view.getTextColThreshold();
-    af.viewport.setShowUnconserved(view.hasShowUnconserved() ? view.isShowUnconserved() : false);
+    af.viewport.setShowUnconserved(view.hasShowUnconserved() ? view
+            .isShowUnconserved() : false);
     af.viewport.setStartRes(view.getStartRes());
     af.viewport.setStartSeq(view.getStartSeq());
 
@@ -2548,85 +2889,91 @@ public class Jalview2XML
       else if (view.getBgColour().startsWith("Annotation"))
       {
         // int find annotation
-        for (int i = 0; i < af.viewport.alignment.getAlignmentAnnotation().length; i++)
+        if (af.viewport.alignment.getAlignmentAnnotation() != null)
         {
-          if (af.viewport.alignment.getAlignmentAnnotation()[i].label
-                  .equals(view.getAnnotationColours().getAnnotation()))
+          for (int i = 0; i < af.viewport.alignment
+                  .getAlignmentAnnotation().length; i++)
           {
-            if (af.viewport.alignment.getAlignmentAnnotation()[i]
-                    .getThreshold() == null)
+            if (af.viewport.alignment.getAlignmentAnnotation()[i].label
+                    .equals(view.getAnnotationColours().getAnnotation()))
             {
-              af.viewport.alignment.getAlignmentAnnotation()[i]
-                      .setThreshold(new jalview.datamodel.GraphLine(view
-                              .getAnnotationColours().getThreshold(),
-                              "Threshold", java.awt.Color.black)
-
-                      );
-            }
+              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)
 
-            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++)
+              if (view.getAnnotationColours().getColourScheme()
+                      .equals("None"))
               {
-                jalview.datamodel.SequenceGroup sg = (jalview.datamodel.SequenceGroup) al
-                        .getGroups().elementAt(g);
+                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());
+              }
 
-                if (sg.cs == null)
+              // Also use these settings for all the groups
+              if (al.getGroups() != null)
+              {
+                for (int g = 0; g < al.getGroups().size(); g++)
                 {
-                  continue;
-                }
+                  jalview.datamodel.SequenceGroup sg = (jalview.datamodel.SequenceGroup) al
+                          .getGroups().elementAt(g);
 
-                /*
-                 * 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());
-                }
+                  if (sg.cs == null)
+                  {
+                    continue;
+                  }
+
+                  /*
+                   * 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;
             }
 
-            break;
           }
-
         }
       }
       else
@@ -2657,6 +3004,65 @@ public class Jalview2XML
     {
       af.viewport.showSequenceFeatures = true;
     }
+    if (view.hasCentreColumnLabels())
+    {
+      af.viewport.setCentreColumnLabels(view.getCentreColumnLabels());
+    }
+    if (view.hasIgnoreGapsinConsensus())
+    {
+      af.viewport.ignoreGapsInConsensusCalculation = view
+              .getIgnoreGapsinConsensus();
+    }
+    if (view.hasFollowHighlight())
+    {
+      af.viewport.followHighlight = view.getFollowHighlight();
+    }
+    if (view.hasFollowSelection())
+    {
+      af.viewport.followSelection = view.getFollowSelection();
+    }
+    if (view.hasShowConsensusHistogram())
+    {
+      af.viewport.setShowConsensusHistogram(view
+              .getShowConsensusHistogram());
+    }
+    else
+    {
+      af.viewport.setShowConsensusHistogram(true);
+    }
+    if (view.hasShowSequenceLogo())
+    {
+      af.viewport.showSequenceLogo = view.getShowSequenceLogo();
+    }
+    else
+    {
+      af.viewport.showSequenceLogo = false;
+    }
+    if (view.hasShowDbRefTooltip())
+    {
+      af.viewport.setShowDbRefs(view.getShowDbRefTooltip());
+    }
+    if (view.hasShowNPfeatureTooltip())
+    {
+      af.viewport.setShowNpFeats(view.hasShowNPfeatureTooltip());
+    }
+    if (view.hasShowGroupConsensus())
+    {
+      af.viewport.setShowGroupConsensus(view.getShowGroupConsensus());
+    }
+    else
+    {
+      af.viewport.setShowGroupConsensus(false);
+    }
+    if (view.hasShowGroupConservation())
+    {
+      af.viewport.setShowGroupConservation(view.getShowGroupConservation());
+    }
+    else
+    {
+      af.viewport.setShowGroupConservation(false);
+    }
+
     // recover featre settings
     if (jms.getFeatureSettings() != null)
     {
@@ -2666,9 +3072,38 @@ public class Jalview2XML
       for (int fs = 0; fs < jms.getFeatureSettings().getSettingCount(); fs++)
       {
         Setting setting = jms.getFeatureSettings().getSetting(fs);
-
-        af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer().setColour(
-                setting.getType(), new java.awt.Color(setting.getColour()));
+        if (setting.hasMincolour())
+        {
+          GraduatedColor gc = setting.hasMin() ? new GraduatedColor(
+                  new java.awt.Color(setting.getMincolour()),
+                  new java.awt.Color(setting.getColour()),
+                  setting.getMin(), setting.getMax()) : new GraduatedColor(
+                  new java.awt.Color(setting.getMincolour()),
+                  new java.awt.Color(setting.getColour()), 0, 1);
+          if (setting.hasThreshold())
+          {
+            gc.setThresh(setting.getThreshold());
+            gc.setThreshType(setting.getThreshstate());
+          }
+          gc.setAutoScaled(true); // default
+          if (setting.hasAutoScale())
+          {
+            gc.setAutoScaled(setting.getAutoScale());
+          }
+          if (setting.hasColourByLabel())
+          {
+            gc.setColourByLabel(setting.getColourByLabel());
+          }
+          // and put in the feature colour table.
+          af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer().setColour(
+                  setting.getType(), gc);
+        }
+        else
+        {
+          af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer().setColour(
+                  setting.getType(),
+                  new java.awt.Color(setting.getColour()));
+        }
         renderOrder[fs] = setting.getType();
         if (setting.hasOrder())
           af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer().setOrder(
@@ -2705,8 +3140,9 @@ public class Jalview2XML
 
     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());
+    Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
+            view.getHeight());
+    af.alignPanel.updateAnnotation(false); // recompute any autoannotation
     return af;
   }
 
@@ -2786,6 +3222,8 @@ public class Jalview2XML
       SequenceI[] dsseqs = new SequenceI[dseqs.size()];
       dseqs.copyInto(dsseqs);
       ds = new jalview.datamodel.Alignment(dsseqs);
+      debug("Created new dataset " + vamsasSet.getDatasetId()
+              + " for alignment " + System.identityHashCode(al));
       addDatasetRef(vamsasSet.getDatasetId(), ds);
     }
     // set the dataset for the newly imported alignment.
@@ -2798,11 +3236,11 @@ public class Jalview2XML
   /**
    * 
    * @param vamsasSeq
-   *                sequence definition to create/merge dataset sequence for
+   *          sequence definition to create/merge dataset sequence for
    * @param ds
-   *                dataset alignment
+   *          dataset alignment
    * @param dseqs
-   *                vector to add new dataset sequence to
+   *          vector to add new dataset sequence to
    */
   private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
           AlignmentI ds, Vector dseqs)
@@ -2892,7 +3330,9 @@ public class Jalview2XML
   }
 
   java.util.Hashtable datasetIds = null;
+
   java.util.IdentityHashMap dataset2Ids = null;
+
   private Alignment getDatasetFor(String datasetId)
   {
     if (datasetIds == null)
@@ -2915,35 +3355,40 @@ public class Jalview2XML
     }
     datasetIds.put(datasetId, dataset);
   }
+
   /**
    * make a new dataset ID for this jalview dataset alignment
+   * 
    * @param dataset
    * @return
    */
   private String getDatasetIdRef(jalview.datamodel.Alignment dataset)
   {
-    if (dataset.getDataset()!=null)
+    if (dataset.getDataset() != null)
     {
       warn("Serious issue!  Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
     }
-    String datasetId=makeHashCode(dataset, null);
-    if (datasetId==null)
+    String datasetId = makeHashCode(dataset, null);
+    if (datasetId == null)
     {
       // make a new datasetId and record it
       if (dataset2Ids == null)
       {
         dataset2Ids = new IdentityHashMap();
-      } else {
+      }
+      else
+      {
         datasetId = (String) dataset2Ids.get(dataset);
       }
-      if (datasetId==null)
+      if (datasetId == null)
       {
-        datasetId = "ds"+dataset2Ids.size()+1;
-        dataset2Ids.put(dataset,datasetId);
+        datasetId = "ds" + dataset2Ids.size() + 1;
+        dataset2Ids.put(dataset, datasetId);
       }
     }
     return datasetId;
   }
+
   private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
   {
     for (int d = 0; d < sequence.getDBRefCount(); d++)
@@ -2987,7 +3432,7 @@ public class Jalview2XML
       MappingChoice mc = m.getMappingChoice();
       if (mc.getDseqFor() != null)
       {
-        String dsfor = ""+mc.getDseqFor();
+        String dsfor = "" + mc.getDseqFor();
         if (seqRefIds.containsKey(dsfor))
         {
           /**
@@ -3030,8 +3475,8 @@ public class Jalview2XML
           /**
            * make a new dataset sequence and add it to refIds hash
            */
-          djs = new jalview.datamodel.Sequence(ms.getName(), ms
-                  .getSequence());
+          djs = new jalview.datamodel.Sequence(ms.getName(),
+                  ms.getSequence());
           djs.setStart(jmap.getMap().getToLowest());
           djs.setEnd(jmap.getMap().getToHighest());
           djs.setVamsasId(uniqueSetSuffix + sqid);
@@ -3063,9 +3508,12 @@ public class Jalview2XML
     else
     {
       uniqueSetSuffix = "";
-      jm.getJalviewModelSequence().getViewport(0).setId(null); // we don't overwrite the view we just copied
+      jm.getJalviewModelSequence().getViewport(0).setId(null); // we don't
+      // overwrite the
+      // view we just
+      // copied
     }
-    if (this.frefedSequence==null)
+    if (this.frefedSequence == null)
     {
       frefedSequence = new Vector();
     }
@@ -3077,8 +3525,9 @@ 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) {
+     * 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]; } } }
      */
@@ -3139,6 +3588,34 @@ public class Jalview2XML
     }
   }
 
+  private void debug(String string)
+  {
+    debug(string, null);
+  }
+
+  private void debug(String msg, Exception e)
+  {
+    if (Cache.log != null)
+    {
+      if (e != null)
+      {
+        Cache.log.debug(msg, e);
+      }
+      else
+      {
+        Cache.log.debug(msg);
+      }
+    }
+    else
+    {
+      System.err.println("Warning: " + msg);
+      if (e != null)
+      {
+        e.printStackTrace();
+      }
+    }
+  }
+
   /**
    * set the object to ID mapping tables used to write/recover objects and XML
    * ID strings for the jalview project. If external tables are provided then
@@ -3147,9 +3624,9 @@ public class Jalview2XML
    * alignment objects containing dataset sequences
    * 
    * @param vobj2jv
-   *                Map from ID strings to jalview datamodel
+   *          Map from ID strings to jalview datamodel
    * @param jv2vobj
-   *                Map from jalview datamodel to ID strings
+   *          Map from jalview datamodel to ID strings
    * 
    * 
    */