JAL-1588 part work save/restore of Chimera session
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 8 Jan 2015 15:05:31 +0000 (15:05 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 8 Jan 2015 15:05:31 +0000 (15:05 +0000)
schemas/jalview.xsd
src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AppJmol.java
src/jalview/gui/AppJmolBinding.java
src/jalview/gui/ChimeraViewFrame.java
src/jalview/gui/Desktop.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/StructureViewer.java
src/jalview/gui/StructureViewerBase.java
src/jalview/structures/models/AAStructureBindingModel.java

index 137f7fb..27f952d 100755 (executable)
                                                                                                                                                </xs:documentation>
                                                                                                                                        </xs:annotation>
                                                                                                                                </xs:attribute>
-                                                                                                                               <xs:attribute
-                                                                                                                                       name="chimeraSession" type="xs:string" use="optional">
-                                                                                                                                       <xs:annotation>
-                                                                                                                                               <xs:documentation>
-Full path name to a saved Chimera session file (usually a .py file).
-                                                                                                                                               </xs:documentation>
-                                                                                                                                       </xs:annotation>
-                                                                                                                               </xs:attribute>
+
                                                                                                                        </xs:extension>
                                                                                                                </xs:simpleContent>
                                                                                                        </xs:complexType>
index 34dd3f7..6e6f5ee 100644 (file)
@@ -23,6 +23,7 @@ package jalview.ext.rbvi.chimera;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureRenderer;
 import jalview.api.SequenceRenderer;
+import jalview.bin.Cache;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.PDBEntry;
@@ -1278,10 +1279,31 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     {
       List<String> reply = viewer.sendChimeraCommand("save " + filepath,
               true);
-      return true; // todo: check for error in reply?
-      // System.out.println(reply);
+      if (reply.contains("Session written"))
+      {
+        return true;
+      }
+      else
+      {
+        Cache.log
+                .error("Error saving Chimera session: " + reply.toString());
+      }
     }
     return false;
   }
 
+  /**
+   * Ask Chimera to open a session file. Returns true if successful, else false.
+   * The filename must have a .py extension for this command to work.
+   * 
+   * @param filepath
+   * @return
+   */
+  public boolean openSession(String filepath)
+  {
+    evalStateCommand("open " + filepath, true);
+    // todo: test for failure - how?
+    return true;
+  }
+
 }
index 11cb909..27e8ca0 100644 (file)
@@ -1076,10 +1076,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 .lastIndexOf(java.io.File.separatorChar) + 1);
       }
 
+      /*
+       * First save any linked Chimera session.
+       */
+      Desktop.instance.saveChimeraSessions(file);
+
       success = new Jalview2XML().saveAlignment(this, file, shortName);
 
       statusBar.setText(MessageManager.formatMessage(
-              "label.successfully_saved_to_file_in_format", new String[]
+              "label.successfully_saved_to_file_in_format", new Object[]
               { fileName, format }));
 
     }
index 55288d0..bd4a393 100644 (file)
@@ -427,118 +427,6 @@ public class AppJmol extends StructureViewerBase
     openNewJmol(ap, pe, seqs);
   }
 
-  public AlignmentPanel[] getAllAlignmentPanels()
-  {
-    AlignmentPanel[] t;
-    AlignmentPanel[] list = new AlignmentPanel[0];
-    for (String setid : _aps)
-    {
-      AlignmentPanel[] panels = PaintRefresher.getAssociatedPanels(setid);
-      if (panels != null)
-      {
-        t = new AlignmentPanel[list.length + panels.length];
-        System.arraycopy(list, 0, t, 0, list.length);
-        System.arraycopy(panels, 0, t, list.length, panels.length);
-        list = t;
-      }
-    }
-
-    return list;
-  }
-
-  /**
-   * set the primary alignmentPanel reference and add another alignPanel to the
-   * list of ones to use for colouring and aligning
-   * 
-   * @param nap
-   */
-  public void addAlignmentPanel(AlignmentPanel nap)
-  {
-    if (getAlignmentPanel() == null)
-    {
-      setAlignmentPanel(nap);
-    }
-    if (!_aps.contains(nap.av.getSequenceSetId()))
-    {
-      _aps.add(nap.av.getSequenceSetId());
-    }
-  }
-
-  /**
-   * remove any references held to the given alignment panel
-   * 
-   * @param nap
-   */
-  public void removeAlignmentPanel(AlignmentPanel nap)
-  {
-    try
-    {
-      _alignwith.remove(nap);
-      _colourwith.remove(nap);
-      if (getAlignmentPanel() == nap)
-      {
-        setAlignmentPanel(null);
-        for (AlignmentPanel aps : getAllAlignmentPanels())
-        {
-          if (aps != nap)
-          {
-            setAlignmentPanel(aps);
-            break;
-          }
-        }
-      }
-    } catch (Exception ex)
-    {
-    }
-    if (getAlignmentPanel() != null)
-    {
-      buildActionMenu();
-    }
-  }
-
-  public void useAlignmentPanelForSuperposition(AlignmentPanel nap)
-  {
-    addAlignmentPanel(nap);
-    if (!_alignwith.contains(nap))
-    {
-      _alignwith.add(nap);
-    }
-  }
-
-  public void excludeAlignmentPanelForSuperposition(AlignmentPanel nap)
-  {
-    if (_alignwith.contains(nap))
-    {
-      _alignwith.remove(nap);
-    }
-  }
-
-  public void useAlignmentPanelForColourbyseq(AlignmentPanel nap,
-          boolean enableColourBySeq)
-  {
-    useAlignmentPanelForColourbyseq(nap);
-    getBinding().setColourBySequence(enableColourBySeq);
-    seqColour.setSelected(enableColourBySeq);
-    viewerColour.setSelected(!enableColourBySeq);
-  }
-
-  public void useAlignmentPanelForColourbyseq(AlignmentPanel nap)
-  {
-    addAlignmentPanel(nap);
-    if (!_colourwith.contains(nap))
-    {
-      _colourwith.add(nap);
-    }
-  }
-
-  public void excludeAlignmentPanelForColourbyseq(AlignmentPanel nap)
-  {
-    if (_colourwith.contains(nap))
-    {
-      _colourwith.remove(nap);
-    }
-  }
-
   /**
    * pdb retrieval thread.
    */
index c70380c..131f5bb 100644 (file)
@@ -173,25 +173,6 @@ public class AppJmolBinding extends JalviewJmolBinding
     appJmolWindow.showConsole(b);
   }
 
-  /**
-   * add the given sequences to the mapping scope for the given pdb file handle
-   * 
-   * @param pdbFile
-   *          - pdbFile identifier
-   * @param seq
-   *          - set of sequences it can be mapped to
-   */
-  public void addSequenceForStructFile(String pdbFile, SequenceI[] seq)
-  {
-    for (int pe = 0; pe < getPdbCount(); pe++)
-    {
-      if (getPdbEntry(pe).getFile().equals(pdbFile))
-      {
-        addSequence(pe, seq);
-      }
-    }
-  }
-
   @Override
   protected JmolAppConsoleInterface createJmolConsole(JmolViewer viewer2,
           Container consolePanel, String buttonsToShow)
index bc985df..4e313b5 100644 (file)
@@ -27,6 +27,7 @@ import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.ext.rbvi.chimera.JalviewChimeraBinding;
+import jalview.gui.Jalview2XML.ViewerData;
 import jalview.io.AppletFormatAdapter;
 import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
@@ -97,6 +98,11 @@ public class ChimeraViewFrame extends StructureViewerBase
    */
   private Thread worker = null;
 
+  /*
+   * Path to Chimera session file - set in saveSession()
+   */
+  private String chimeraSessionFile = "";
+
   /**
    * Initialise menu options.
    */
@@ -336,115 +342,21 @@ public class ChimeraViewFrame extends StructureViewerBase
     openNewChimera(ap, pe, seqs);
   }
 
-  public AlignmentPanel[] getAllAlignmentPanels()
-  {
-    AlignmentPanel[] t, list = new AlignmentPanel[0];
-    for (String setid : _aps)
-    {
-      AlignmentPanel[] panels = PaintRefresher.getAssociatedPanels(setid);
-      if (panels != null)
-      {
-        t = new AlignmentPanel[list.length + panels.length];
-        System.arraycopy(list, 0, t, 0, list.length);
-        System.arraycopy(panels, 0, t, list.length, panels.length);
-        list = t;
-      }
-    }
-
-    return list;
-  }
-
-  /**
-   * set the primary alignmentPanel reference and add another alignPanel to the
-   * list of ones to use for colouring and aligning
-   * 
-   * @param nap
-   */
-  public void addAlignmentPanel(AlignmentPanel nap)
-  {
-    if (getAlignmentPanel() == null)
-    {
-      setAlignmentPanel(nap);
-    }
-    if (!_aps.contains(nap.av.getSequenceSetId()))
-    {
-      _aps.add(nap.av.getSequenceSetId());
-    }
-  }
-
   /**
-   * remove any references held to the given alignment panel
+   * Create a new viewer from saved session state data.
    * 
-   * @param nap
+   * @param viewerData
+   * @param af
    */
-  public void removeAlignmentPanel(AlignmentPanel nap)
-  {
-    try
-    {
-      _alignwith.remove(nap);
-      _colourwith.remove(nap);
-      if (getAlignmentPanel() == nap)
-      {
-        setAlignmentPanel(null);
-        for (AlignmentPanel aps : getAllAlignmentPanels())
-        {
-          if (aps != nap)
-          {
-            setAlignmentPanel(aps);
-            break;
-          }
-        }
-      }
-    } catch (Exception ex)
-    {
-    }
-    if (getAlignmentPanel() != null)
-    {
-      buildActionMenu();
-    }
-  }
-
-  public void useAlignmentPanelForSuperposition(AlignmentPanel nap)
-  {
-    addAlignmentPanel(nap);
-    if (!_alignwith.contains(nap))
-    {
-      _alignwith.add(nap);
-    }
-  }
-
-  public void excludeAlignmentPanelForSuperposition(AlignmentPanel nap)
-  {
-    if (_alignwith.contains(nap))
-    {
-      _alignwith.remove(nap);
-    }
-  }
-
-  public void useAlignmentPanelForColourbyseq(AlignmentPanel nap,
-          boolean enableColourBySeq)
-  {
-    useAlignmentPanelForColourbyseq(nap);
-    getBinding().setColourBySequence(enableColourBySeq);
-    seqColour.setSelected(enableColourBySeq);
-    viewerColour.setSelected(!enableColourBySeq);
-  }
-
-  public void useAlignmentPanelForColourbyseq(AlignmentPanel nap)
+  public ChimeraViewFrame(ViewerData viewerData, AlignFrame af)
   {
-    addAlignmentPanel(nap);
-    if (!_colourwith.contains(nap))
-    {
-      _colourwith.add(nap);
-    }
-  }
-
-  public void excludeAlignmentPanelForColourbyseq(AlignmentPanel nap)
-  {
-    if (_colourwith.contains(nap))
-    {
-      _colourwith.remove(nap);
-    }
+    super();
+    String chimeraSessionFile = viewerData.stateData;
+    openNewChimera(af.alignPanel, new PDBEntry[]
+    {}, new SequenceI[][]
+    {});
+    initChimera("open " + chimeraSessionFile);
+    // TODO restore mappings
   }
 
   /**
@@ -1175,9 +1087,26 @@ public class ChimeraViewFrame extends StructureViewerBase
    * if successful, else false.
    * 
    * @param filepath
+   * @see getStateInfo
    */
   public boolean saveSession(String filepath)
   {
-    return jmb.saveSession(filepath);
+    boolean result = jmb.saveSession(filepath);
+    if (result)
+    {
+      this.chimeraSessionFile = filepath;
+    }
+    return result;
+  }
+
+  /**
+   * Returns the file path of the Chimera session file the last time it was
+   * saved. If it was never saved, returns an empty string. There is no
+   * guarantee that the Chimera session has not changed since it was saved.
+   */
+  @Override
+  public String getStateInfo()
+  {
+    return this.chimeraSessionFile;
   }
 }
index 06af0c1..70c8355 100644 (file)
@@ -1467,6 +1467,9 @@ public class Desktop extends jalview.jbgui.GDesktop implements
       final java.io.File choice = chooser.getSelectedFile();
       setProjectFile(choice);
 
+      // TODO or move inside the new Thread?
+      saveChimeraSessions(choice.getAbsolutePath());
+
       new Thread(new Runnable()
       {
         public void run()
@@ -1502,6 +1505,32 @@ public class Desktop extends jalview.jbgui.GDesktop implements
     }
   }
 
+  /**
+   * Request any open, linked Chimera sessions to save their state.
+   * 
+   * @param jalviewProjectFilename
+   *          the filename of the Jalview project; Chimera session files should
+   *          be given distinct, but obviously related, names.
+   */
+  public void saveChimeraSessions(String jalviewProjectFilename)
+  {
+    int i = 0;
+    for (JInternalFrame frame : getAllFrames())
+    {
+      if (frame instanceof ChimeraViewFrame)
+      {
+        /*
+         * Construct a filename for the Chimera session by append _chimera<n>.py
+         * to the Jalview project file name.
+         */
+        String chimeraPath = jalviewProjectFilename + "_chimera_" + i
+                + ".py";
+        ((ChimeraViewFrame) frame).saveSession(chimeraPath);
+        i++;
+      }
+    }
+  }
+
   private void setProjectFile(File choice)
   {
     this.projectFile = choice;
index c960287..9ba8fb7 100644 (file)
@@ -129,7 +129,10 @@ import org.exolab.castor.xml.Unmarshaller;
 public class Jalview2XML
 {
 
-  private class ViewerData
+  /**
+   * A data bean to hold stored data about a structure viewer.
+   */
+  public class ViewerData
   {
 
     private int x;
@@ -140,13 +143,13 @@ public class Jalview2XML
 
     private int height;
 
-    private boolean alignWithPanel;
+    public boolean alignWithPanel;
 
-    private boolean colourWithAlignPanel;
+    public boolean colourWithAlignPanel;
 
-    private boolean colourByViewer;
+    public boolean colourByViewer;
 
-    private String stateData = "";
+    String stateData = "";
 
     // todo: java bean in place of Object []
     private Map<File, Object[]> fileData = new HashMap<File, Object[]>();
@@ -600,6 +603,7 @@ public class Jalview2XML
           boolean storeDS, JarOutputStream jout)
   {
     initSeqRefs();
+    List<String> viewIds = new ArrayList<String>();
     List<UserColourScheme> userColours = new ArrayList<UserColourScheme>();
 
     AlignViewport av = ap.av;
@@ -771,11 +775,10 @@ public class Jalview2XML
           pdb.setType(entry.getType());
 
           /*
-           * Store any JMol or Chimera views associated with this sequence. This
+           * Store any structure views associated with this sequence. This
            * section copes with duplicate entries in the project, so a dataset
            * only view *should* be coped with sensibly.
            */
-          List<String> viewIds = new ArrayList<String>();
           // This must have been loaded, is it still visible?
           JInternalFrame[] frames = Desktop.desktop.getAllFrames();
           String matchedFile = null;
@@ -3174,234 +3177,279 @@ public class Jalview2XML
         }
       }
     }
+      // Instantiate the associated structure views
+      for (Entry<String, ViewerData> entry : jmolViewIds.entrySet())
+      {
+        createOrLinkStructureViewer(entry, af, ap);
+      }
+  }
+
+  /**
+   * 
+   * @param viewerData
+   * @param af
+   * @param ap
+   */
+  protected void createOrLinkStructureViewer(
+          Entry<String, ViewerData> viewerData, AlignFrame af,
+          AlignmentPanel ap)
+  {
+    final ViewerData svattrib = viewerData.getValue();
+
+    /*
+     * Search for any viewer windows already open from other alignment views
+     * that exactly match the stored structure state
+     */
+    StructureViewerBase comp = findMatchingViewer(viewerData);
+
+    if (comp != null)
     {
+      linkStructureViewer(ap, comp, svattrib);
+      return;
+    }
 
-      // Instantiate the associated Jmol views
-      for (Entry<String, ViewerData> entry : jmolViewIds.entrySet())
+    /*
+     * Pending an XML element for ViewerType, just check if stateData contains
+     * "chimera" (part of the chimera session filename).
+     */
+    if (svattrib.stateData.indexOf("chimera") > -1)
+    {
+      createChimeraViewer(viewerData, af);
+    }
+    else
+    {
+      createJmolViewer(viewerData, af);
+    }
+  }
+
+  /**
+   * Create a new Chimera viewer.
+   * 
+   * @param viewerData
+   * @param af
+   */
+  protected void createChimeraViewer(Entry<String, ViewerData> viewerData,
+          AlignFrame af)
+  {
+    final ViewerData svattrib = viewerData.getValue();
+    ChimeraViewFrame cvf = new ChimeraViewFrame(svattrib, af);
+  }
+
+  /**
+   * 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.
+   * 
+   * @param viewerData
+   * @param af
+   */
+  protected void createJmolViewer(
+          final Entry<String, ViewerData> viewerData, AlignFrame af)
+  {
+    final ViewerData svattrib = viewerData.getValue();
+    String state = svattrib.stateData;
+    List<String> pdbfilenames = new ArrayList<String>();
+    List<SequenceI[]> seqmaps = new ArrayList<SequenceI[]>();
+    List<String> pdbids = new ArrayList<String>();
+    StringBuilder newFileLoc = new StringBuilder(64);
+    int cp = 0, ncp, ecp;
+    Map<File, Object[]> oldFiles = svattrib.fileData;
+    while ((ncp = state.indexOf("load ", cp)) > -1)
+    {
+      do
+      {
+        // look for next filename in load statement
+        newFileLoc.append(state.substring(cp,
+                ncp = (state.indexOf("\"", ncp + 1) + 1)));
+        String oldfilenam = state.substring(ncp,
+                ecp = state.indexOf("\"", ncp));
+        // recover the new mapping data for this old filename
+        // have to normalize filename - since Jmol and jalview do
+        // filename
+        // translation differently.
+        Object[] filedat = oldFiles.get(new File(oldfilenam));
+        newFileLoc.append(Platform.escapeString((String) filedat[0]));
+        pdbfilenames.add((String) filedat[0]);
+        pdbids.add((String) filedat[1]);
+        seqmaps.add(((Vector<SequenceI>) filedat[2])
+                .toArray(new SequenceI[0]));
+        newFileLoc.append("\"");
+        cp = ecp + 1; // advance beyond last \" and set cursor so we can
+                      // look for next file statement.
+      } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
+    }
+    if (cp > 0)
+    {
+      // just append rest of state
+      newFileLoc.append(state.substring(cp));
+    }
+    else
+    {
+      System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
+      newFileLoc = new StringBuilder(state);
+      newFileLoc.append("; load append ");
+      for (File id : oldFiles.keySet())
       {
-        String sviewid = entry.getKey();
-        ViewerData svattrib = entry.getValue();
-        String state = svattrib.stateData;
-        Map<File, Object[]> oldFiles = svattrib.fileData;
-        final boolean useinJmolsuperpos = svattrib.alignWithPanel;
-        final boolean usetoColourbyseq = svattrib.colourWithAlignPanel;
-        final boolean jmolColouring = svattrib.colourByViewer;
-        int x = svattrib.x;
-        int y = svattrib.y;
-        int width = svattrib.width;
-        int height = svattrib.height;
-        // 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>();
+        // 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.add((String) filedat[0]);
+        pdbids.add((String) filedat[1]);
+        seqmaps.add(((Vector<SequenceI>) filedat[2])
+                .toArray(new SequenceI[0]));
+        newFileLoc.append(" \"");
+        newFileLoc.append((String) filedat[0]);
+        newFileLoc.append("\"");
 
-        /*
-         * Search for any Jmol windows already open from other alignment views
-         * that exactly match the stored structure state
-         */
-        AppJmol comp = null;
-        JInternalFrame[] frames = getAllFrames();
-        for (JInternalFrame frame : frames)
-        {
-          if (frame instanceof AppJmol)
-          {
-            /*
-             * Post jalview 2.4 schema includes structure view id
-             */
-            if (sviewid != null
-                    && ((StructureViewerBase) frame).getViewId().equals(
-                            sviewid))
-            {
-              comp = (AppJmol) frame;
-            }
-            /*
-             * Otherwise test for matching position and size of viewer frame
-             */
-            else if (frame.getX() == x && frame.getY() == y
-                    && frame.getHeight() == height
-                    && frame.getWidth() == width)
-            {
-              comp = (AppJmol) frame;
-            }
-          }
-        }
+      }
+      newFileLoc.append(";");
+    }
 
-        if (comp == null)
+    if (newFileLoc.length() > 0)
+    {
+      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"))
         {
-          /*
-           * 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();
-            }
-            do
-            {
-              // look for next filename in load statement
-              newFileLoc.append(state.substring(cp,
-                      ncp = (state.indexOf("\"", ncp + 1) + 1)));
-              String oldfilenam = state.substring(ncp,
-                      ecp = state.indexOf("\"", ncp));
-              // recover the new mapping data for this old filename
-              // have to normalize filename - since Jmol and jalview do
-              // filename
-              // translation differently.
-              Object[] filedat = oldFiles.get(new File(oldfilenam));
-              newFileLoc.append(Platform
-                      .escapeString((String) filedat[0]));
-              pdbfilenames.addElement((String) filedat[0]);
-              pdbids.addElement((String) filedat[1]);
-              seqmaps.addElement(((Vector<SequenceI>) filedat[2])
-                      .toArray(new SequenceI[0]));
-              newFileLoc.append("\"");
-              cp = ecp + 1; // advance beyond last \" and set cursor so we can
-                            // look for next file statement.
-            } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
-          }
-          if (cp > 0)
+          if (val.trim().equals("true"))
           {
-            // just append rest of state
-            newFileLoc.append(state.substring(cp));
+            val = "1";
           }
           else
           {
-            System.err
-                    .print("Ignoring incomplete Jmol state for PDB ids: ");
-            newFileLoc = new StringBuffer(state);
-            newFileLoc.append("; load append ");
-            for (File id : oldFiles.keySet())
-            {
-              // add this and any other pdb files that should be present in
-              // the viewer
-              Object[] filedat = oldFiles.get(id);
-              String nfilename;
-              newFileLoc.append(((String) filedat[0]));
-              pdbfilenames.addElement((String) filedat[0]);
-              pdbids.addElement((String) filedat[1]);
-              seqmaps.addElement(((Vector<SequenceI>) filedat[2])
-                      .toArray(new SequenceI[0]));
-              newFileLoc.append(" \"");
-              newFileLoc.append((String) filedat[0]);
-              newFileLoc.append("\"");
-
-            }
-            newFileLoc.append(";");
+            val = "0";
           }
+          newFileLoc.replace(histbug, diff, val);
+        }
+      }
 
-          if (newFileLoc != null)
+      final String[] pdbf = pdbfilenames.toArray(new String[pdbfilenames
+              .size()]);
+      final String[] id = pdbids.toArray(new String[pdbids.size()]);
+      final SequenceI[][] sq = seqmaps
+              .toArray(new SequenceI[seqmaps.size()][]);
+      final String fileloc = newFileLoc.toString();
+      final String sviewid = viewerData.getKey();
+      final AlignFrame alf = af;
+      final java.awt.Rectangle rect = new java.awt.Rectangle(svattrib.x,
+              svattrib.y, svattrib.width, svattrib.height);
+      try
+      {
+        javax.swing.SwingUtilities.invokeAndWait(new Runnable()
+        {
+          @Override
+          public void run()
           {
-            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);
-              }
-            }
-            // TODO: assemble String[] { pdb files }, String[] { id for each
-            // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
-            // seqs_file 2}} from hash
-            final String[] pdbf = pdbfilenames
-                    .toArray(new String[pdbfilenames.size()]), id = pdbids
-                    .toArray(new String[pdbids.size()]);
-            final SequenceI[][] sq = 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);
+            JalviewStructureDisplayI sview = null;
             try
             {
-              javax.swing.SwingUtilities.invokeAndWait(new Runnable()
-              {
-                @Override
-                public void run()
-                {
-                  JalviewStructureDisplayI sview = null;
-                  try
-                  {
-                    // JAL-1333 note - we probably can't migrate Jmol views to UCSF Chimera!
-                    sview = new StructureViewer(alf.alignPanel
-                            .getStructureSelectionManager()).createView(
-                            StructureViewer.ViewerType.JMOL, pdbf, id, sq,
-                            alf.alignPanel,
-                            useinJmolsuperpos, usetoColourbyseq,
-                            jmolColouring, fileloc, rect, vid);
-                    addNewStructureViewer(sview);
-                  } 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)
+              // JAL-1333 note - we probably can't migrate Jmol views to UCSF
+              // Chimera!
+              sview = new StructureViewer(alf.alignPanel
+                      .getStructureSelectionManager()).createView(
+                      StructureViewer.ViewerType.JMOL, pdbf, id, sq,
+                      alf.alignPanel, svattrib, fileloc, rect, sviewid);
+              addNewStructureViewer(sview);
+            } catch (OutOfMemoryError ex)
             {
-              // e.printStackTrace();
+              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)
+      {
+        // e.printStackTrace();
+      }
+    }
+  }
+
+  /**
+   * Returns any open frame that matches given structure viewer data. The match
+   * is based on the unique viewId, or (for older project versions) the frame's
+   * geometry.
+   * 
+   * @param viewerData
+   * @return
+   */
+  protected StructureViewerBase findMatchingViewer(
+          Entry<String, ViewerData> viewerData)
+  {
+    final String sviewid = viewerData.getKey();
+    final ViewerData svattrib = viewerData.getValue();
+    StructureViewerBase comp = null;
+    JInternalFrame[] frames = getAllFrames();
+    for (JInternalFrame frame : frames)
+    {
+      if (frame instanceof StructureViewerBase)
+      {
+        /*
+         * Post jalview 2.4 schema includes structure view id
+         */
+        if (sviewid != null
+                && ((StructureViewerBase) frame).getViewId().equals(
+                        sviewid))
+        {
+          comp = (AppJmol) frame;
+          // todo: break?
         }
-        else
-        // if (comp != null)
+        /*
+         * Otherwise test for matching position and size of viewer frame
+         */
+        else if (frame.getX() == svattrib.x && frame.getY() == svattrib.y
+                && frame.getHeight() == svattrib.height
+                && frame.getWidth() == svattrib.width)
         {
-          linkStructureViewer(ap, comp, oldFiles, useinJmolsuperpos,
-                  usetoColourbyseq, jmolColouring);
+          comp = (AppJmol) frame;
+          // todo: break?
         }
       }
     }
+    return comp;
   }
 
   /**
-   * Link an AlignmentPanel to an existing JMol viewer.
+   * Link an AlignmentPanel to an existing structure viewer.
    * 
    * @param ap
    * @param viewer
    * @param oldFiles
-   * @param useinJmolsuperpos
+   * @param useinViewerSuperpos
    * @param usetoColourbyseq
-   * @param jmolColouring
+   * @param viewerColouring
    */
-  protected void linkStructureViewer(AlignmentPanel ap, AppJmol viewer,
-          Map<File, Object[]> oldFiles,
-          final boolean useinJmolsuperpos, final boolean usetoColourbyseq,
-          final boolean jmolColouring)
+  protected void linkStructureViewer(AlignmentPanel ap,
+          StructureViewerBase viewer, ViewerData svattrib)
   {
     // NOTE: if the jalview project is part of a shared session then
     // view synchronization should/could be done here.
 
-    // add mapping for sequences in this view to an already open Jmol
-    // instance
+    final boolean useinViewerSuperpos = svattrib.alignWithPanel;
+    final boolean usetoColourbyseq = svattrib.colourWithAlignPanel;
+    final boolean viewerColouring = svattrib.colourByViewer;
+    Map<File, Object[]> oldFiles = svattrib.fileData;
+
+    /*
+     * Add mapping for sequences in this view to an already open viewer
+     */
+    final AAStructureBindingModel binding = viewer.getBinding();
     for (File id : oldFiles.keySet())
     {
       // add this and any other pdb files that should be present in the
@@ -3410,13 +3458,15 @@ public class Jalview2XML
       String pdbFile = (String) filedat[0];
       SequenceI[] seq = ((Vector<SequenceI>) filedat[2])
               .toArray(new SequenceI[0]);
-      viewer.jmb.getSsm().setMapping(seq, null, pdbFile,
+      binding
+              .getSsm()
+              .setMapping(seq, null, pdbFile,
               jalview.io.AppletFormatAdapter.FILE);
-      viewer.jmb.addSequenceForStructFile(pdbFile, seq);
+      binding.addSequenceForStructFile(pdbFile, seq);
     }
-    // and add the AlignmentPanel's reference to the Jmol view
+    // and add the AlignmentPanel's reference to the view panel
     viewer.addAlignmentPanel(ap);
-    if (useinJmolsuperpos)
+    if (useinViewerSuperpos)
     {
       viewer.useAlignmentPanelForSuperposition(ap);
     }
@@ -3426,7 +3476,7 @@ public class Jalview2XML
     }
     if (usetoColourbyseq)
     {
-      viewer.useAlignmentPanelForColourbyseq(ap, !jmolColouring);
+      viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
     }
     else
     {
index c204fec..7d986c8 100644 (file)
@@ -24,6 +24,7 @@ import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.Cache;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
+import jalview.gui.Jalview2XML.ViewerData;
 import jalview.structure.StructureSelectionManager;
 
 import java.awt.Rectangle;
@@ -115,18 +116,35 @@ public class StructureViewer
     return viewStructures(getViewerType(), ap, pdb, sequenceIs);
   }
 
+  /**
+   * Create a new panel controlling a structure viewer.
+   * 
+   * @param type
+   * @param pdbf
+   * @param id
+   * @param sq
+   * @param alignPanel
+   * @param viewerData
+   * @param fileloc
+   * @param rect
+   * @param vid
+   * @return
+   */
   public JalviewStructureDisplayI createView(ViewerType type,
-          String[] pdbf,
-          String[] id, SequenceI[][] sq, AlignmentPanel alignPanel,
-          boolean useinJmolsuperpos, boolean usetoColourbyseq,
-          boolean jmolColouring, String fileloc, Rectangle rect, String vid)
+          String[] pdbf, String[] id, SequenceI[][] sq,
+          AlignmentPanel alignPanel, ViewerData viewerData, String fileloc,
+          Rectangle rect, String vid)
   {
+    final boolean useinViewerSuperpos = viewerData.alignWithPanel;
+    final boolean usetoColourbyseq = viewerData.colourWithAlignPanel;
+    final boolean viewerColouring = viewerData.colourByViewer;
+
     JalviewStructureDisplayI sview = null;
     switch (type)
     {
     case JMOL:
-      sview = new AppJmol(pdbf, id, sq, alignPanel, useinJmolsuperpos,
-              usetoColourbyseq, jmolColouring, fileloc, rect, vid);
+      sview = new AppJmol(pdbf, id, sq, alignPanel, useinViewerSuperpos,
+              usetoColourbyseq, viewerColouring, fileloc, rect, vid);
       break;
     case CHIMERA:
       Cache.log.error("Unsupported structure viewer type "
index 34398fe..13af0e8 100644 (file)
@@ -1,5 +1,8 @@
 package jalview.gui;
 
+import jalview.gui.ViewSelectionMenu.ViewSetProvider;
+import jalview.jbgui.GStructureViewer;
+
 import java.awt.Component;
 import java.util.ArrayList;
 import java.util.List;
@@ -7,9 +10,6 @@ import java.util.Vector;
 
 import javax.swing.JMenuItem;
 
-import jalview.gui.ViewSelectionMenu.ViewSetProvider;
-import jalview.jbgui.GStructureViewer;
-
 /**
  * Base class with common functionality for JMol, Chimera or other structure
  * viewers.
@@ -81,10 +81,7 @@ public abstract class StructureViewerBase extends GStructureViewer
     this.viewId = viewId;
   }
 
-  public String getStateInfo()
-  {
-    return "";
-  }
+  public abstract String getStateInfo();
 
   protected void buildActionMenu()
   {
@@ -115,4 +112,114 @@ public abstract class StructureViewerBase extends GStructureViewer
   {
     this.ap = alp;
   }
+
+  public AlignmentPanel[] getAllAlignmentPanels()
+  {
+    AlignmentPanel[] t, list = new AlignmentPanel[0];
+    for (String setid : _aps)
+    {
+      AlignmentPanel[] panels = PaintRefresher.getAssociatedPanels(setid);
+      if (panels != null)
+      {
+        t = new AlignmentPanel[list.length + panels.length];
+        System.arraycopy(list, 0, t, 0, list.length);
+        System.arraycopy(panels, 0, t, list.length, panels.length);
+        list = t;
+      }
+    }
+  
+    return list;
+  }
+
+  /**
+   * set the primary alignmentPanel reference and add another alignPanel to the
+   * list of ones to use for colouring and aligning
+   * 
+   * @param nap
+   */
+  public void addAlignmentPanel(AlignmentPanel nap)
+  {
+    if (getAlignmentPanel() == null)
+    {
+      setAlignmentPanel(nap);
+    }
+    if (!_aps.contains(nap.av.getSequenceSetId()))
+    {
+      _aps.add(nap.av.getSequenceSetId());
+    }
+  }
+
+  /**
+   * remove any references held to the given alignment panel
+   * 
+   * @param nap
+   */
+  public void removeAlignmentPanel(AlignmentPanel nap)
+  {
+    try
+    {
+      _alignwith.remove(nap);
+      _colourwith.remove(nap);
+      if (getAlignmentPanel() == nap)
+      {
+        setAlignmentPanel(null);
+        for (AlignmentPanel aps : getAllAlignmentPanels())
+        {
+          if (aps != nap)
+          {
+            setAlignmentPanel(aps);
+            break;
+          }
+        }
+      }
+    } catch (Exception ex)
+    {
+    }
+    if (getAlignmentPanel() != null)
+    {
+      buildActionMenu();
+    }
+  }
+
+  public void useAlignmentPanelForSuperposition(AlignmentPanel nap)
+  {
+    addAlignmentPanel(nap);
+    if (!_alignwith.contains(nap))
+    {
+      _alignwith.add(nap);
+    }
+  }
+
+  public void excludeAlignmentPanelForSuperposition(AlignmentPanel nap)
+  {
+    if (_alignwith.contains(nap))
+    {
+      _alignwith.remove(nap);
+    }
+  }
+
+  public void useAlignmentPanelForColourbyseq(AlignmentPanel nap, boolean enableColourBySeq)
+  {
+    useAlignmentPanelForColourbyseq(nap);
+    getBinding().setColourBySequence(enableColourBySeq);
+    seqColour.setSelected(enableColourBySeq);
+    viewerColour.setSelected(!enableColourBySeq);
+  }
+
+  public void useAlignmentPanelForColourbyseq(AlignmentPanel nap)
+  {
+    addAlignmentPanel(nap);
+    if (!_colourwith.contains(nap))
+    {
+      _colourwith.add(nap);
+    }
+  }
+
+  public void excludeAlignmentPanelForColourbyseq(AlignmentPanel nap)
+  {
+    if (_colourwith.contains(nap))
+    {
+      _colourwith.remove(nap);
+    }
+  }
 }
index 12be239..664c903 100644 (file)
@@ -342,4 +342,23 @@ public abstract class AAStructureBindingModel extends
     addSequenceAndChain(pe, seq, null);
   }
 
+  /**
+   * add the given sequences to the mapping scope for the given pdb file handle
+   * 
+   * @param pdbFile
+   *          - pdbFile identifier
+   * @param seq
+   *          - set of sequences it can be mapped to
+   */
+  public void addSequenceForStructFile(String pdbFile, SequenceI[] seq)
+  {
+    for (int pe = 0; pe < getPdbCount(); pe++)
+    {
+      if (getPdbEntry(pe).getFile().equals(pdbFile))
+      {
+        addSequence(pe, seq);
+      }
+    }
+  }
+
 }
\ No newline at end of file