JAL-250 prototype ‘hide redundant sequences’ - redundant seqs are represented by...
[jalview.git] / src / jalview / gui / Jalview2XML.java
index 9b2b04a..68245b6 100644 (file)
@@ -108,6 +108,7 @@ import java.lang.reflect.InvocationTargetException;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -277,9 +278,12 @@ public class Jalview2XML
   {
     String sref;
 
-    public SeqFref(String _sref)
+    String type;
+
+    public SeqFref(String _sref, String type)
     {
       sref = _sref;
+      this.type = type;
     }
 
     public String getSref()
@@ -313,6 +317,12 @@ public class Jalview2XML
      * @return true if the forward reference was fully resolved
      */
     abstract boolean resolve();
+
+    @Override
+    public String toString()
+    {
+      return type + " reference to " + sref;
+    }
   }
 
   /**
@@ -325,7 +335,7 @@ public class Jalview2XML
   public SeqFref newMappingRef(final String sref,
           final jalview.datamodel.Mapping _jmap)
   {
-    SeqFref fref = new SeqFref(sref)
+    SeqFref fref = new SeqFref(sref, "Mapping")
     {
       public jalview.datamodel.Mapping jmap = _jmap;
 
@@ -348,7 +358,7 @@ public class Jalview2XML
           final AlignedCodonFrame _cf, final jalview.datamodel.Mapping _jmap)
   {
 
-    SeqFref fref = new SeqFref(sref)
+    SeqFref fref = new SeqFref(sref, "Codon Frame")
     {
       AlignedCodonFrame cf = _cf;
 
@@ -396,7 +406,8 @@ public class Jalview2XML
     }
     if (unresolved>0)
     {
-      System.err.println("There were "+unresolved+" forward references left unresolved on the stack.");
+      System.err.println("Jalview Project Import: There were " + unresolved
+              + " forward references left unresolved on the stack.");
     }
     if (failedtoresolve>0)
     {
@@ -491,7 +502,20 @@ public class Jalview2XML
     {
       return;
     }
+    saveAllFrames(Arrays.asList(frames), jout);
+  }
 
+  /**
+   * core method for storing state for a set of AlignFrames.
+   * 
+   * @param frames
+   *          - frames involving all data to be exported (including containing
+   *          splitframes)
+   * @param jout
+   *          - project output stream
+   */
+  private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
+  {
     Hashtable<String, AlignFrame> dsses = new Hashtable<String, AlignFrame>();
 
     /*
@@ -511,9 +535,9 @@ public class Jalview2XML
       List<String> viewIds = new ArrayList<String>();
 
       // REVERSE ORDER
-      for (int i = frames.length - 1; i > -1; i--)
+      for (int i = frames.size() - 1; i > -1; i--)
       {
-        AlignFrame af = frames[i];
+        AlignFrame af = frames.get(i);
         // skip ?
         if (skipList != null
                 && skipList
@@ -616,30 +640,20 @@ public class Jalview2XML
   {
     try
     {
-      int ap = 0;
-      int apSize = af.alignPanels.size();
       FileOutputStream fos = new FileOutputStream(jarFile);
       JarOutputStream jout = new JarOutputStream(fos);
-      Hashtable<String, AlignFrame> dsses = new Hashtable<String, AlignFrame>();
-      List<String> viewIds = new ArrayList<String>();
+      List<AlignFrame> frames = new ArrayList<AlignFrame>();
 
-      for (AlignmentPanel apanel : af.alignPanels)
+      // resolve splitframes
+      if (af.getViewport().getCodingComplement() != null)
       {
-        String jfileName = apSize == 1 ? fileName : fileName + ap;
-        ap++;
-        if (!jfileName.endsWith(".xml"))
-        {
-          jfileName = jfileName + ".xml";
-        }
-        saveState(apanel, jfileName, jout, viewIds);
-        String dssid = getDatasetIdRef(af.getViewport().getAlignment()
-                .getDataset());
-        if (!dsses.containsKey(dssid))
-        {
-          dsses.put(dssid, af);
-        }
+        frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
+      }
+      else
+      {
+        frames.add(af);
       }
-      writeDatasetFor(dsses, fileName, jout);
+      saveAllFrames(frames, jout);
       try
       {
         jout.flush();
@@ -987,7 +1001,8 @@ public class Jalview2XML
       jal = av.getAlignment();
     }
     // SAVE MAPPINGS
-    if (jal.getCodonFrames() != null)
+    // FOR DATASET
+    if (storeDS && jal.getCodonFrames() != null)
     {
       List<AlignedCodonFrame> jac = jal.getCodonFrames();
       for (AlignedCodonFrame acf : jac)
@@ -2035,16 +2050,17 @@ public class Jalview2XML
     if (jds.getDatasetSequence() != null)
     {
       vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
-      if (jds.getDatasetSequence().getDBRefs() != null)
-      {
-        dbrefs = jds.getDatasetSequence().getDBRefs();
-      }
     }
     else
     {
-      vamsasSeq.setDsseqid(id); // so we can tell which sequences really are
+      // seqId==dsseqid so we can tell which sequences really are
       // dataset sequences only
+      vamsasSeq.setDsseqid(id);
       dbrefs = jds.getDBRefs();
+      if (parentseq == null)
+      {
+        parentseq = jds;
+      }
     }
     if (dbrefs != null)
     {
@@ -2096,38 +2112,32 @@ public class Jalview2XML
       if (jmp.getTo() != null)
       {
         MappingChoice mpc = new MappingChoice();
-        if (recurse
-                && (parentseq != jmp.getTo() || parentseq
-                        .getDatasetSequence() != jmp.getTo()))
+
+        // check/create ID for the sequence referenced by getTo()
+
+        String jmpid = "";
+        SequenceI ps = null;
+        if (parentseq != jmp.getTo()
+                && parentseq.getDatasetSequence() != jmp.getTo())
         {
-          mpc.setSequence(createVamsasSequence(false, seqHash(jmp.getTo()),
-                  jmp.getTo(), jds));
+          // chaining dbref rather than a handshaking one
+          jmpid = seqHash(ps = jmp.getTo());
         }
         else
         {
-          String jmpid = "";
-          SequenceI ps = null;
-          if (parentseq != jmp.getTo()
-                  && parentseq.getDatasetSequence() != jmp.getTo())
-          {
-            // chaining dbref rather than a handshaking one
-            jmpid = seqHash(ps = jmp.getTo());
-          }
-          else
-          {
-            jmpid = seqHash(ps = parentseq);
-          }
-          mpc.setDseqFor(jmpid);
-          if (!seqRefIds.containsKey(mpc.getDseqFor()))
-          {
-            jalview.bin.Cache.log.debug("creatign new DseqFor ID");
-            seqRefIds.put(mpc.getDseqFor(), ps);
-          }
-          else
-          {
-            jalview.bin.Cache.log.debug("reusing DseqFor ID");
-          }
+          jmpid = seqHash(ps = parentseq);
+        }
+        mpc.setDseqFor(jmpid);
+        if (!seqRefIds.containsKey(mpc.getDseqFor()))
+        {
+          jalview.bin.Cache.log.debug("creatign new DseqFor ID");
+          seqRefIds.put(mpc.getDseqFor(), ps);
+        }
+        else
+        {
+          jalview.bin.Cache.log.debug("reusing DseqFor ID");
         }
+
         mp.setMappingChoice(mpc);
       }
     }
@@ -2339,6 +2349,7 @@ public class Jalview2XML
       initSeqRefs();
     }
     AlignFrame af = null, _af = null;
+    IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<AlignmentI, AlignmentI>();
     Map<String, AlignFrame> gatherToThisFrame = new HashMap<String, AlignFrame>();
     final String file = jprovider.getFilename();
     try
@@ -2366,13 +2377,24 @@ public class Jalview2XML
           if (true) // !skipViewport(object))
           {
             _af = loadFromObject(object, file, true, jprovider);
-            if (object.getJalviewModelSequence().getViewportCount() > 0)
+            if (_af != null
+                    && object.getJalviewModelSequence().getViewportCount() > 0)
             {
-              af = _af;
-              if (af.viewport.isGatherViewsHere())
+              if (af == null)
+              {
+                // store a reference to the first view
+                af = _af;
+              }
+              if (_af.viewport.isGatherViewsHere())
               {
-                gatherToThisFrame.put(af.viewport.getSequenceSetId(), af);
+                // if this is a gathered view, keep its reference since
+                // after gathering views, only this frame will remain
+                af = _af;
+                gatherToThisFrame.put(_af.viewport.getSequenceSetId(), _af);
               }
+              // Save dataset to register mappings once all resolved
+              importedDatasets.put(af.viewport.getAlignment().getDataset(),
+                      af.viewport.getAlignment().getDataset());
             }
           }
           entryCount++;
@@ -2428,11 +2450,6 @@ public class Jalview2XML
       e.printStackTrace();
     }
 
-    if (Desktop.instance != null)
-    {
-      Desktop.instance.stopLoading();
-    }
-
     /*
      * Regather multiple views (with the same sequence set id) to the frame (if
      * any) that is flagged as the one to gather to, i.e. convert them to tabbed
@@ -2446,11 +2463,24 @@ public class Jalview2XML
     }
 
     restoreSplitFrames();
-
+    for (AlignmentI ds : importedDatasets.keySet())
+    {
+      if (ds.getCodonFrames() != null)
+      {
+        StructureSelectionManager.getStructureSelectionManager(
+                Desktop.instance).registerMappings(ds.getCodonFrames());
+      }
+    }
     if (errorMessage != null)
     {
       reportErrors();
     }
+
+    if (Desktop.instance != null)
+    {
+      Desktop.instance.stopLoading();
+    }
+
     return af;
   }
 
@@ -2823,7 +2853,39 @@ public class Jalview2XML
     SequenceI[] orderedSeqs = tmpseqs
             .toArray(new SequenceI[tmpseqs.size()]);
 
-    AlignmentI al = new Alignment(orderedSeqs);
+    AlignmentI al = null;
+    // so we must create or recover the dataset alignment before going further
+    // ///////////////////////////////
+    if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
+    {
+      // older jalview projects do not have a dataset - so creat alignment and
+      // dataset
+      al = new Alignment(orderedSeqs);
+      al.setDataset(null);
+    }
+    else
+    {
+      boolean isdsal = object.getJalviewModelSequence().getViewportCount() == 0;
+      if (isdsal)
+      {
+        // we are importing a dataset record, so
+        // recover reference to an alignment already materialsed as dataset
+        al = getDatasetFor(vamsasSet.getDatasetId());
+      }
+      if (al == null)
+      {
+        // materialse the alignment
+        al = new Alignment(orderedSeqs);
+      }
+      if (isdsal)
+      {
+        addDatasetRef(vamsasSet.getDatasetId(), al);
+      }
+
+      // finally, verify all data in vamsasSet is actually present in al
+      // passing on flag indicating if it is actually a stored dataset
+      recoverDatasetFor(vamsasSet, al, isdsal);
+    }
 
     if (referenceseqForView != null)
     {
@@ -2836,22 +2898,6 @@ public class Jalview2XML
       al.setProperty(ssp.getKey(), ssp.getValue());
     }
 
-    // /
-    // SequenceFeatures are added to the DatasetSequence,
-    // so we must create or recover the dataset before loading features
-    // ///////////////////////////////
-    if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
-    {
-      // older jalview projects do not have a dataset id.
-      al.setDataset(null);
-    }
-    else
-    {
-      // recover dataset - passing on flag indicating if this a 'viewless'
-      // sequence set (a.k.a. a stored dataset for the project)
-      recoverDatasetFor(vamsasSet, al, object.getJalviewModelSequence()
-              .getViewportCount() == 0);
-    }
     // ///////////////////////////////
 
     Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
@@ -4534,7 +4580,7 @@ public class Jalview2XML
       }
     }
     af.setMenusFromViewport(af.viewport);
-
+    af.setTitle(view.getTitle());
     // TODO: we don't need to do this if the viewport is aready visible.
     /*
      * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it