From 0c5e8f8ba81b913c63b60d7670d66aca661ea4f5 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Thu, 8 Jan 2015 15:05:31 +0000 Subject: [PATCH] JAL-1588 part work save/restore of Chimera session --- schemas/jalview.xsd | 9 +- .../ext/rbvi/chimera/JalviewChimeraBinding.java | 26 +- src/jalview/gui/AlignFrame.java | 7 +- src/jalview/gui/AppJmol.java | 112 ----- src/jalview/gui/AppJmolBinding.java | 19 - src/jalview/gui/ChimeraViewFrame.java | 141 ++---- src/jalview/gui/Desktop.java | 29 ++ src/jalview/gui/Jalview2XML.java | 456 +++++++++++--------- src/jalview/gui/StructureViewer.java | 30 +- src/jalview/gui/StructureViewerBase.java | 121 +++++- .../structures/models/AAStructureBindingModel.java | 19 + 11 files changed, 505 insertions(+), 464 deletions(-) diff --git a/schemas/jalview.xsd b/schemas/jalview.xsd index 137f7fb..27f952d 100755 --- a/schemas/jalview.xsd +++ b/schemas/jalview.xsd @@ -203,14 +203,7 @@ - - - -Full path name to a saved Chimera session file (usually a .py file). - - - + diff --git a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java index 34dd3f7..6e6f5ee 100644 --- a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java +++ b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java @@ -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 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; + } + } diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 11cb909..27e8ca0 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -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 })); } diff --git a/src/jalview/gui/AppJmol.java b/src/jalview/gui/AppJmol.java index 55288d0..bd4a393 100644 --- a/src/jalview/gui/AppJmol.java +++ b/src/jalview/gui/AppJmol.java @@ -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. */ diff --git a/src/jalview/gui/AppJmolBinding.java b/src/jalview/gui/AppJmolBinding.java index c70380c..131f5bb 100644 --- a/src/jalview/gui/AppJmolBinding.java +++ b/src/jalview/gui/AppJmolBinding.java @@ -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) diff --git a/src/jalview/gui/ChimeraViewFrame.java b/src/jalview/gui/ChimeraViewFrame.java index bc985df..4e313b5 100644 --- a/src/jalview/gui/ChimeraViewFrame.java +++ b/src/jalview/gui/ChimeraViewFrame.java @@ -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; } } diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 06af0c1..70c8355 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -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.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; diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java index c960287..9ba8fb7 100644 --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -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 fileData = new HashMap(); @@ -600,6 +603,7 @@ public class Jalview2XML boolean storeDS, JarOutputStream jout) { initSeqRefs(); + List viewIds = new ArrayList(); List userColours = new ArrayList(); 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 viewIds = new ArrayList(); // 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 entry : jmolViewIds.entrySet()) + { + createOrLinkStructureViewer(entry, af, ap); + } + } + + /** + * + * @param viewerData + * @param af + * @param ap + */ + protected void createOrLinkStructureViewer( + Entry 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 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 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 viewerData, AlignFrame af) + { + final ViewerData svattrib = viewerData.getValue(); + String state = svattrib.stateData; + List pdbfilenames = new ArrayList(); + List seqmaps = new ArrayList(); + List pdbids = new ArrayList(); + StringBuilder newFileLoc = new StringBuilder(64); + int cp = 0, ncp, ecp; + Map 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) 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 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 pdbfilenames = new Vector(); - Vector seqmaps = new Vector(); - Vector pdbids = new Vector(); + // 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) 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) 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) 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 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 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 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) 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 { diff --git a/src/jalview/gui/StructureViewer.java b/src/jalview/gui/StructureViewer.java index c204fec..7d986c8 100644 --- a/src/jalview/gui/StructureViewer.java +++ b/src/jalview/gui/StructureViewer.java @@ -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 " diff --git a/src/jalview/gui/StructureViewerBase.java b/src/jalview/gui/StructureViewerBase.java index 34398fe..13af0e8 100644 --- a/src/jalview/gui/StructureViewerBase.java +++ b/src/jalview/gui/StructureViewerBase.java @@ -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); + } + } } diff --git a/src/jalview/structures/models/AAStructureBindingModel.java b/src/jalview/structures/models/AAStructureBindingModel.java index 12be239..664c903 100644 --- a/src/jalview/structures/models/AAStructureBindingModel.java +++ b/src/jalview/structures/models/AAStructureBindingModel.java @@ -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 -- 1.7.10.2