Ensure 'None' translates into no colour scheme applied
[jalview.git] / src / jalview / gui / Jalview2XML.java
index e57e748..97dfefd 100755 (executable)
@@ -48,10 +48,55 @@ import jalview.structure.StructureSelectionManager;
  */
 public class Jalview2XML
 {
-
-  Hashtable seqRefIds = null;
+  /**
+   * create/return unique hash string for sq
+   * @param sq
+   * @return new or existing unique string for sq
+   */
+  String seqHash(SequenceI sq)
+  {
+    if (seqsToIds==null)
+    {
+      initSeqRefs();
+    }
+    if (seqsToIds.containsKey(sq))
+    {
+      return (String) seqsToIds.get(sq);
+    } else {
+      //         create sequential key
+      String key = "sq"+(seqsToIds.size()+1);
+      seqsToIds.put(sq, key);
+      return key;
+    }
+  }
+  void clearSeqRefs()
+  {
+    seqRefIds.clear();
+    seqsToIds.clear();
+  }
+  void initSeqRefs()
+  {
+    if (seqsToIds==null)
+    {
+      seqsToIds = new IdentityHashMap();
+    }
+    if (seqRefIds==null)
+    {
+      seqRefIds = new Hashtable();
+    }
+  }
+  java.util.IdentityHashMap seqsToIds = null; // SequenceI->key resolution
+  java.util.Hashtable seqRefIds = null; // key->SequenceI resolution
 
   Vector frefedSequence = null;
+  boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
+  public Jalview2XML()
+  {
+  }
+  public Jalview2XML(boolean raiseGUI)
+  {
+    this.raiseGUI = raiseGUI;
+  }
 
   public void resolveFrefedSequences()
   {
@@ -131,8 +176,8 @@ public class Jalview2XML
 
       //NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
       ////////////////////////////////////////////////////
-      PrintWriter out = new PrintWriter(new OutputStreamWriter(jout,
-              "UTF-8"));
+      //NOTE ALSO new PrintWriter must be used for each new JarEntry
+      PrintWriter out = null;
 
       Vector shortNames = new Vector();
 
@@ -177,17 +222,21 @@ public class Jalview2XML
           {
             AlignmentPanel apanel = (AlignmentPanel) af.alignPanels
                     .elementAt(ap);
+            String fileName = apSize == 1 ? shortName : ap + shortName;
+            if (!fileName.endsWith(".xml"))
+            {
+              fileName = fileName + ".xml";
+            }
 
-            SaveState(apanel, apSize == 1 ? shortName : ap + shortName,
-                    jout, out);
+            SaveState(apanel, fileName, jout);
           }
         }
       }
-
-      out.close();
+      try { jout.flush(); } catch (Exception foo) {};
       jout.close();
     } catch (Exception ex)
     {
+      //TODO: inform user of the problem - they need to know if their data was not saved !
       ex.printStackTrace();
     }
   }
@@ -201,17 +250,19 @@ public class Jalview2XML
       int ap, apSize = af.alignPanels.size();
       FileOutputStream fos = new FileOutputStream(jarFile);
       JarOutputStream jout = new JarOutputStream(fos);
-      PrintWriter out = new PrintWriter(new OutputStreamWriter(jout,
-              "UTF-8"));
       for (ap = 0; ap < apSize; ap++)
       {
         AlignmentPanel apanel = (AlignmentPanel) af.alignPanels
                 .elementAt(ap);
-
-        SaveState(apanel, apSize == 1 ? fileName : fileName + ap, jout, out);
+        String jfileName = apSize == 1 ? fileName : fileName + ap;
+        if (!jfileName.endsWith(".xml"))
+        {
+          jfileName = jfileName + ".xml";
+        }
+        SaveState(apanel, jfileName, jout);
       }
 
-      out.close();
+      try { jout.flush(); } catch (Exception foo) {};
       jout.close();
       return true;
     } catch (Exception ex)
@@ -222,22 +273,19 @@ public class Jalview2XML
   }
 
   /**
-   * DOCUMENT ME!
+   * create a JalviewModel from an algnment view and marshall it
+   * to a JarOutputStream
    *
-   * @param af DOCUMENT ME!
-   * @param timeStamp DOCUMENT ME!
-   * @param fileName DOCUMENT ME!
-   * @param jout DOCUMENT ME!
-   * @param out DOCUMENT ME!
+   * @param ap panel to create jalview model for
+   * @param fileName name of alignment panel written to output stream
+   * @param jout jar output stream
+   * @param out jar entry name
    */
   public JalviewModel SaveState(AlignmentPanel ap, String fileName,
-          JarOutputStream jout, PrintWriter out)
+          JarOutputStream jout)
   {
-    if (seqRefIds == null)
-    {
-      seqRefIds = new Hashtable();
-    }
-
+    initSeqRefs();
+    
     Vector userColours = new Vector();
 
     AlignViewport av = ap.av;
@@ -282,22 +330,29 @@ public class Jalview2XML
     JSeq jseq;
 
     //SAVE SEQUENCES
-    int id = 0;
+    String id = "";
     jalview.datamodel.SequenceI jds;
     for (int i = 0; i < jal.getHeight(); i++)
     {
       jds = jal.getSequenceAt(i);
-      id = jds.hashCode();
-
-      if (seqRefIds.get(id + "") != null)
-      {
-
+      id = seqHash(jds);
+
+      if (seqRefIds.get(id) != null)
+      {
+        // This happens for two reasons: 1. multiple views are being serialised. 2. the hashCode has collided with another sequence's code. This DOES HAPPEN! (PF00072.15.stk does this)
+        // JBPNote: Uncomment to debug writing out of files that do not read back in due to ArrayOutOfBoundExceptions.
+        //System.err.println("vamsasSeq backref: "+id+"");
+        //System.err.println(jds.getName()+" "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
+        //System.err.println("Hashcode: "+seqHash(jds));
+        //SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
+        //System.err.println(rsq.getName()+" "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
+        //System.err.println("Hashcode: "+seqHash(rsq));
       }
       else
       {
         vamsasSeq = createVamsasSequence(id, jds);
         vamsasSet.addSequence(vamsasSeq);
-        seqRefIds.put(id + "", jal.getSequenceAt(i));
+        seqRefIds.put(id, jds);
       }
 
       jseq = new JSeq();
@@ -305,7 +360,7 @@ public class Jalview2XML
       jseq.setEnd(jds.getEnd());
       jseq.setColour(av.getSequenceColour(jds).getRGB());
 
-      jseq.setId(id);
+      jseq.setId(id); // jseq id should be a string not a number
 
       if (av.hasHiddenRows)
       {
@@ -440,6 +495,7 @@ public class Jalview2XML
 
                   DataOutputStream dout = new DataOutputStream(jout);
                   dout.write(data, 0, data.length);
+                  dout.flush();
                   jout.closeEntry();
                 }
               } catch (Exception ex)
@@ -485,7 +541,7 @@ public class Jalview2XML
       {
         AlcodonFrame alc = new AlcodonFrame();
         vamsasSet.addAlcodonFrame(alc);
-        for (int p = 0; p < jac[i].aaWidth; i++)
+        for (int p = 0; p < jac[i].aaWidth; p++)
         {
           Alcodon cmap = new Alcodon();
           cmap.setPos1(jac[i].codons[p][0]);
@@ -721,7 +777,7 @@ public class Jalview2XML
         {
           jalview.datamodel.Sequence seq = (jalview.datamodel.Sequence) sg
                   .getSequenceAt(s);
-          groups[i].addSeq(seq.hashCode());
+          groups[i].addSeq(seqHash(seq));
         }
       }
 
@@ -918,47 +974,47 @@ public class Jalview2XML
     object.setJalviewModelSequence(jms);
     object.getVamsasModel().addSequenceSet(vamsasSet);
 
-    if (out != null)
+    if (jout!=null && fileName!=null)
     {
-      //We may not want to right the object to disk,
+      //We may not want to write the object to disk,
       //eg we can copy the alignViewport to a new view object
       //using save and then load
       try
       {
-        if (!fileName.endsWith(".xml"))
-        {
-          fileName = fileName + ".xml";
-        }
-
         JarEntry entry = new JarEntry(fileName);
         jout.putNextEntry(entry);
-
-        object.marshal(out);
+        PrintWriter pout = new PrintWriter(new OutputStreamWriter(jout,
+        "UTF-8"));
+        org.exolab.castor.xml.Marshaller marshaller = new org.exolab.castor.xml.Marshaller(pout);
+        marshaller.marshal(object);
+        pout.flush();
+        jout.closeEntry();
       } catch (Exception ex)
       {
+        // TODO: raise error in GUI if marshalling failed.
         ex.printStackTrace();
       }
     }
     return object;
   }
 
-  private Sequence createVamsasSequence(int id, SequenceI jds)
+  private Sequence createVamsasSequence(String id, SequenceI jds)
   {
     return createVamsasSequence(true, id, jds, null);
   }
 
-  private Sequence createVamsasSequence(boolean recurse, int id,
+  private Sequence createVamsasSequence(boolean recurse, String id,
           SequenceI jds, SequenceI parentseq)
   {
     Sequence vamsasSeq = new Sequence();
-    vamsasSeq.setId(id + "");
+    vamsasSeq.setId(id);
     vamsasSeq.setName(jds.getName());
     vamsasSeq.setSequence(jds.getSequenceAsString());
     vamsasSeq.setDescription(jds.getDescription());
     jalview.datamodel.DBRefEntry[] dbrefs = null;
     if (jds.getDatasetSequence() != null)
     {
-      vamsasSeq.setDsseqid(jds.getDatasetSequence().hashCode() + "");
+      vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
       if (jds.getDatasetSequence().getDBRef() != null)
       {
         dbrefs = jds.getDatasetSequence().getDBRef();
@@ -966,9 +1022,10 @@ public class Jalview2XML
     }
     else
     {
+      vamsasSeq.setDsseqid(id); // so we can tell which sequences really are dataset sequences only
       dbrefs = jds.getDBRef();
     }
-    if (jds.getDBRef() != null)
+    if (dbrefs != null)
     {
       for (int d = 0; d < dbrefs.length; d++)
       {
@@ -1022,24 +1079,24 @@ public class Jalview2XML
                 && (parentseq != jmp.getTo() || parentseq
                         .getDatasetSequence() != jmp.getTo()))
         {
-          mpc.setSequence(createVamsasSequence(false, jmp.getTo()
-                  .hashCode(), jmp.getTo(), jds));
+          mpc.setSequence(createVamsasSequence(false, seqHash(jmp.getTo())
+                  , jmp.getTo(), jds));
         }
         else
         {
-          long jmpid = 0;
+          String jmpid = "";
           SequenceI ps = null;
           if (parentseq != jmp.getTo()
                   && parentseq.getDatasetSequence() != jmp.getTo())
           {
             // chaining dbref rather than a handshaking one
-            jmpid = (ps = jmp.getTo()).hashCode();
+            jmpid = seqHash(ps = jmp.getTo());
           }
           else
           {
-            jmpid = (ps = parentseq).hashCode();
+            jmpid = seqHash(ps = parentseq);
           }
-          mpc.setDseqFor("" + jmpid);
+          mpc.setDseqFor(jmpid);
           if (!seqRefIds.containsKey(mpc.getDseqFor()))
           {
             jalview.bin.Cache.log.debug("creatign new DseqFor ID");
@@ -1224,9 +1281,22 @@ public class Jalview2XML
               + ex + "\n");
     } catch (Exception ex)
     {
+      System.err.println("Parsing as Jalview Version 2 file failed.");
+      ex.printStackTrace(System.err);
+      
       //Is Version 1 Jar file?
-      af = new Jalview2XML_V1().LoadJalviewAlign(file);
+      try {
+        af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(file);
+      } catch (Exception ex2) {
+        System.err.println("Exception whilst loading as jalviewXMLV1:");
+        ex2.printStackTrace();
+        af = null;
+      }
 
+      if (Desktop.instance != null)
+      {
+        Desktop.instance.stopLoading();
+      }
       if (af != null)
       {
         System.out.println("Successfully loaded archive file");
@@ -1252,15 +1322,20 @@ public class Jalview2XML
     if (errorMessage != null)
     {
       final String finalErrorMessage = errorMessage;
-      javax.swing.SwingUtilities.invokeLater(new Runnable()
-      {
-        public void run()
+      if (raiseGUI)
+        {
+        javax.swing.SwingUtilities.invokeLater(new Runnable()
+        {
+          public void run()
         {
           JOptionPane.showInternalMessageDialog(Desktop.desktop,
                   finalErrorMessage, "Error loading Jalview file",
                   JOptionPane.WARNING_MESSAGE);
         }
       });
+        } else {
+          System.err.println("Problem loading Jalview file: "+errorMessage);
+        }
     }
 
     return af;
@@ -1305,6 +1380,7 @@ public class Jalview2XML
       {
         out.println(data);
       }
+      try { out.flush(); } catch (Exception foo) {};
       out.close();
 
       alreadyLoadedPDB.put(pdbId, outFile.getAbsolutePath());
@@ -1339,6 +1415,7 @@ public class Jalview2XML
     boolean multipleView = false;
 
     JSeq[] JSEQ = object.getJalviewModelSequence().getJSeq();
+    int vi=0; // counter in vamsasSeq array
     for (int i = 0; i < JSEQ.length; i++)
     {
       String seqId = JSEQ[i].getId() + "";
@@ -1350,14 +1427,15 @@ public class Jalview2XML
       }
       else
       {
-        jseq = new jalview.datamodel.Sequence(vamsasSeq[i].getName(),
-                vamsasSeq[i].getSequence());
-        jseq.setDescription(vamsasSeq[i].getDescription());
+        jseq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
+                vamsasSeq[vi].getSequence());
+        jseq.setDescription(vamsasSeq[vi].getDescription());
         jseq.setStart(JSEQ[i].getStart());
         jseq.setEnd(JSEQ[i].getEnd());
         jseq.setVamsasId(uniqueSetSuffix + seqId);
-        seqRefIds.put(vamsasSeq[i].getId(), jseq);
+        seqRefIds.put(vamsasSeq[vi].getId()+"", jseq);
         tmpseqs.add(jseq);
+        vi++;
       }
 
       if (JSEQ[i].getHidden())
@@ -1399,7 +1477,6 @@ public class Jalview2XML
     {
       // older jalview projects do not have a dataset id.
       al.setDataset(null);
-      // addDatasetRef(al.getDataset());
     }
     else
     {
@@ -1440,7 +1517,10 @@ public class Jalview2XML
             al.getSequenceAt(i).getDatasetSequence().addSequenceFeature(sf);
           }
         }
-
+        if (vamsasSeq[i].getDBRefCount() > 0)
+        {
+          addDBRefs(al.getSequenceAt(i).getDatasetSequence(), vamsasSeq[i]);
+        }
         if (JSEQ[i].getPdbidsCount() > 0)
         {
           Pdbids[] ids = JSEQ[i].getPdbids();
@@ -1464,10 +1544,6 @@ public class Jalview2XML
             al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
           }
         }
-        if (vamsasSeq[i].getDBRefCount() > 0)
-        {
-          addDBRefs(al.getSequenceAt(i).getDatasetSequence(), vamsasSeq[i]);
-        }
       }
     }
 
@@ -1573,9 +1649,14 @@ public class Jalview2XML
                     .getSecondaryStructure() == null || ae[aa]
                     .getSecondaryStructure().length() == 0) ? ' ' : ae[aa]
                     .getSecondaryStructure().charAt(0), ae[aa].getValue()
-
+                    
             );
-
+            // JBPNote: Consider verifying dataflow for IO of secondary structure annotation read from Stockholm files
+            // this was added to try to ensure that 
+            //if (anot[ae[aa].getPosition()].secondaryStructure>' ')
+            //{
+            //  anot[ae[aa].getPosition()].displayCharacter = "";
+            //}
             anot[ae[aa].getPosition()].colour = new java.awt.Color(ae[aa]
                     .getColour());
           }
@@ -2070,8 +2151,21 @@ public class Jalview2XML
               int height = ids[p].getStructureState(s).getHeight();
 
               java.awt.Component comp = null;
-
-              JInternalFrame[] frames = Desktop.desktop.getAllFrames();
+              
+              JInternalFrame[] frames = null;
+              do {
+                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);
               for (int f = 0; f < frames.length; f++)
               {
                 if (frames[f] instanceof AppJmol)
@@ -2139,80 +2233,114 @@ public class Jalview2XML
     for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
     {
       Sequence vamsasSeq = vamsasSet.getSequence(i);
-      jalview.datamodel.Sequence sq = null;
-      String sqid = vamsasSeq.getDsseqid();
+      ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs);
+    }
+    // create a new dataset
+    if (ds == null)
+    {
+      SequenceI[] dsseqs = new SequenceI[dseqs.size()];
+      dseqs.copyInto(dsseqs);
+      ds = new jalview.datamodel.Alignment(dsseqs);
+      addDatasetRef(vamsasSet.getDatasetId(), ds);
+    }
+    // set the dataset for the newly imported alignment.
+    if (al.getDataset() == null)
+    {
+      al.setDataset(ds);
+    }
+  }
+  
+
+  /**
+   * 
+   * @param vamsasSeq sequence definition to create/merge dataset sequence for
+   * @param ds dataset alignment 
+   * @param dseqs vector to add new dataset sequence to
+   */
+  private void ensureJalviewDatasetSequence(Sequence vamsasSeq, AlignmentI ds, Vector dseqs)
+  {
+    jalview.datamodel.Sequence sq = (jalview.datamodel.Sequence) seqRefIds.get(vamsasSeq.getId());
+    jalview.datamodel.SequenceI dsq = null;
+    if (sq!=null && sq.getDatasetSequence()!=null)
+    {
+      dsq = (jalview.datamodel.SequenceI) sq.getDatasetSequence();
+    }
+    
+    String sqid = vamsasSeq.getDsseqid();
+    if (dsq==null)
+    {
+      // need to create or add a new dataset sequence reference to this sequence
       if (sqid != null)
       {
-        sq = (jalview.datamodel.Sequence) seqRefIds.get(vamsasSeq
-                .getDsseqid());
+        dsq = (jalview.datamodel.SequenceI) seqRefIds.get(sqid);
       }
-      if (sq == null)
+      // check again
+      if (dsq == null)
       {
-        sq = (jalview.datamodel.Sequence) seqRefIds.get(vamsasSeq.getId());
-        jalview.datamodel.SequenceI dsq = sq.createDatasetSequence();
+        // make a new dataset sequence
+        dsq = sq.createDatasetSequence();
         if (sqid == null)
         {
           // make up a new dataset reference for this sequence
-          sqid = "" + dsq.hashCode();
+          sqid = seqHash(dsq);
         }
-        ((SequenceI) dsq).setVamsasId(uniqueSetSuffix + sqid);
+        dsq.setVamsasId(uniqueSetSuffix + sqid);
         seqRefIds.put(sqid, dsq);
         if (ds == null)
         {
-          dseqs.addElement(dsq);
+          if (dseqs!=null)
+          {
+            dseqs.addElement(dsq);
+          }
         }
         else
         {
           ds.addSequence(dsq);
         }
-       
+      } else {
+        if (sq!=dsq)
+        {  // make this dataset sequence sq's dataset sequence
+          sq.setDatasetSequence(dsq);
+        }
       }
-      // TODO: refactor: This is a low-level sequence operation - effectively merging one dataset sequence into another.
-      // check that dataset sequence really is the union of all references to it
-      boolean pre = sq.getStart() < sq.getDatasetSequence().getStart();
-      boolean post = sq.getEnd() > sq.getDatasetSequence().getEnd();
-      if (pre || post)
+    }
+    // TODO: refactor this as a merge dataset sequence function
+    // now check that sq (the dataset sequence) sequence really is the union of all references to it
+    //boolean pre = sq.getStart() < dsq.getStart();
+    //boolean post = sq.getEnd() > dsq.getEnd();
+    //if (pre || post)
+    if (sq!=dsq)
+    {
+      StringBuffer sb = new StringBuffer();
+      String newres = jalview.analysis.AlignSeq.extractGaps(
+              jalview.util.Comparison.GapChars, sq.getSequenceAsString());
+      if (!newres.equalsIgnoreCase(dsq.getSequenceAsString()) && newres.length()>dsq.getLength())
       {
-        SequenceI dsq = sq.getDatasetSequence();
-        StringBuffer sb = new StringBuffer();
-        String newres = jalview.analysis.AlignSeq.extractGaps(
-                jalview.util.Comparison.GapChars, sq.getSequenceAsString());
+        // Update with the longer sequence.
         synchronized (dsq)
         {
-          sb.append(dsq.getSequence());
-          if (pre)
-          {
-            sb.insert(0, newres
-                    .substring(0, dsq.getStart() - sq.getStart()));
-            dsq.setStart(sq.getStart());
-          }
-          if (post)
-          {
-            sb.append(newres.substring(newres.length() - sq.getEnd()
-                    - dsq.getEnd()));
-            dsq.setEnd(sq.getEnd());
-          }
-          dsq.setSequence(sb.toString());
+        /*if (pre)
+        {
+          sb.insert(0, newres
+                  .substring(0, dsq.getStart() - sq.getStart()));
+          dsq.setStart(sq.getStart());
+        }
+        if (post)
+        {
+          sb.append(newres.substring(newres.length() - sq.getEnd()
+                  - dsq.getEnd()));
+          dsq.setEnd(sq.getEnd());
+        }
+        */
+        dsq.setSequence(sb.toString());
         }
+        //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 ("
-                        + (pre ? "prepended" : "") + " "
-                        + (post ? "appended" : ""));
+              .println("DEBUG Notice:  Merged dataset sequence"); // ("
+                      // + (pre ? "prepended" : "") + " "
+                      //+ (post ? "appended" : ""));
       }
     }
-    // create a new dataset
-    if (ds == null)
-    {
-      SequenceI[] dsseqs = new SequenceI[dseqs.size()];
-      dseqs.copyInto(dsseqs);
-      ds = new jalview.datamodel.Alignment(dsseqs);
-      addDatasetRef(vamsasSet.getDatasetId(), ds);
-    }
-    // set the dataset for the newly imported alignment.
-    if (al.getDataset() == null)
-    {
-      al.setDataset(ds);
-    }
   }
 
   java.util.Hashtable datasetIds = null;
@@ -2299,18 +2427,38 @@ public class Jalview2XML
       else
       {
         /**
-         * make a new sequence and add it to refIds hash
+         * local sequence definition
          */
         Sequence ms = mc.getSequence();
-        jalview.datamodel.Sequence djs = new jalview.datamodel.Sequence(ms
+        jalview.datamodel.Sequence djs=null;
+        String sqid = ms.getDsseqid();
+        if (sqid!=null && sqid.length()>0)
+        {
+          /*
+           * recover dataset sequence
+           */
+          djs = (jalview.datamodel.Sequence) seqRefIds.get(sqid);
+        } else {
+          System.err.println("Warning - making up dataset sequence id for DbRef sequence map reference");
+          sqid = ((Object)ms).toString(); // make up a new hascode for undefined dataset sequence hash (unlikely to happen)
+        }
+        
+        if (djs==null) {
+          /**
+           * make a new dataset sequence and add it to refIds hash
+           */
+          djs = new jalview.datamodel.Sequence(ms
                 .getName(), ms.getSequence());
-        djs.setStart(jmap.getMap().getToLowest());
-        djs.setEnd(jmap.getMap().getToHighest());
-        djs.setVamsasId(uniqueSetSuffix + ms.getId());
-        jmap.setTo(djs);
-        seqRefIds.put(ms.getId(), djs);
+          djs.setStart(jmap.getMap().getToLowest());
+          djs.setEnd(jmap.getMap().getToHighest());
+          djs.setVamsasId(uniqueSetSuffix + sqid);
+          jmap.setTo(djs);
+          seqRefIds.put(sqid, djs);
+          
+        }
         jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
         addDBRefs(djs, ms);
+        
       }
     }
     return (jmap);
@@ -2320,12 +2468,12 @@ public class Jalview2XML
   public jalview.gui.AlignmentPanel copyAlignPanel(AlignmentPanel ap,
           boolean keepSeqRefs)
   {
-    jalview.schemabinding.version2.JalviewModel jm = SaveState(ap, null,
-            null, null);
+    jalview.schemabinding.version2.JalviewModel jm = 
+       SaveState(ap, null, null);
 
     if (!keepSeqRefs)
     {
-      seqRefIds.clear();
+      clearSeqRefs();
       jm.getJalviewModelSequence().getViewport(0).setSequenceSetId(null);
     }
     else
@@ -2353,4 +2501,16 @@ public class Jalview2XML
 
     return af.alignPanel;
   }
+  /* (non-Javadoc)
+   * @see java.lang.Object#finalize()
+   */
+  protected void finalize() throws Throwable
+  {
+    // really make sure we have no buried refs left.
+    clearSeqRefs();
+    this.seqRefIds = null;
+    this.seqsToIds = null;
+    super.finalize();
+  }
+  
 }