X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fext%2Fjmol%2FJalviewJmolBinding.java;h=dc18369aa2678804f1061b59b12552d9b3cc661b;hb=67f21ba986462faaa66c606709463fff6c29c116;hp=fe5c9803facec08c4efc5328ea5bba46883e5a0a;hpb=9ae9207767c6ddad56fa405423935c924e959d93;p=jalview.git diff --git a/src/jalview/ext/jmol/JalviewJmolBinding.java b/src/jalview/ext/jmol/JalviewJmolBinding.java index fe5c980..dc18369 100644 --- a/src/jalview/ext/jmol/JalviewJmolBinding.java +++ b/src/jalview/ext/jmol/JalviewJmolBinding.java @@ -20,33 +20,19 @@ */ package jalview.ext.jmol; -import jalview.api.FeatureRenderer; -import jalview.datamodel.AlignmentI; -import jalview.datamodel.HiddenColumns; -import jalview.datamodel.PDBEntry; -import jalview.datamodel.SequenceI; -import jalview.gui.IProgressIndicator; -import jalview.gui.StructureViewer.ViewerType; -import jalview.io.DataSourceType; -import jalview.io.StructureFile; -import jalview.structure.AtomSpec; -import jalview.structure.StructureCommandsI.SuperposeData; -import jalview.structure.StructureSelectionManager; -import jalview.structures.models.AAStructureBindingModel; -import jalview.util.MessageManager; - import java.awt.Container; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.io.File; import java.net.URL; import java.util.ArrayList; -import java.util.BitSet; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.Vector; +import javax.swing.SwingUtilities; + import org.jmol.adapter.smarter.SmarterJmolAdapter; import org.jmol.api.JmolAppConsoleInterface; import org.jmol.api.JmolSelectionListener; @@ -55,6 +41,26 @@ import org.jmol.api.JmolViewer; import org.jmol.c.CBK; import org.jmol.viewer.Viewer; +import jalview.api.AlignmentViewPanel; +import jalview.api.FeatureRenderer; +import jalview.api.FeatureSettingsModelI; +import jalview.api.SequenceRenderer; +import jalview.bin.Console; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.SequenceI; +import jalview.gui.AppJmol; +import jalview.gui.IProgressIndicator; +import jalview.gui.StructureViewer.ViewerType; +import jalview.io.DataSourceType; +import jalview.io.StructureFile; +import jalview.structure.AtomSpec; +import jalview.structure.StructureCommand; +import jalview.structure.StructureCommandI; +import jalview.structure.StructureSelectionManager; +import jalview.structures.models.AAStructureBindingModel; +import jalview.ws.dbsources.Pdb; +import javajs.util.BS; + public abstract class JalviewJmolBinding extends AAStructureBindingModel implements JmolStatusListener, JmolSelectionListener, ComponentListener @@ -85,8 +91,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel setStructureCommands(new JmolCommands()); /* * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(), - * "jalviewJmol", ap.av.applet .getDocumentBase(), - * ap.av.applet.getCodeBase(), "", this); + * "jalviewJmol", ap.av.applet .getDocumentBase(), ap.av.applet.getCodeBase(), + * "", this); * * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true); */ @@ -114,50 +120,64 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel return getViewerTitle("Jmol", true); } - public void closeViewer() + private String jmolScript(String script) { - // remove listeners for all structures in viewer - getSsm().removeStructureViewerListener(this, this.getStructureFiles()); - jmolViewer.dispose(); - lastCommand = null; - jmolViewer = null; - releaseUIResources(); + return jmolScript(script, false); + } + + private String jmolScript(String script, boolean useScriptWait) + { + Console.debug(">>Jmol>> " + script); + String s; + if (useScriptWait) + { + s = jmolViewer.scriptWait(script); + } + else + { + s = jmolViewer.evalStringQuiet(script); // scriptWait(script); BH + } + Console.debug("< executeCommand(String command, boolean getReply) + public List executeCommand(StructureCommandI command, + boolean getReply) { if (command == null) { return null; } + String cmd = command.getCommand(); jmolHistory(false); - if (lastCommand == null || !lastCommand.equals(command)) + if (lastCommand == null || !lastCommand.equals(cmd)) { - jmolViewer.evalStringQuiet(command + "\n"); + jmolScript(cmd + "\n"); } jmolHistory(true); - lastCommand = command; + lastCommand = cmd; return null; } public void createImage(String file, String type, int quality) { - System.out.println("JMOL CREATE IMAGE"); + jalview.bin.Console.outPrintln("JMOL CREATE IMAGE"); } @Override public String createImage(String fileName, String type, Object textOrBytes, int quality) { - System.out.println("JMOL CREATE IMAGE"); + jalview.bin.Console.outPrintln("JMOL CREATE IMAGE"); return null; } @Override public String eval(String strEval) { - // System.out.println(strEval); + // jalview.bin.Console.outPrintln(strEval); // "# 'eval' is implemented only for the applet."; return null; } @@ -189,7 +209,6 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel @Override public synchronized String[] getStructureFiles() { - List mset = new ArrayList<>(); if (jmolViewer == null) { return new String[0]; @@ -199,15 +218,23 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel { int modelCount = jmolViewer.ms.mc; String filePath = null; + List mset = new ArrayList<>(); for (int i = 0; i < modelCount; ++i) { + /* + * defensive check for null as getModelFileName can return null even when model + * count ms.mc is > 0 + */ filePath = jmolViewer.ms.getModelFileName(i); - if (!mset.contains(filePath)) + if (filePath != null && !mset.contains(filePath)) { mset.add(filePath); } } - modelFileNames = mset.toArray(new String[mset.size()]); + if (!mset.isEmpty()) + { + modelFileNames = mset.toArray(new String[mset.size()]); + } } return modelFileNames; @@ -242,74 +269,96 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel { if (resetLastRes.length() > 0) { - jmolViewer.evalStringQuiet(resetLastRes.toString()); + jmolScript(resetLastRes.toString()); resetLastRes.setLength(0); } + StringBuilder highlightCommands=null; for (AtomSpec atom : atoms) { - highlightAtom(atom.getAtomIndex(), atom.getPdbResNum(), + StringBuilder thisAtom = highlightAtom(atom.getAtomIndex(), atom.getPdbResNum(), atom.getChain(), atom.getPdbFile()); + if (thisAtom!=null) { + if (highlightCommands==null) + { + highlightCommands=thisAtom; + } else { + highlightCommands.append(thisAtom); + } + } } + if (highlightCommands!=null) + { + jmolHistory(false); + jmolScript(highlightCommands.toString()); + jmolHistory(true); + } + // Highlight distances between atoms with a 'measure' command - not yet + // working + // if (atoms.size() >= 2) + // { + // StringBuilder sb = new StringBuilder(); + // for (int a = 0; a < atoms.size(); a++) + // { + // AtomSpec speca = atoms.get(a); + // String a_model = getModelIdForFile(speca.getPdbFile()); + // for (int b = a + 1; b < atoms.size(); b++) + // { + // AtomSpec specb = atoms.get(b); + // String b_model = getModelIdForFile(speca.getPdbFile()); + // sb.append("measure ALL (" + speca.getAtomIndex() + " and */" + // + a_model + ") (" + specb.getAtomIndex() + " and */" + // + b_model + ");"); + // } + // } + // jmolHistory(false, useScriptWait); + // jmolScript(sb.toString(), useScriptWait); + // jmolHistory(true, useScriptWait); + // } + } + } // jmol/ssm only - public void highlightAtom(int atomIndex, int pdbResNum, String chain, + private StringBuilder highlightAtom(int atomIndex, int pdbResNum, String chain, String pdbfile) { - if (modelFileNames == null) + String modelId = getModelIdForFile(pdbfile); + if (modelId.isEmpty()) { - return; - } - - // look up file model number for this pdbfile - int mdlNum = 0; - // may need to adjust for URLencoding here - we don't worry about that yet. - while (mdlNum < modelFileNames.length - && !pdbfile.equals(modelFileNames[mdlNum])) - { - mdlNum++; - } - if (mdlNum == modelFileNames.length) - { - return; + return null; } - jmolHistory(false); - + StringBuilder selection = new StringBuilder(32); StringBuilder cmd = new StringBuilder(64); - cmd.append("select ").append(String.valueOf(pdbResNum)); // +modelNum - - resetLastRes.append("select ").append(String.valueOf(pdbResNum)); // +modelNum - - cmd.append(":"); - resetLastRes.append(":"); + selection.append("select ").append(String.valueOf(pdbResNum)); + selection.append(":"); if (!chain.equals(" ")) { - cmd.append(chain); - resetLastRes.append(chain); - } - { - cmd.append(" /").append(String.valueOf(mdlNum + 1)); - resetLastRes.append("/").append(String.valueOf(mdlNum + 1)); + selection.append(chain); } - cmd.append(";wireframe 100;" + cmd.toString() + " and not hetero;"); + selection.append(" /").append(modelId); - resetLastRes.append(";wireframe 0;" + resetLastRes.toString() - + " and not hetero; spacefill 0;"); + cmd.append(selection).append(";wireframe 100;").append(selection) + .append(" and not hetero;").append("spacefill 200;select none"); - cmd.append("spacefill 200;select none"); - - jmolViewer.evalStringQuiet(cmd.toString()); - jmolHistory(true); + resetLastRes.append(selection).append(";wireframe 0;").append(selection) + .append(" and not hetero; spacefill 0;"); + return cmd; } private boolean debug = true; private void jmolHistory(boolean enable) { - jmolViewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off")); + jmolHistory(enable, false); + } + + private void jmolHistory(boolean enable, boolean useScriptWait) + { + jmolScript("History " + ((debug || enable) ? "on" : "off"), + useScriptWait); } public void loadInline(String string) @@ -409,8 +458,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel } /* - * highlight position on alignment(s); if some text is returned, - * show this as a second line on the structure hover tooltip + * highlight position on alignment(s); if some text is returned, show this as a + * second line on the structure hover tooltip */ String label = getSsm().mouseOverStructure(pdbResNum, chainId, pdbfilename); @@ -425,7 +474,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel sb.append(";set hoverLabel \"").append(toks.nextToken()).append(" ") .append(toks.nextToken()); sb.append("|").append(label).append("\""); - executeCommand(sb.toString(), false); + executeCommand(new StructureCommand(sb.toString()), false); } } @@ -438,7 +487,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel lastMessage = strInfo; if (data != null) { - System.err.println("Ignoring additional hover info: " + data + jalview.bin.Console.errPrintln("Ignoring additional hover info: " + data + " (other info: '" + strInfo + "' pos " + atomIndex + ")"); } mouseOverStructure(atomIndex, strInfo); @@ -446,8 +495,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel /* * { if (history != null && strStatus != null && - * !strStatus.equals("Script completed")) { history.append("\n" + strStatus); - * } } + * !strStatus.equals("Script completed")) { history.append("\n" + strStatus); } + * } */ public void notifyAtomPicked(int atomIndex, String strInfo, @@ -455,11 +504,11 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel { /** * this implements the toggle label behaviour copied from the original - * structure viewer, MCView + * structure viewer, mc_view */ if (strData != null) { - System.err.println("Ignoring additional pick data string " + strData); + jalview.bin.Console.errPrintln("Ignoring additional pick data string " + strData); } int chainSeparator = strInfo.indexOf(":"); int p = 0; @@ -486,7 +535,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel if (!atomsPicked.contains(picked)) { - jmolViewer.evalStringQuiet("select " + picked + ";label %n %r:%c"); + jmolScript("select " + picked + ";label %n %r:%c"); atomsPicked.addElement(picked); } else @@ -508,6 +557,28 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel @Override public void notifyCallback(CBK type, Object[] data) { + /* + * ensure processed in AWT thread to avoid risk of deadlocks + */ + SwingUtilities.invokeLater(new Runnable() + { + + @Override + public void run() + { + processCallback(type, data); + } + }); + } + + /** + * Processes one callback notification from Jmol + * + * @param type + * @param data + */ + protected void processCallback(CBK type, Object[] data) + { try { switch (type) @@ -539,7 +610,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel (data == null) ? ((String) null) : (String) data[1]); break; case ERROR: - // System.err.println("Ignoring error callback."); + // jalview.bin.Console.errPrintln("Ignoring error callback."); break; case SYNC: case RESIZE: @@ -549,13 +620,13 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel case CLICK: default: - System.err.println( + jalview.bin.Console.errPrintln( "Unhandled callback " + type + " " + data[1].toString()); break; } } catch (Exception e) { - System.err.println("Squashed Jmol callback handler error:"); + jalview.bin.Console.errPrintln("Squashed Jmol callback handler error:"); e.printStackTrace(); } } @@ -609,6 +680,11 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel modelFileNames = null; boolean notifyLoaded = false; String[] modelfilenames = getStructureFiles(); + if (modelfilenames == null) + { + // Jmol is still loading files! + return; + } // first check if we've lost any structures if (oldmodels != null && oldmodels.length > 0) { @@ -672,8 +748,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel // see JAL-623 - need method of matching pasted data up { pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe], - pdbfile, DataSourceType.PASTE, - getIProgressIndicator()); + pdbfile, DataSourceType.PASTE, getIProgressIndicator()); getPdbEntry(modelnum).setFile("INLINE" + pdb.getId()); matches = true; foundEntry = true; @@ -712,14 +787,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel } if (matches) { - // add an entry for every chain in the model - for (int i = 0; i < pdb.getChains().size(); i++) - { - String chid = pdb.getId() + ":" - + pdb.getChains().elementAt(i).id; - addChainFile(chid, fileName); - getChainNames().add(chid); - } + stashFoundChains(pdb, fileName); notifyLoaded = true; } } @@ -748,7 +816,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel // } if (!isLoadingFromArchive()) { - jmolViewer.evalStringQuiet( + jmolScript( "model *; select backbone;restrict;cartoon;wireframe off;spacefill off"); } // register ourselves as a listener and notify the gui that it needs to @@ -759,7 +827,9 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel FeatureRenderer fr = getFeatureRenderer(null); if (fr != null) { - fr.featuresAdded(); + FeatureSettingsModelI colours = new Pdb().getFeatureColourScheme(); + ((AppJmol) getViewer()).getAlignmentPanel().av + .applyFeaturesStyle(colours); } refreshGUI(); loadNotifiesHandled++; @@ -788,8 +858,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel public abstract void sendConsoleEcho(String strEcho); /* * { showConsole(true); * - * history.append("\n" + - * strEcho); } + * history.append("\n" + strEcho); } */ // /End JmolStatusListener @@ -806,14 +875,16 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel public void setCallbackFunction(String callbackType, String callbackFunction) { - System.err.println("Ignoring set-callback request to associate " + jalview.bin.Console.errPrintln("Ignoring set-callback request to associate " + callbackType + " with function " + callbackFunction); } public void showHelp() { - showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp"); + showUrl("http://wiki.jmol.org" + // BH 2018 "http://jmol.sourceforge.net/docs/JmolUserGuide/" + , "jmolHelp"); } /** @@ -830,7 +901,16 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel */ public abstract void showConsole(boolean show); + public static Viewer getJmolData(JmolParser jmolParser) + { + return (Viewer) JmolViewer.allocateViewer(null, null, null, null, null, + "-x -o -n", jmolParser); + } + /** + * + * + * * @param renderPanel * @param jmolfileio * - when true will initialise jmol's file IO system (should be false @@ -861,13 +941,16 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel * @param consolePanel * - panel to contain Jmol console * @param buttonsToShow - * - buttons to show on the console, in ordr + * - buttons to show on the console, in order */ public void allocateViewer(Container renderPanel, boolean jmolfileio, String htmlName, URL documentBase, URL codeBase, String commandOptions, final Container consolePanel, String buttonsToShow) { + + jalview.bin.Console.errPrintln("Allocating Jmol Viewer: " + commandOptions); + if (commandOptions == null) { commandOptions = ""; @@ -879,7 +962,15 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel jmolViewer.setJmolStatusListener(this); // extends JmolCallbackListener - console = createJmolConsole(consolePanel, buttonsToShow); + try + { + console = createJmolConsole(consolePanel, buttonsToShow); + } catch (Throwable e) + { + jalview.bin.Console.errPrintln("Could not create Jmol application console. " + + e.getMessage()); + e.printStackTrace(); + } if (consolePanel != null) { consolePanel.addComponentListener(this); @@ -891,6 +982,9 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel protected abstract JmolAppConsoleInterface createJmolConsole( Container consolePanel, String buttonsToShow); + // BH 2018 -- Jmol console is not working due to problems with styled + // documents. + protected org.jmol.api.JmolAppConsoleInterface console = null; @Override @@ -955,20 +1049,20 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel } @Override - protected int getModelNoForFile(String pdbFile) + protected String getModelIdForFile(String pdbFile) { if (modelFileNames == null) { - return -1; + return ""; } for (int i = 0; i < modelFileNames.length; i++) { if (modelFileNames[i].equalsIgnoreCase(pdbFile)) { - return i; + return String.valueOf(i + 1); } } - return -1; + return ""; } @Override @@ -976,4 +1070,41 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel { return ViewerType.JMOL; } + + @Override + protected String getModelId(int pdbfnum, String file) + { + return String.valueOf(pdbfnum + 1); + } + + /** + * Returns ".spt" - the Jmol session file extension + * + * @return + * @see https://chemapps.stolaf.edu/jmol/docs/#writemodel + */ + @Override + public String getSessionFileExtension() + { + return ".spt"; + } + + @Override + public void selectionChanged(BS arg0) + { + // TODO Auto-generated method stub + + } + + @Override + public SequenceRenderer getSequenceRenderer(AlignmentViewPanel avp) + { + return new jalview.gui.SequenceRenderer(avp.getAlignViewport()); + } + + @Override + public String getHelpURL() + { + return "http://wiki.jmol.org"; // BH 2018 + } }