JAL-845 code/refactoring/tests related to linking DNA and protein
[jalview.git] / src / jalview / gui / Jalview2XML.java
index a1a009d..d3a7e2c 100644 (file)
@@ -1,42 +1,71 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1)
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
  * Copyright (C) 2014 The Jalview Authors
  * 
  * This file is part of Jalview.
  * 
  * Jalview is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
  *  
  * Jalview is distributed in the hope that it will be useful, but 
  * WITHOUT ANY WARRANTY; without even the implied warranty 
  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
  * PURPOSE.  See the GNU General Public License for more details.
  * 
- * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
 package jalview.gui;
 
-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.*;
-
-import org.exolab.castor.xml.*;
-
+import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.Cache;
+import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
-import jalview.schemabinding.version2.*;
-import jalview.schemes.*;
+import jalview.schemabinding.version2.AlcodMap;
+import jalview.schemabinding.version2.AlcodonFrame;
+import jalview.schemabinding.version2.Annotation;
+import jalview.schemabinding.version2.AnnotationColours;
+import jalview.schemabinding.version2.AnnotationElement;
+import jalview.schemabinding.version2.CalcIdParam;
+import jalview.schemabinding.version2.DBRef;
+import jalview.schemabinding.version2.Features;
+import jalview.schemabinding.version2.Group;
+import jalview.schemabinding.version2.HiddenColumns;
+import jalview.schemabinding.version2.JGroup;
+import jalview.schemabinding.version2.JSeq;
+import jalview.schemabinding.version2.JalviewModel;
+import jalview.schemabinding.version2.JalviewModelSequence;
+import jalview.schemabinding.version2.MapListFrom;
+import jalview.schemabinding.version2.MapListTo;
+import jalview.schemabinding.version2.Mapping;
+import jalview.schemabinding.version2.MappingChoice;
+import jalview.schemabinding.version2.OtherData;
+import jalview.schemabinding.version2.PdbentryItem;
+import jalview.schemabinding.version2.Pdbids;
+import jalview.schemabinding.version2.Property;
+import jalview.schemabinding.version2.Sequence;
+import jalview.schemabinding.version2.SequenceSet;
+import jalview.schemabinding.version2.SequenceSetProperties;
+import jalview.schemabinding.version2.Setting;
+import jalview.schemabinding.version2.StructureState;
+import jalview.schemabinding.version2.ThresholdLine;
+import jalview.schemabinding.version2.Tree;
+import jalview.schemabinding.version2.UserColours;
+import jalview.schemabinding.version2.Viewport;
+import jalview.schemes.AnnotationColourGradient;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemeProperty;
+import jalview.schemes.GraduatedColor;
+import jalview.schemes.ResidueColourScheme;
+import jalview.schemes.ResidueProperties;
+import jalview.structure.StructureSelectionManager;
+import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.util.jarInputStreamProvider;
 import jalview.viewmodel.AlignmentViewport;
@@ -47,6 +76,41 @@ import jalview.ws.params.ArgumentI;
 import jalview.ws.params.AutoCalcSetting;
 import jalview.ws.params.WsParamSetI;
 
+import java.awt.Rectangle;
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
+
+import javax.swing.JInternalFrame;
+import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+
+import org.exolab.castor.xml.Unmarshaller;
+
 /**
  * Write out the current jalview desktop state as a Jalview XML stream.
  * 
@@ -338,8 +402,7 @@ public class Jalview2XML
 
           for (ap = 0; ap < apSize; ap++)
           {
-            AlignmentPanel apanel = (AlignmentPanel) af.alignPanels
-                    .elementAt(ap);
+            AlignmentPanel apanel = af.alignPanels.get(ap);
             String fileName = apSize == 1 ? shortName : ap + shortName;
             if (!fileName.endsWith(".xml"))
             {
@@ -394,8 +457,8 @@ public class Jalview2XML
       Hashtable<String, AlignFrame> dsses = new Hashtable<String, AlignFrame>();
       for (ap = 0; ap < apSize; ap++)
       {
-        AlignmentPanel apanel = (AlignmentPanel) af.alignPanels
-                .elementAt(ap);
+        AlignmentPanel apanel = af.alignPanels
+                .get(ap);
         String jfileName = apSize == 1 ? fileName : fileName + ap;
         if (!jfileName.endsWith(".xml"))
         {
@@ -674,7 +737,9 @@ public class Jalview2XML
                                 .startsWith(
                                         jmol.jmb.pdbentry[peid].getId()
                                                 .toLowerCase())))
+                {
                   continue;
+                }
                 if (matchedFile == null)
                 {
                   matchedFile = jmol.jmb.pdbentry[peid].getFile();
@@ -796,31 +861,18 @@ public class Jalview2XML
       jal = av.getAlignment();
     }
     // SAVE MAPPINGS
-    if (jal.getCodonFrames() != null && jal.getCodonFrames().length > 0)
+    Set<AlignedCodonFrame> jac = jal.getCodonFrames();
+    if (jac != null)
     {
-      jalview.datamodel.AlignedCodonFrame[] jac = jal.getCodonFrames();
-      for (int i = 0; i < jac.length; i++)
+      for (AlignedCodonFrame acf : jac)
       {
         AlcodonFrame alc = new AlcodonFrame();
         vamsasSet.addAlcodonFrame(alc);
-        for (int p = 0; p < jac[i].aaWidth; p++)
-        {
-          Alcodon cmap = new Alcodon();
-          if (jac[i].codons[p] != null)
-          {
-            // 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]);
-          }
-          alc.addAlcodon(cmap);
-        }
-        if (jac[i].getProtMappings() != null
-                && jac[i].getProtMappings().length > 0)
+        if (acf.getProtMappings() != null
+                && acf.getProtMappings().length > 0)
         {
-          SequenceI[] dnas = jac[i].getdnaSeqs();
-          jalview.datamodel.Mapping[] pmaps = jac[i].getProtMappings();
+          SequenceI[] dnas = acf.getdnaSeqs();
+          jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
           for (int m = 0; m < pmaps.length; m++)
           {
             AlcodMap alcmap = new AlcodMap();
@@ -1187,8 +1239,8 @@ public class Jalview2XML
           for (int c = 0; c < av.getColumnSelection().getHiddenColumns()
                   .size(); c++)
           {
-            int[] region = (int[]) av.getColumnSelection()
-                    .getHiddenColumns().elementAt(c);
+            int[] region = av.getColumnSelection().getHiddenColumns()
+                    .get(c);
             HiddenColumns hc = new HiddenColumns();
             hc.setStart(region[0]);
             hc.setEnd(region[1]);
@@ -1353,7 +1405,16 @@ public class Jalview2XML
         calcIdSet.add(aa[i].getCalcId());
         an.setCalcId(aa[i].getCalcId());
       }
-
+      if (aa[i].hasProperties())
+      {
+        for (String pr : aa[i].getProperties())
+        {
+          Property prop = new Property();
+          prop.setName(pr);
+          prop.setValue(aa[i].getProperty(pr));
+          an.addProperty(prop);
+        }
+      }
       AnnotationElement ae;
       if (aa[i].annotations != null)
       {
@@ -1367,18 +1428,25 @@ public class Jalview2XML
 
           ae = new AnnotationElement();
           if (aa[i].annotations[a].description != null)
+          {
             ae.setDescription(aa[i].annotations[a].description);
+          }
           if (aa[i].annotations[a].displayCharacter != null)
+          {
             ae.setDisplayCharacter(aa[i].annotations[a].displayCharacter);
+          }
 
           if (!Float.isNaN(aa[i].annotations[a].value))
+          {
             ae.setValue(aa[i].annotations[a].value);
+          }
 
           ae.setPosition(a);
-          if (aa[i].annotations[a].secondaryStructure != ' '
-                  && aa[i].annotations[a].secondaryStructure != '\0')
+          if (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)
@@ -1499,8 +1567,7 @@ public class Jalview2XML
         return false;
       }
     }
-    throw new Error("Unsupported Version for calcIdparam "
-            + calcIdParam.toString());
+    throw new Error(MessageManager.formatMessage("error.unsupported_version_calcIdparam", new String[]{calcIdParam.toString()}));
   }
 
   /**
@@ -1793,7 +1860,7 @@ public class Jalview2XML
     try
     {
       // create list to store references for any new Jmol viewers created
-      newStructureViewers = new Vector<AppJmol>();
+      newStructureViewers = new Vector<JalviewStructureDisplayI>();
       // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
       // Workaround is to make sure caller implements the JarInputStreamProvider
       // interface
@@ -1924,8 +1991,7 @@ public class Jalview2XML
             if (object.getJalviewModelSequence().getViewportCount() > 0)
             {
               af = _af;
-              if (object.getJalviewModelSequence().getViewportCount() > 1
-                      && af.viewport.gatherViewsHere)
+              if (af.viewport.gatherViewsHere)
               {
                 gatherToThisFrame.put(af.viewport.getSequenceSetId(), af);
               }
@@ -2044,7 +2110,7 @@ public class Jalview2XML
     errorMessage = null;
   }
 
-  Hashtable alreadyLoadedPDB;
+  Hashtable<String, String> alreadyLoadedPDB;
 
   /**
    * when set, local views will be updated from view stored in JalviewXML
@@ -2056,10 +2122,14 @@ public class Jalview2XML
   String loadPDBFile(jarInputStreamProvider jprovider, String pdbId)
   {
     if (alreadyLoadedPDB == null)
+    {
       alreadyLoadedPDB = new Hashtable();
+    }
 
     if (alreadyLoadedPDB.containsKey(pdbId))
+    {
       return alreadyLoadedPDB.get(pdbId).toString();
+    }
 
     try
     {
@@ -2229,7 +2299,10 @@ public class Jalview2XML
     }
     else
     {
-      recoverDatasetFor(vamsasSet, al);
+      // 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);
     }
     // ///////////////////////////////
 
@@ -2291,7 +2364,9 @@ public class Jalview2XML
                 entry.setFile(pdbloaded.get(ids[p].getId()).toString());
               }
             }
-
+            StructureSelectionManager.getStructureSelectionManager(
+                    Desktop.instance)
+                    .registerPDBEntry(entry);
             al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
           }
         }
@@ -2308,28 +2383,7 @@ public class Jalview2XML
       AlcodonFrame[] alc = vamsasSet.getAlcodonFrame();
       for (int i = 0; i < alc.length; i++)
       {
-        jalview.datamodel.AlignedCodonFrame cf = new jalview.datamodel.AlignedCodonFrame(
-                alc[i].getAlcodonCount());
-        if (alc[i].getAlcodonCount() > 0)
-        {
-          Alcodon[] alcods = alc[i].getAlcodon();
-          for (int p = 0; p < cf.codons.length; p++)
-          {
-            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
-            {
-              cf.codons[p] = null;
-            }
-          }
-        }
+        AlignedCodonFrame cf = new AlignedCodonFrame();
         if (alc[i].getAlcodMapCount() > 0)
         {
           AlcodMap[] maps = alc[i].getAlcodMap();
@@ -2407,7 +2461,9 @@ public class Jalview2XML
           // in principle Visible should always be true for annotation displayed
           // in multiple views
           if (an[i].hasVisible())
+          {
             jda.visible = an[i].getVisible();
+          }
 
           al.addAnnotation(jda);
 
@@ -2426,7 +2482,9 @@ public class Jalview2XML
             anpos = ae[aa].getPosition();
 
             if (anpos >= anot.length)
+            {
               continue;
+            }
 
             anot[anpos] = new jalview.datamodel.Annotation(
 
@@ -2520,10 +2578,14 @@ public class Jalview2XML
           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())
         {
@@ -2545,7 +2607,14 @@ public class Jalview2XML
           jaa.belowAlignment = an[i].isBelowAlignment();
         }
         jaa.setCalcId(an[i].getCalcId());
-
+        if (an[i].getPropertyCount() > 0)
+        {
+          for (jalview.schemabinding.version2.Property prop : an[i]
+                  .getProperty())
+          {
+            jaa.setProperty(prop.getName(), prop.getValue());
+          }
+        }
         if (jaa.autoCalculated)
         {
           autoAlan.add(new JvAnnotRow(i, jaa));
@@ -3131,10 +3200,11 @@ public class Jalview2XML
                   @Override
                   public void run()
                   {
-                    AppJmol sview = null;
+                    JalviewStructureDisplayI sview = null;
                     try
                     {
-                      sview = new AppJmol(pdbf, id, sq, alf.alignPanel,
+                      // JAL-1333 note - we probably can't migrate Jmol views to UCSF Chimera!
+                      sview = new StructureViewer(alf.alignPanel.getStructureSelectionManager()).createView(StructureViewer.Viewer.JMOL, pdbf, id, sq, alf.alignPanel,
                               useinJmolsuperpos, usetoColourbyseq,
                               jmolColouring, fileloc, rect, vid);
                       addNewStructureViewer(sview);
@@ -3210,15 +3280,18 @@ public class Jalview2XML
 
   /**
    * 
-   * @param supported - minimum version we are comparing against
-   * @param version - version of data being processsed.
+   * @param supported
+   *          - minimum version we are comparing against
+   * @param version
+   *          - version of data being processsed.
    * @return true if version is development/null or evaluates to the same or
    *         later X.Y.Z (where X,Y,Z are like [0-9]+b?[0-9]*)
    */
   private boolean isVersionStringLaterThan(String supported, String version)
   {
     if (version == null || version.equalsIgnoreCase("DEVELOPMENT BUILD")
-            || version.equalsIgnoreCase("Test"))
+            || version.equalsIgnoreCase("Test")
+            || version.equalsIgnoreCase("AUTOMATED BUILD"))
     {
       System.err.println("Assuming project file with "
               + (version == null ? "null" : version)
@@ -3261,13 +3334,13 @@ public class Jalview2XML
     return true;
   }
 
-  Vector<AppJmol> newStructureViewers = null;
+  Vector<JalviewStructureDisplayI> newStructureViewers = null;
 
-  protected void addNewStructureViewer(AppJmol sview)
+  protected void addNewStructureViewer(JalviewStructureDisplayI sview)
   {
     if (newStructureViewers != null)
     {
-      sview.jmb.setFinishedLoadingFromArchive(false);
+      sview.getBinding().setFinishedLoadingFromArchive(false);
       newStructureViewers.add(sview);
     }
   }
@@ -3276,9 +3349,9 @@ public class Jalview2XML
   {
     if (newStructureViewers != null)
     {
-      for (AppJmol sview : newStructureViewers)
+      for (JalviewStructureDisplayI sview : newStructureViewers)
       {
-        sview.jmb.setFinishedLoadingFromArchive(true);
+        sview.getBinding().setFinishedLoadingFromArchive(true);
       }
       newStructureViewers.clear();
       newStructureViewers = null;
@@ -3313,8 +3386,8 @@ public class Jalview2XML
       if (av != null)
       {
         // propagate shared settings to this new view
-        af.viewport.historyList = av.historyList;
-        af.viewport.redoList = av.redoList;
+        af.viewport.setHistoryList(av.getHistoryList());
+        af.viewport.setRedoList(av.getRedoList());
       }
       else
       {
@@ -3538,12 +3611,16 @@ public class Jalview2XML
         }
         renderOrder[fs] = setting.getType();
         if (setting.hasOrder())
+        {
           af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer().setOrder(
                   setting.getType(), setting.getOrder());
+        }
         else
+        {
           af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer().setOrder(
                   setting.getType(),
                   fs / jms.getFeatureSettings().getSettingCount());
+        }
         if (setting.getDisplay())
         {
           af.viewport.featuresDisplayed.put(setting.getType(), new Integer(
@@ -3876,7 +3953,8 @@ public class Jalview2XML
     }
   }
 
-  private void recoverDatasetFor(SequenceSet vamsasSet, Alignment al)
+  private void recoverDatasetFor(SequenceSet vamsasSet, Alignment al,
+          boolean ignoreUnrefed)
   {
     jalview.datamodel.Alignment ds = getDatasetFor(vamsasSet.getDatasetId());
     Vector dseqs = null;
@@ -3888,7 +3966,7 @@ public class Jalview2XML
     for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
     {
       Sequence vamsasSeq = vamsasSet.getSequence(i);
-      ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs);
+      ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed);
     }
     // create a new dataset
     if (ds == null)
@@ -3901,7 +3979,7 @@ public class Jalview2XML
       addDatasetRef(vamsasSet.getDatasetId(), ds);
     }
     // set the dataset for the newly imported alignment.
-    if (al.getDataset() == null)
+    if (al.getDataset() == null && !ignoreUnrefed)
     {
       al.setDataset(ds);
     }
@@ -3917,7 +3995,7 @@ public class Jalview2XML
    *          vector to add new dataset sequence to
    */
   private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
-          AlignmentI ds, Vector dseqs)
+          AlignmentI ds, Vector dseqs, boolean ignoreUnrefed)
   {
     // JBP TODO: Check this is called for AlCodonFrames to support recovery of
     // xRef Codon Maps
@@ -3928,7 +4006,10 @@ public class Jalview2XML
     {
       dsq = sq.getDatasetSequence();
     }
-
+    if (sq == null && ignoreUnrefed)
+    {
+      return;
+    }
     String sqid = vamsasSeq.getDsseqid();
     if (dsq == null)
     {
@@ -4386,7 +4467,9 @@ public class Jalview2XML
         }
       }
       else
+      {
         Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
+      }
     }
   }