From: jprocter Date: Tue, 29 Jun 2010 16:23:00 +0000 (+0000) Subject: upgrading structure/sequence binding so that a structure view can contain many pdb... X-Git-Tag: Release_2_6~153 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=f8456d4c0b253ae32a4b569e12bb8bf7f7096d65;p=jalview.git upgrading structure/sequence binding so that a structure view can contain many pdb files --- diff --git a/src/MCview/AppletPDBCanvas.java b/src/MCview/AppletPDBCanvas.java index cdad671..c82c331 100755 --- a/src/MCview/AppletPDBCanvas.java +++ b/src/MCview/AppletPDBCanvas.java @@ -1100,9 +1100,9 @@ public class AppletPDBCanvas extends Panel implements MouseListener, // //////////////////////////////// // /StructureListener - public String getPdbFile() + public String[] getPdbFile() { - return pdbentry.getFile(); + return new String[] { pdbentry.getFile() }; } String lastMessage; diff --git a/src/MCview/PDBCanvas.java b/src/MCview/PDBCanvas.java index b3148df..584c076 100755 --- a/src/MCview/PDBCanvas.java +++ b/src/MCview/PDBCanvas.java @@ -1067,9 +1067,9 @@ public class PDBCanvas extends JPanel implements MouseListener, // //////////////////////////////// // /StructureListener - public String getPdbFile() + public String[] getPdbFile() { - return pdbentry.getFile(); + return new String[] { pdbentry.getFile() }; } String lastMessage; diff --git a/src/jalview/appletgui/AppletJmol.java b/src/jalview/appletgui/AppletJmol.java index ff0f5ae..9809859 100644 --- a/src/jalview/appletgui/AppletJmol.java +++ b/src/jalview/appletgui/AppletJmol.java @@ -21,6 +21,7 @@ import java.util.*; import java.awt.*; import java.awt.event.*; +import jalview.api.SequenceStructureBinding; import jalview.datamodel.*; import jalview.structure.*; import jalview.io.*; @@ -34,7 +35,7 @@ import org.jmol.viewer.JmolConstants; import jalview.schemes.*; public class AppletJmol extends EmbmenuFrame implements StructureListener, - JmolStatusListener, KeyListener, ActionListener, ItemListener + JmolStatusListener, KeyListener, ActionListener, ItemListener, SequenceStructureBinding { Menu fileMenu = new Menu("File"); @@ -189,8 +190,9 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, embedMenuIfNeeded(renderPanel); this.add(renderPanel, BorderLayout.CENTER); viewer = JmolViewer.allocateViewer(renderPanel, - new SmarterJmolAdapter(), "jalviewJmol", ap.av.applet.getDocumentBase(), - ap.av.applet.getCodeBase(), "", this); + new SmarterJmolAdapter(), "jalviewJmol", ap.av.applet + .getDocumentBase(), ap.av.applet.getCodeBase(), "", + this); jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true); @@ -270,6 +272,21 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, jalview.bin.JalviewLite.addFrame(this, "Jmol", 400, 400); } + /** + * create a new binding between structures in an existing jmol viewer instance and + * an alignpanel with sequences that have existing PDBFile entries. Note, this does not open a new Jmol window, + * or modify the display of the structures in the original jmol window. + * @param viewer2 + * @param alignPanel + * @param seqs - sequences to search for associations + */ + public AppletJmol(JmolViewer viewer2, AlignmentPanel alignPanel, + SequenceI[] seqs) + { + + // TODO Auto-generated constructor stub + } + public void loadInline(String string) { loadedInline = true; @@ -299,14 +316,30 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, void centerViewer() { + jmolHistory(false); StringBuffer cmd = new StringBuffer(); + String lbl; + int mlength, p,mnum; for (int i = 0; i < chainMenu.getItemCount(); i++) { if (chainMenu.getItem(i) instanceof CheckboxMenuItem) { CheckboxMenuItem item = (CheckboxMenuItem) chainMenu.getItem(i); if (item.getState()) - cmd.append(":" + item.getLabel() + " or "); + { + lbl = item.getLabel(); + mlength = 0; + do + { + p = mlength; + mlength = lbl.indexOf(":", p); + } while (p < mlength && mlength < (lbl.length() - 2)); + mnum = 1+getModelNum(lbl.substring(0, mlength)); + if (mnum>0) + {cmd.append(":" + lbl.substring(mlength + 1) + " /" + + mnum + " or "); + } + } } } @@ -316,25 +349,42 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, viewer .evalString("select *;restrict " + cmd + ";cartoon;center " + cmd); + jmolHistory(true); + } + + private int getModelNum(String modelFileName) + { + String[] mfn = getPdbFile(); + if (mfn == null) + { + return -1; + } + for (int i = 0; i < mfn.length; i++) + { + if (mfn[i].equalsIgnoreCase(modelFileName)) + return i; + } + return -1; } void closeViewer() { viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE); + // remove listeners for all structures in viewer + StructureSelectionManager.getStructureSelectionManager() + .removeStructureViewerListener(this, this.getPdbFile()); + // and shut down jmol viewer.evalStringQuiet("zap"); viewer.setJmolStatusListener(null); - viewer = null; - // We'll need to find out what other - // listeners need to be shut down in Jmol - StructureSelectionManager.getStructureSelectionManager() - .removeStructureViewerListener(this, pdbentry.getId()); + viewer = null; this.setVisible(false); } public void actionPerformed(ActionEvent evt) { + jmolHistory(false); if (evt.getSource() == mappingMenuItem) { jalview.appletgui.CutAndPasteTransfer cap = new jalview.appletgui.CutAndPasteTransfer( @@ -417,8 +467,12 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, centerViewer(); allChainsSelected = false; } + jmolHistory(true); + } + private void jmolHistory(boolean enable) + { + viewer.setBooleanProperty("history", enable); } - public void setJalviewColourScheme(ColourSchemeI cs) { colourBySequence = false; @@ -430,6 +484,7 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, String res; int index; Color col; + jmolHistory(false); Enumeration en = ResidueProperties.aa3Hash.keys(); StringBuffer command = new StringBuffer("select *;color white;"); @@ -447,6 +502,7 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, } viewer.evalStringQuiet(command.toString()); + jmolHistory(true); } public void itemStateChanged(ItemEvent evt) @@ -480,24 +536,42 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, { } + String[] modelFileNames = null; + // //////////////////////////////// // /StructureListener - public String getPdbFile() + public String[] getPdbFile() { - return "???"; + if (modelFileNames == null) + { + String mset[] = new String[viewer.getModelCount()]; + for (int i = 0; i < mset.length; i++) + { + mset[i] = viewer.getModelFileName(i); + } + modelFileNames = mset; + } + return modelFileNames; } String lastMessage; + // jmol/ssm only public void mouseOverStructure(int atomIndex, String strInfo) { int pdbResNum; - - int chainSeparator = strInfo.indexOf(":"); + int mdlSep = strInfo.indexOf("/"); + int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1; if (chainSeparator == -1) + { chainSeparator = strInfo.indexOf("."); - + if (mdlSep > -1 && mdlSep < chainSeparator) + { + chainSeparator1 = chainSeparator; + chainSeparator = mdlSep; + } + } pdbResNum = Integer.parseInt(strInfo.substring( strInfo.indexOf("]") + 1, chainSeparator)); @@ -511,8 +585,27 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, chainId = " "; } + String pdbfilename = pdbentry.getFile(); + if (mdlSep > -1) + { + if (chainSeparator1 == -1) + { + chainSeparator1 = strInfo.indexOf(".", mdlSep); + } + String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1, + chainSeparator1) : strInfo.substring(mdlSep + 1); + try + { + // recover PDB filename for the model hovered over. + pdbfilename = viewer + .getModelFileName(new Integer(mdlId).intValue() - 1); + } catch (Exception e) + { + } + ; + } if (lastMessage == null || !lastMessage.equals(strInfo)) - ssm.mouseOverStructure(pdbResNum, chainId, pdbentry.getFile()); + ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename); lastMessage = strInfo; } @@ -521,31 +614,42 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, StringBuffer eval = new StringBuffer(); + // jmol/ssm only public void highlightAtom(int atomIndex, int pdbResNum, String chain, String pdbfile) { - if (!pdbfile.equals(pdbentry.getFile())) + int mdlNum = 1+getModelNum(pdbfile); + if (mdlNum==0) + { return; + } + jmolHistory(false); + // if (!pdbfile.equals(pdbentry.getFile())) + // return; if (resetLastRes.length() > 0) { viewer.evalStringQuiet(resetLastRes.toString()); } eval.setLength(0); - eval.append("select " + pdbResNum); + eval.append("select " + pdbResNum); // +modelNum resetLastRes.setLength(0); - resetLastRes.append("select " + pdbResNum); + resetLastRes.append("select " + pdbResNum); // +modelNum - eval.append(":"); - resetLastRes.append(":"); if (!chain.equals(" ")) { + eval.append(":"); + resetLastRes.append(":"); eval.append(chain); resetLastRes.append(chain); } - + // if (mdlNum != 0) + { + eval.append(" /" + (mdlNum)); + resetLastRes.append("/" + (mdlNum)); + } eval.append(";wireframe 100;" + eval.toString() + " and not hetero;"); resetLastRes.append(";wireframe 0;" + resetLastRes.toString() @@ -554,6 +658,7 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, eval.append("spacefill 200;select none"); viewer.evalStringQuiet(eval.toString()); + jmolHistory(true); } @@ -584,12 +689,7 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, if (!colourBySequence) return; - - StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile()); - - if (mapping.length < 1) - return; - + String[] files = getPdbFile(); SequenceRenderer sr = new SequenceRenderer(ap.av); boolean showFeatures = false; @@ -607,62 +707,74 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, StringBuffer command = new StringBuffer(); - int lastPos = -1; - for (int s = 0; s < sequence.length; s++) + for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++) { - for (int sp, m = 0; m < mapping.length; m++) + StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]); + + if (mapping == null || mapping.length < 1) + continue; + + int lastPos = -1; + for (int s = 0; s < sequence.length; s++) { - if (mapping[m].getSequence() == sequence[s] - && (sp = ap.av.alignment.findIndex(sequence[s])) > -1) + for (int sp, m = 0; m < mapping.length; m++) { - SequenceI asp = ap.av.alignment.getSequenceAt(sp); - for (int r = 0; r < asp.getLength(); r++) + if (mapping[m].getSequence() == sequence[s] + && (sp = ap.av.alignment.findIndex(sequence[s])) > -1) { - // no mapping to gaps in sequence - if (jalview.util.Comparison.isGap(asp.getCharAt(r))) + SequenceI asp = ap.av.alignment.getSequenceAt(sp); + for (int r = 0; r < asp.getLength(); r++) { - continue; + // no mapping to gaps in sequence + if (jalview.util.Comparison.isGap(asp.getCharAt(r))) + { + continue; + } + int pos = mapping[m].getPDBResNum(asp.findPosition(r)); + + if (pos < 1 || pos == lastPos) + continue; + + lastPos = pos; + + Color col = sr.getResidueBoxColour(sequence[s], r); + + if (showFeatures) + col = fr.findFeatureColour(col, sequence[s], r); + String newSelcom = (mapping[m].getChain() != " " ? ":" + + mapping[m].getChain() : "") + + "/" + + (pdbfnum + 1) + + ".1" + + ";color[" + + col.getRed() + + "," + + col.getGreen() + + "," + + col.getBlue() + "]"; + if (command.toString().endsWith(newSelcom)) + { + command = condenseCommand(command.toString(), pos); + continue; + } + // TODO: deal with case when buffer is too large for Jmol to parse + // - execute command and flush + + command.append(";select " + pos); + command.append(newSelcom); } - int pos = mapping[m].getPDBResNum(asp.findPosition(r)); - - if (pos < 1 || pos == lastPos) - continue; - - lastPos = pos; - - Color col = sr.getResidueBoxColour(sequence[s], r); - - if (showFeatures) - col = fr.findFeatureColour(col, sequence[s], r); - - if (command.toString().endsWith( - ":" + mapping[m].getChain() + ";color[" + col.getRed() - + "," + col.getGreen() + "," + col.getBlue() - + "]")) - { - command = condenseCommand(command.toString(), pos); - continue; - } - - command.append(";select " + pos); - - if (!mapping[m].getChain().equals(" ")) - { - command.append(":" + mapping[m].getChain()); - } - - command.append(";color[" + col.getRed() + "," + col.getGreen() - + "," + col.getBlue() + "]"); + break; } - break; } } } + jmolHistory(false); if (lastCommand == null || !lastCommand.equals(command.toString())) { viewer.evalStringQuiet(command.toString()); } + jmolHistory(true); lastCommand = command.toString(); } @@ -704,7 +816,7 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, { } - public void notifyFileLoaded(String fullPathName, String fileName, + public void notifyFileLoaded(String fullPathName, String fileName2, String modelName, String errorMsg, int modelParts) { if (errorMsg != null) @@ -713,71 +825,93 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, repaint(); return; } - fileLoadingError = null; - - if (fileName != null) + modelFileNames = null; + + String[] modelfilenames = getPdbFile(); + ssm = StructureSelectionManager.getStructureSelectionManager(); + boolean modelsloaded=false; + for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++) { - // TODO: do some checking using the modelPts number of parts against our own estimate of the number of chains - // FILE LOADED OK - jmolpopup.updateComputedMenus(); - viewer - .evalStringQuiet("select backbone;restrict;cartoon;wireframe off;spacefill off"); - - ssm = StructureSelectionManager.getStructureSelectionManager(); - MCview.PDBfile pdb; - if (loadedInline) + String fileName = modelfilenames[modelnum]; + if (fileName != null) { - pdb = ssm.setMapping(sequence, chains, pdbentry.getFile(), - AppletFormatAdapter.PASTE); - pdbentry.setFile("INLINE" + pdb.id); - } - else - { - // TODO: Jmol can in principle retrieve from CLASSLOADER but this needs - // to be tested. See mantis bug - // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605 + // search pdbentries and sequences to find correct pdbentry and sequence[] pair for this filename + if (pdbentry.getFile().equals(fileName)) + { + modelsloaded=true; + MCview.PDBfile pdb; + if (loadedInline) + { + pdb = ssm.setMapping(sequence, chains, pdbentry.getFile(), + AppletFormatAdapter.PASTE); + pdbentry.setFile("INLINE" + pdb.id); + } + else + { + // TODO: Jmol can in principle retrieve from CLASSLOADER but this + // needs + // to be tested. See mantis bug + // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605 - pdb = ssm.setMapping(sequence, chains, pdbentry.getFile(), - AppletFormatAdapter.URL); + pdb = ssm.setMapping(sequence, chains, pdbentry.getFile(), + AppletFormatAdapter.URL); - } + } - pdbentry.setId(pdb.id); + pdbentry.setId(pdb.id); - ssm.addStructureViewerListener(this); + Vector chains = new Vector(); + for (int i = 0; i < pdb.chains.size(); i++) + { + chains.addElement(new String(pdb.id + ":" + + ((MCview.PDBChain) pdb.chains.elementAt(i)).id)); + } + setChainMenuItems(chains); - Vector chains = new Vector(); - for (int i = 0; i < pdb.chains.size(); i++) - { - chains.addElement(((MCview.PDBChain) pdb.chains.elementAt(i)).id); - } - setChainMenuItems(chains); + colourBySequence(ap); - colourBySequence(ap); + StringBuffer title = new StringBuffer(sequence[0].getName() + ":" + + pdbentry.getId()); - StringBuffer title = new StringBuffer(sequence[0].getName() + ":" - + pdbentry.getId()); + if (pdbentry.getProperty() != null) + { + if (pdbentry.getProperty().get("method") != null) + { + title.append(" Method: "); + title.append(pdbentry.getProperty().get("method")); + } + if (pdbentry.getProperty().get("chains") != null) + { + title.append(" Chain:"); + title.append(pdbentry.getProperty().get("chains")); + } + } + + this.setTitle(title.toString()); - if (pdbentry.getProperty() != null) - { - if (pdbentry.getProperty().get("method") != null) - { - title.append(" Method: "); - title.append(pdbentry.getProperty().get("method")); } - if (pdbentry.getProperty().get("chains") != null) + else { - title.append(" Chain:"); - title.append(pdbentry.getProperty().get("chains")); + // this is a foreign pdb file that jalview doesn't know about - add it to the dataset + // and try to find a home - either on a matching sequence or as a new sequence. + String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1", + "PDB"); + // parse pdb file into a chain, etc. + // locate best match for pdb in associated views and add mapping to + // ssm + modelsloaded=true; } } + } + if (modelsloaded) { + // FILE LOADED OK + jmolpopup.updateComputedMenus(); + viewer + .evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off"); - this.setTitle(title.toString()); - + ssm.addStructureViewerListener(this); } - else - return; } public void sendConsoleEcho(String strEcho) @@ -813,27 +947,32 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, public void notifyAtomPicked(int atomIndex, String strInfo, String strData) { - if (strData!=null) + if (strData != null) { - System.err.println("Ignoring additional pick data string "+strData); + System.err.println("Ignoring additional pick data string " + strData); } int chainSeparator = strInfo.indexOf(":"); - + int p=0; if (chainSeparator == -1) chainSeparator = strInfo.indexOf("."); String picked = strInfo.substring(strInfo.indexOf("]") + 1, chainSeparator); - - if (strInfo.indexOf(":") > -1) - picked += strInfo.substring(strInfo.indexOf(":") + 1, strInfo + String mdlString=""; + if ((p=strInfo.indexOf(":")) > -1) + picked += strInfo.substring(p + 1, strInfo .indexOf(".")); - picked = "(("+picked+".CA" + ")|("+picked+".P"+"))"; + if ((p=strInfo.indexOf("/"))> -1) + { + mdlString += strInfo.substring(p, strInfo.indexOf(" #")); + } + picked = "((" + picked + ".CA" + mdlString+")|(" + picked + ".P" + mdlString+"))"; + jmolHistory(false); if (!atomsPicked.contains(picked)) { - viewer.evalString("select " + picked + ";label %n %r:%c"); + viewer.evalStringQuiet("select " + picked + ";label %n %r:%c"); atomsPicked.addElement(picked); } else @@ -841,18 +980,19 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, viewer.evalString("select " + picked + ";label off"); atomsPicked.removeElement(picked); } + jmolHistory(true); + } public void notifyAtomHovered(int atomIndex, String strInfo, String data) { - if (data!=null) + if (data != null) { - System.err.println("Ignoring additional hover info: "+data); + System.err.println("Ignoring additional hover info: " + data); } mouseOverStructure(atomIndex, strInfo); } - public void showUrl(String url) { try @@ -885,7 +1025,7 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, public float[][] functionXY(String functionName, int x, int y) { - return null ; + return null; } // /End JmolStatusListener @@ -943,37 +1083,42 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, public void notifyCallback(int type, Object[] data) { - try { - switch (type) + try { - case JmolConstants.CALLBACK_LOADSTRUCT: - notifyFileLoaded((String) data[1], (String) data[2], - (String) data[3], (String) data[4], ((Integer) data[5]).intValue()); - - break; - case JmolConstants.CALLBACK_PICK: - notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1], (String) data[0]); - // also highlight in alignment - case JmolConstants.CALLBACK_HOVER: - notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1], (String) data[0]); - break; - case JmolConstants.CALLBACK_SCRIPT: - notifyScriptTermination((String)data[2], ((Integer)data[3]).intValue()); - break; - case JmolConstants.CALLBACK_ECHO: - sendConsoleEcho((String)data[1]); - break; - case JmolConstants.CALLBACK_MESSAGE: - sendConsoleMessage((data==null) ? ((String) null) : (String)data[1]); - break; - case JmolConstants.CALLBACK_MEASURE: - case JmolConstants.CALLBACK_CLICK: + switch (type) + { + case JmolConstants.CALLBACK_LOADSTRUCT: + notifyFileLoaded((String) data[1], (String) data[2], + (String) data[3], (String) data[4], ((Integer) data[5]) + .intValue()); + + break; + case JmolConstants.CALLBACK_PICK: + notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1], + (String) data[0]); + // also highlight in alignment + case JmolConstants.CALLBACK_HOVER: + notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1], + (String) data[0]); + break; + case JmolConstants.CALLBACK_SCRIPT: + notifyScriptTermination((String) data[2], ((Integer) data[3]) + .intValue()); + break; + case JmolConstants.CALLBACK_ECHO: + sendConsoleEcho((String) data[1]); + break; + case JmolConstants.CALLBACK_MESSAGE: + sendConsoleMessage((data == null) ? ((String) null) + : (String) data[1]); + break; + case JmolConstants.CALLBACK_MEASURE: + case JmolConstants.CALLBACK_CLICK: default: - System.err.println("Unhandled callback "+type+" "+data); + System.err.println("Unhandled callback " + type + " " + data); break; - } - } - catch (Exception e) + } + } catch (Exception e) { System.err.println("Squashed Jmol callback handler error:"); e.printStackTrace(); @@ -994,7 +1139,7 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, case JmolConstants.CALLBACK_ERROR: return true; case JmolConstants.CALLBACK_CLICK: - case JmolConstants.CALLBACK_ANIMFRAME: + case JmolConstants.CALLBACK_ANIMFRAME: case JmolConstants.CALLBACK_MINIMIZATION: case JmolConstants.CALLBACK_RESIZE: case JmolConstants.CALLBACK_SYNC: @@ -1005,8 +1150,9 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener, public void setCallbackFunction(String callbackType, String callbackFunction) { - System.err.println("Ignoring set-callback request to associate "+callbackType+" with function "+callbackFunction); - + System.err.println("Ignoring set-callback request to associate " + + callbackType + " with function " + callbackFunction); + } } diff --git a/src/jalview/gui/AppJmol.java b/src/jalview/gui/AppJmol.java index 7945fa7..dcca874 100644 --- a/src/jalview/gui/AppJmol.java +++ b/src/jalview/gui/AppJmol.java @@ -26,6 +26,7 @@ import java.awt.event.*; import java.io.*; import jalview.jbgui.GStructureViewer; +import jalview.api.SequenceStructureBinding; import jalview.bin.Cache; import jalview.datamodel.*; import jalview.gui.*; @@ -41,7 +42,7 @@ import org.jmol.popup.*; import org.jmol.viewer.JmolConstants; public class AppJmol extends GStructureViewer implements StructureListener, - JmolStatusListener, Runnable + JmolStatusListener, Runnable, SequenceStructureBinding { JmolViewer viewer; @@ -280,14 +281,32 @@ public class AppJmol extends GStructureViewer implements StructureListener, void centerViewer() { + jmolHistory(false); StringBuffer cmd = new StringBuffer(); + String lbl; + int mlength, p,mnum; for (int i = 0; i < chainMenu.getItemCount(); i++) { if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem) { JCheckBoxMenuItem item = (JCheckBoxMenuItem) chainMenu.getItem(i); if (item.isSelected()) - cmd.append(":" + item.getText() + " or "); + { lbl = item.getText(); + mlength = 0; + do + { + p = mlength; + mlength = lbl.indexOf(":", p); + } while (p < mlength && mlength < (lbl.length() - 2)); + if (pdbentry.getId().equals(lbl.substring(0,mlength))) + { + mnum = 1+getModelNum(pdbentry.getFile()); + if (mnum>0) + {cmd.append(":" + lbl.substring(mlength + 1) + " /" + + mnum + " or "); + } + } + } } } @@ -296,19 +315,33 @@ public class AppJmol extends GStructureViewer implements StructureListener, viewer.evalStringQuiet("select *;restrict " + cmd + ";cartoon;center " + cmd); + jmolHistory(true); + } + private int getModelNum(String modelFileName) + { + String[] mfn = getPdbFile(); + if (mfn == null) + { + return -1; + } + for (int i = 0; i < mfn.length; i++) + { + if (mfn[i].equalsIgnoreCase(modelFileName)) + return i; + } + return -1; } void closeViewer() { viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE); + // remove listeners for all structures in viewer + StructureSelectionManager.getStructureSelectionManager() + .removeStructureViewerListener(this, getPdbFile()); + // and shut down jmol viewer.evalStringQuiet("zap"); viewer.setJmolStatusListener(null); viewer = null; - - // We'll need to find out what other - // listeners need to be shut down in Jmol - StructureSelectionManager.getStructureSelectionManager() - .removeStructureViewerListener(this, pdbentry.getFile()); } public void run() @@ -451,15 +484,19 @@ public class AppJmol extends GStructureViewer implements StructureListener, { colourBySequence = false; seqColour.setSelected(false); + jmolHistory(false); viewer.evalStringQuiet("select *;color chain"); + jmolHistory(true); } public void chargeColour_actionPerformed(ActionEvent actionEvent) { colourBySequence = false; seqColour.setSelected(false); + jmolHistory(false); viewer.evalStringQuiet("select *;color white;select ASP,GLU;color red;" + "select LYS,ARG;color blue;select CYS;color yellow"); + jmolHistory(true); } public void zappoColour_actionPerformed(ActionEvent actionEvent) @@ -499,6 +536,7 @@ public class AppJmol extends GStructureViewer implements StructureListener, public void setJalviewColourScheme(ColourSchemeI cs) { + jmolHistory(false); colourBySequence = false; seqColour.setSelected(false); @@ -525,6 +563,7 @@ public class AppJmol extends GStructureViewer implements StructureListener, } viewer.evalStringQuiet(command.toString()); + jmolHistory(true); } public void userColour_actionPerformed(ActionEvent actionEvent) @@ -539,10 +578,16 @@ public class AppJmol extends GStructureViewer implements StructureListener, if (col != null) { + jmolHistory(false); viewer.evalStringQuiet("background [" + col.getRed() + "," + col.getGreen() + "," + col.getBlue() + "];"); + jmolHistory(true); } } + private void jmolHistory(boolean enable) + { + viewer.setBooleanProperty("history", enable); + } public void jmolHelp_actionPerformed(ActionEvent actionEvent) { @@ -554,39 +599,122 @@ public class AppJmol extends GStructureViewer implements StructureListener, { } } + String[] modelFileNames = null; // //////////////////////////////// // /StructureListener - public String getPdbFile() + public String[] getPdbFile() { - return pdbentry.getFile(); + if (modelFileNames == null) + { + String mset[] = new String[viewer.getModelCount()]; + for (int i = 0; i < mset.length; i++) + { + try { + String mname = viewer.getModelFileName(i); + if (mname==null) + { + System.err.println("Model "+i+" has no filename!"); + continue; + } + File fpath = new File(mname); + mset[i] = fpath.toString(); + } catch (Exception e) + { + System.err.println("Couldn't parse "+viewer.getModelFileName(i)+" as a file!"); + } + } + modelFileNames = mset; + } + return modelFileNames; } Pattern pattern = Pattern - .compile("\\[(.*)\\]([0-9]+)(:[a-zA-Z]*)?\\.([a-zA-Z]+)(/[0-9]*)?"); + .compile("\\[(.*)\\]([0-9]+)(:[a-zA-Z]*)?\\.([a-zA-Z]+).*(/[0-9]*)?"); String lastMessage; public void mouseOverStructure(int atomIndex, String strInfo) { + // copied from AppJmol - will be refactored to binding eventually + int pdbResNum; + int mdlSep = strInfo.indexOf("/"); + int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1; + + if (chainSeparator == -1) + { + chainSeparator = strInfo.indexOf("."); + if (mdlSep > -1 && mdlSep < chainSeparator) + { + chainSeparator1 = chainSeparator; + chainSeparator = mdlSep; + } + } + pdbResNum = Integer.parseInt(strInfo.substring( + strInfo.indexOf("]") + 1, chainSeparator)); + + String chainId; + + if (strInfo.indexOf(":") > -1) + chainId = strInfo.substring(strInfo.indexOf(":") + 1, strInfo + .indexOf(".")); + else + { + chainId = " "; + } + + String pdbfilename = pdbentry.getFile(); + if (mdlSep > -1) + { + if (chainSeparator1 == -1) + { + chainSeparator1 = strInfo.indexOf(".", mdlSep); + } + String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1, + chainSeparator1) : strInfo.substring(mdlSep + 1); + try + { + // recover PDB filename for the model hovered over. + pdbfilename = viewer + .getModelFileName(new Integer(mdlId).intValue() - 1); + } catch (Exception e) + { + } + ; + } + if (lastMessage == null || !lastMessage.equals(strInfo)) + ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename); + + lastMessage = strInfo; +/* + * Old Implementation based on Pattern regex. Matcher matcher = pattern.matcher(strInfo); matcher.find(); matcher.group(1); int pdbResNum = Integer.parseInt(matcher.group(2)); String chainId = matcher.group(3); - + if (chainId != null) chainId = chainId.substring(1, chainId.length()); else { chainId = " "; } + String mdlId = matcher.group(4); + String pdbfilename = pdbentry.getFile(); + if (mdlId!=null && mdlId.length()>0) + { + try { + // recover PDB filename for the model hovered over. + pdbfilename = viewer.getModelFileName(new Integer(mdlId).intValue()-1); + } catch (Exception e) {}; + } if (lastMessage == null || !lastMessage.equals(strInfo)) { - ssm.mouseOverStructure(pdbResNum, chainId, pdbentry.getFile()); + ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename); } - lastMessage = strInfo; + lastMessage = strInfo; */ } StringBuffer resetLastRes = new StringBuffer(); @@ -596,38 +724,47 @@ public class AppJmol extends GStructureViewer implements StructureListener, public void highlightAtom(int atomIndex, int pdbResNum, String chain, String pdbfile) { - // TODO: rna: remove CA dependency in select string - if (!pdbfile.equals(pdbentry.getFile())) + int mdlNum = 1+getModelNum(pdbfile); + if (mdlNum==0) + { return; + } + jmolHistory(false); + // if (!pdbfile.equals(pdbentry.getFile())) + // return; if (resetLastRes.length() > 0) { viewer.evalStringQuiet(resetLastRes.toString()); } eval.setLength(0); - eval.append("select " + pdbResNum); + eval.append("select " + pdbResNum); // +modelNum resetLastRes.setLength(0); - resetLastRes.append("select " + pdbResNum); + resetLastRes.append("select " + pdbResNum); // +modelNum - eval.append(":"); - resetLastRes.append(":"); if (!chain.equals(" ")) { + eval.append(":"); + resetLastRes.append(":"); eval.append(chain); resetLastRes.append(chain); } - - eval.append(";wireframe 100;" + eval.toString() + " and not hetero;"); // ".*;"); + // if (mdlNum != 0) + { + eval.append(" /" + (mdlNum)); + resetLastRes.append(" /" + (mdlNum)); + } + eval.append(";wireframe 100;" + eval.toString() + " and not hetero;"); resetLastRes.append(";wireframe 0;" + resetLastRes.toString() - // + ".*;spacefill 0;"); - + " and not hetero;spacefill 0;"); + + " and not hetero; spacefill 0;"); eval.append("spacefill 200;select none"); - // System.out.println("jmol:\n"+eval+"\n"); + viewer.evalStringQuiet(eval.toString()); + jmolHistory(true); } public Color getColour(int atomIndex, int pdbResNum, String chain, @@ -658,11 +795,8 @@ public class AppJmol extends GStructureViewer implements StructureListener, if (!colourBySequence || ap.alignFrame.getCurrentView() != ap.av) return; - StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile()); - - if (mapping.length < 1) - return; - + String[] files = getPdbFile(); + SequenceRenderer sr = new SequenceRenderer(ap.av); boolean showFeatures = false; @@ -679,6 +813,13 @@ public class AppJmol extends GStructureViewer implements StructureListener, } StringBuffer command = new StringBuffer(); + for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++) + { + StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]); + + if (mapping == null || mapping.length < 1) + continue; + int lastPos = -1; for (int sp, s = 0; s < sequence.length; s++) @@ -707,36 +848,38 @@ public class AppJmol extends GStructureViewer implements StructureListener, if (showFeatures) col = fr.findFeatureColour(col, asp, r); - - if (command.toString().endsWith( - ":" + mapping[m].getChain() + ";color[" + col.getRed() - + "," + col.getGreen() + "," + col.getBlue() - + "]")) + String newSelcom = (mapping[m].getChain() != " " ? ":" + + mapping[m].getChain() : "") + + "/" + + (pdbfnum + 1) + + ".1" + + ";color[" + + col.getRed() + + "," + + col.getGreen() + + "," + + col.getBlue() + "]"; + if (command.toString().endsWith(newSelcom)) { command = condenseCommand(command, pos); continue; } command.append(";select " + pos); - - if (!mapping[m].getChain().equals(" ")) - { - command.append(":" + mapping[m].getChain()); - } - - command.append(";color[" + col.getRed() + "," + col.getGreen() - + "," + col.getBlue() + "]"); - + command.append(newSelcom); } break; } } + } } + jmolHistory(false); if (lastCommand == null || !lastCommand.equals(command.toString())) { viewer.evalStringQuiet(command.toString()); } + jmolHistory(true); lastCommand = command.toString(); } @@ -778,7 +921,7 @@ public class AppJmol extends GStructureViewer implements StructureListener, System.out.println("JMOL CREATE IMAGE"); } - public void notifyFileLoaded(String fullPathName, String fileName, + public void notifyFileLoaded(String fullPathName, String fileName2, String modelName, String errorMsg, int modelParts) { if (errorMsg != null) @@ -789,29 +932,38 @@ public class AppJmol extends GStructureViewer implements StructureListener, } fileLoadingError = null; + modelFileNames = null; + + String[] modelfilenames = getPdbFile(); + ssm = StructureSelectionManager.getStructureSelectionManager(); + boolean modelsloaded=false; + for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++) + { + String fileName = modelfilenames[modelnum]; if (fileName != null) { - // TODO: do some checking using the modelPts number of parts against our own estimate of the number of chains + modelsloaded=true; + // search pdbentries and sequences to find correct pdbentry and sequence[] pair for this filename + if (pdbentry.getFile().equals(fileName)) + { + // TODO: do some checking using the modelPts number of parts against our + // own estimate of the number of chains // FILE LOADED OK - ssm = StructureSelectionManager.getStructureSelectionManager(); MCview.PDBfile pdbFile = ssm.setMapping(sequence, chains, pdbentry .getFile(), AppletFormatAdapter.FILE); - ssm.addStructureViewerListener(this); Vector chains = new Vector(); for (int i = 0; i < pdbFile.chains.size(); i++) { chains - .addElement(((MCview.PDBChain) pdbFile.chains.elementAt(i)).id); + .addElement(new String(pdbFile.id+":"+((MCview.PDBChain) pdbFile.chains.elementAt(i)).id)); } setChainMenuItems(chains); - jmolpopup.updateComputedMenus(); - if (!loadingFromArchive) { viewer - .evalStringQuiet("select backbone;restrict;cartoon;wireframe off;spacefill off"); + .evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off"); colourBySequence(ap); } @@ -820,8 +972,23 @@ public class AppJmol extends GStructureViewer implements StructureListener, loadingFromArchive = false; } - else - return; + else { + // this is a foreign pdb file that jalview doesn't know about - add it to the dataset + // and try to find a home - either on a matching sequence or as a new sequence. + String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1", + "PDB"); + // parse pdb file into a chain, etc. + // locate best match for pdb in associated views and add mapping to + // ssm + modelsloaded=true; + } + } + } + if (modelsloaded) + { + ssm.addStructureViewerListener(this); + jmolpopup.updateComputedMenus(); + } } public void sendConsoleEcho(String strEcho) @@ -854,10 +1021,12 @@ public class AppJmol extends GStructureViewer implements StructureListener, public void notifyAtomPicked(int atomIndex, String strInfo, String strData) { - if (strData!=null) + if (strData != null) { - Cache.log.info("Non null pick data string: "+strData+" (other info: '"+strInfo+"' pos "+atomIndex+")"); + Cache.log.info("Non null pick data string: " + strData + + " (other info: '" + strInfo + "' pos " + atomIndex + ")"); } + /* Matcher matcher = pattern.matcher(strInfo); matcher.find(); @@ -867,17 +1036,35 @@ public class AppJmol extends GStructureViewer implements StructureListener, String picked = resnum; + if (chainId != null) picked += (":" + chainId.substring(1, chainId.length())); - - picked = "(("+picked+".CA" + ")|("+picked+".P"+"))"; - +*/ + int chainSeparator = strInfo.indexOf(":"); + int p=0; + if (chainSeparator == -1) + chainSeparator = strInfo.indexOf("."); + + String picked = strInfo.substring(strInfo.indexOf("]") + 1, + chainSeparator); + String mdlString=""; + if ((p=strInfo.indexOf(":")) > -1) + picked += strInfo.substring(p + 1, strInfo + .indexOf(".")); + + if ((p=strInfo.indexOf("/"))> -1) + { + mdlString += strInfo.substring(p, strInfo.indexOf(" #")); + } + picked = "((" + picked + ".CA" + mdlString+")|(" + picked + ".P" + mdlString+"))"; + jmolHistory(false); if (!atomsPicked.contains(picked)) { - if (chainId != null) + // TODO: re-instate chain ID separator dependent labelling for both applet and application +// if (chainId != null) viewer.evalString("select " + picked + ";label %n %r:%c"); - else - viewer.evalString("select " + picked + ";label %n %r"); +// else +// viewer.evalString("select " + picked + ";label %n %r"); atomsPicked.addElement(picked); } else @@ -885,7 +1072,7 @@ public class AppJmol extends GStructureViewer implements StructureListener, viewer.evalString("select " + picked + ";label off"); atomsPicked.removeElement(picked); } - + jmolHistory(true); if (scriptWindow != null) { scriptWindow.sendConsoleMessage(strInfo); @@ -895,9 +1082,10 @@ public class AppJmol extends GStructureViewer implements StructureListener, public void notifyAtomHovered(int atomIndex, String strInfo, String data) { - if (data!=null) + if (data != null) { - Cache.log.info("Non null hover data string: "+data+" (other info: '"+strInfo+"' pos "+atomIndex+")"); + Cache.log.info("Non null hover data string: " + data + + " (other info: '" + strInfo + "' pos " + atomIndex + ")"); } mouseOverStructure(atomIndex, strInfo); } @@ -905,11 +1093,12 @@ public class AppJmol extends GStructureViewer implements StructureListener, @Override public void showUrl(String url) { - try { + try + { jalview.util.BrowserLauncher.openURL(url); } catch (IOException e) { - Cache.log.error("Failed to launch Jmol-associated url "+url,e); + Cache.log.error("Failed to launch Jmol-associated url " + url, e); // TODO: 2.6 : warn user if browser was not configured. } } @@ -1024,39 +1213,44 @@ public class AppJmol extends GStructureViewer implements StructureListener, @Override public void notifyCallback(int type, Object[] data) { - try { - switch (type) + try { - case JmolConstants.CALLBACK_LOADSTRUCT: - notifyFileLoaded((String) data[1], (String) data[2], - (String) data[3], (String) data[4], ((Integer) data[5]).intValue()); - - break; - case JmolConstants.CALLBACK_PICK: - notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1], (String) data[0]); - // also highlight in alignment - case JmolConstants.CALLBACK_HOVER: - notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1], (String) data[0]); - break; - case JmolConstants.CALLBACK_SCRIPT: - notifyScriptTermination((String)data[2], ((Integer)data[3]).intValue()); - break; - case JmolConstants.CALLBACK_ECHO: - sendConsoleEcho((String)data[1]); - break; - case JmolConstants.CALLBACK_MESSAGE: - sendConsoleMessage((data==null) ? ((String) null) : (String)data[1]); - break; - case JmolConstants.CALLBACK_MEASURE: - case JmolConstants.CALLBACK_CLICK: + switch (type) + { + case JmolConstants.CALLBACK_LOADSTRUCT: + notifyFileLoaded((String) data[1], (String) data[2], + (String) data[3], (String) data[4], ((Integer) data[5]) + .intValue()); + + break; + case JmolConstants.CALLBACK_PICK: + notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1], + (String) data[0]); + // also highlight in alignment + case JmolConstants.CALLBACK_HOVER: + notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1], + (String) data[0]); + break; + case JmolConstants.CALLBACK_SCRIPT: + notifyScriptTermination((String) data[2], ((Integer) data[3]) + .intValue()); + break; + case JmolConstants.CALLBACK_ECHO: + sendConsoleEcho((String) data[1]); + break; + case JmolConstants.CALLBACK_MESSAGE: + sendConsoleMessage((data == null) ? ((String) null) + : (String) data[1]); + break; + case JmolConstants.CALLBACK_MEASURE: + case JmolConstants.CALLBACK_CLICK: default: - System.err.println("Unhandled callback "+type+" "+data); + System.err.println("Unhandled callback " + type + " " + data); break; - } - } - catch (Exception e) + } + } catch (Exception e) { - Cache.log.warn("Squashed Jmol callback handler error: ",e); + Cache.log.warn("Squashed Jmol callback handler error: ", e); } } @@ -1075,7 +1269,7 @@ public class AppJmol extends GStructureViewer implements StructureListener, case JmolConstants.CALLBACK_ERROR: return true; case JmolConstants.CALLBACK_CLICK: - case JmolConstants.CALLBACK_ANIMFRAME: + case JmolConstants.CALLBACK_ANIMFRAME: case JmolConstants.CALLBACK_MINIMIZATION: case JmolConstants.CALLBACK_RESIZE: case JmolConstants.CALLBACK_SYNC: @@ -1087,8 +1281,9 @@ public class AppJmol extends GStructureViewer implements StructureListener, public void setCallbackFunction(String callbackType, String callbackFunction) { - Cache.log.debug("Ignoring set-callback request to associate "+callbackType+" with function "+callbackFunction); - + Cache.log.debug("Ignoring set-callback request to associate " + + callbackType + " with function " + callbackFunction); + } } diff --git a/src/jalview/structure/StructureListener.java b/src/jalview/structure/StructureListener.java index 940a782..103c854 100644 --- a/src/jalview/structure/StructureListener.java +++ b/src/jalview/structure/StructureListener.java @@ -19,7 +19,7 @@ package jalview.structure; public interface StructureListener { - public String getPdbFile(); + public String[] getPdbFile(); public void mouseOverStructure(int atomIndex, String strInfo); diff --git a/src/jalview/structure/StructureSelectionManager.java b/src/jalview/structure/StructureSelectionManager.java index 483f1a4..d2b336d 100644 --- a/src/jalview/structure/StructureSelectionManager.java +++ b/src/jalview/structure/StructureSelectionManager.java @@ -133,10 +133,12 @@ public class StructureSelectionManager for (int i = 0; i < pdb.chains.size(); i++) { - - // TODO: correctly determine sequence type for mixed na/peptide structures + + // TODO: correctly determine sequence type for mixed na/peptide + // structures AlignSeq as = new AlignSeq(sequence[s], ((PDBChain) pdb.chains - .elementAt(i)).sequence, ((PDBChain)pdb.chains.elementAt(i)).isNa ? AlignSeq.DNA : AlignSeq.PEP); + .elementAt(i)).sequence, ((PDBChain) pdb.chains + .elementAt(i)).isNa ? AlignSeq.DNA : AlignSeq.PEP); as.calcScoreMatrix(); as.traceAlignment(); PDBChain chain = ((PDBChain) pdb.chains.elementAt(i)); @@ -222,32 +224,42 @@ public class StructureSelectionManager return pdb; } - public void removeStructureViewerListener(Object svl, String pdbfile) + public void removeStructureViewerListener(Object svl, String[] pdbfiles) { listeners.removeElement(svl); - + if (pdbfiles==null) + { + return; + } boolean removeMapping = true; - + String[] handlepdbs; + Vector pdbs = new Vector(); + for (int i = 0; i < pdbfiles.length; pdbs.addElement(pdbfiles[i++])) + ; StructureListener sl; for (int i = 0; i < listeners.size(); i++) { if (listeners.elementAt(i) instanceof StructureListener) { sl = (StructureListener) listeners.elementAt(i); - if (sl.getPdbFile().equals(pdbfile)) + handlepdbs = sl.getPdbFile(); + for (int j = 0; j < handlepdbs.length; j++) { - removeMapping = false; - break; + if (pdbs.contains(handlepdbs[j])) + { + pdbs.removeElement(handlepdbs[j]); + } } + } } - - if (removeMapping && mappings != null) + + if (pdbs.size()>0 && mappings != null) { Vector tmp = new Vector(); for (int i = 0; i < mappings.length; i++) { - if (!mappings[i].pdbfile.equals(pdbfile)) + if (!pdbs.contains(mappings[i].pdbfile)) { tmp.addElement(mappings[i]); }