-/*\r
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)\r
- * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle\r
- * \r
- * This file is part of Jalview.\r
- * \r
- * Jalview is free software: you can redistribute it and/or\r
- * modify it under the terms of the GNU General Public License \r
- * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\r
- * \r
- * Jalview is distributed in the hope that it will be useful, but \r
- * WITHOUT ANY WARRANTY; without even the implied warranty \r
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
- * PURPOSE. See the GNU General Public License for more details.\r
- * \r
- * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.\r
- */\r
-package jalview.ext.jmol;\r
-\r
-import jalview.api.AlignmentViewPanel;\r
-import jalview.api.FeatureRenderer;\r
-import jalview.api.SequenceRenderer;\r
-import jalview.api.SequenceStructureBinding;\r
-import jalview.api.StructureSelectionManagerProvider;\r
-import jalview.datamodel.AlignmentI;\r
-import jalview.datamodel.ColumnSelection;\r
-import jalview.datamodel.PDBEntry;\r
-import jalview.datamodel.SequenceI;\r
-import jalview.io.AppletFormatAdapter;\r
-import jalview.schemes.ColourSchemeI;\r
-import jalview.schemes.ResidueProperties;\r
-import jalview.structure.StructureListener;\r
-import jalview.structure.StructureMapping;\r
-import jalview.structure.StructureSelectionManager;\r
-\r
-import java.awt.Color;\r
-import java.awt.Container;\r
-import java.awt.event.ComponentEvent;\r
-import java.awt.event.ComponentListener;\r
-import java.io.File;\r
-import java.net.URL;\r
-import java.security.AccessControlException;\r
-import java.util.Enumeration;\r
-import java.util.Hashtable;\r
-import java.util.Map;\r
-import java.util.Vector;\r
-\r
-import org.jmol.adapter.smarter.SmarterJmolAdapter;\r
-import org.jmol.api.JmolAppConsoleInterface;\r
-import org.jmol.api.JmolSelectionListener;\r
-import org.jmol.api.JmolStatusListener;\r
-import org.jmol.api.JmolViewer;\r
-import org.jmol.constant.EnumCallback;\r
-import org.jmol.popup.JmolPopup;\r
-\r
-public abstract class JalviewJmolBinding implements StructureListener,\r
- JmolStatusListener, SequenceStructureBinding,\r
- JmolSelectionListener, ComponentListener, StructureSelectionManagerProvider\r
-\r
-{\r
- /**\r
- * set if Jmol state is being restored from some source - instructs binding\r
- * not to apply default display style when structure set is updated for first\r
- * time.\r
- */\r
- private boolean loadingFromArchive = false;\r
-\r
- /**\r
- * state flag used to check if the Jmol viewer's paint method can be called\r
- */\r
- private boolean finishedInit = false;\r
-\r
- public boolean isFinishedInit()\r
- {\r
- return finishedInit;\r
- }\r
-\r
- public void setFinishedInit(boolean finishedInit)\r
- {\r
- this.finishedInit = finishedInit;\r
- }\r
-\r
- boolean allChainsSelected = false;\r
-\r
- /**\r
- * when true, try to search the associated datamodel for sequences that are\r
- * associated with any unknown structures in the Jmol view.\r
- */\r
- private boolean associateNewStructs = false;\r
-\r
- Vector atomsPicked = new Vector();\r
-\r
- public Vector chainNames;\r
-\r
- Hashtable chainFile;\r
-\r
- /**\r
- * array of target chains for seuqences - tied to pdbentry and sequence[]\r
- */\r
- protected String[][] chains;\r
-\r
- boolean colourBySequence = true;\r
-\r
- StringBuffer eval = new StringBuffer();\r
-\r
- public String fileLoadingError;\r
-\r
- /**\r
- * the default or current model displayed if the model cannot be identified\r
- * from the selection message\r
- */\r
- int frameNo = 0;\r
-\r
- protected JmolPopup jmolpopup;\r
-\r
- String lastCommand;\r
-\r
- String lastMessage;\r
-\r
- boolean loadedInline;\r
-\r
- /**\r
- * current set of model filenames loaded in the Jmol instance\r
- */\r
- String[] modelFileNames = null;\r
-\r
- public PDBEntry[] pdbentry;\r
-\r
- /**\r
- * datasource protocol for access to PDBEntrylatest\r
- */\r
- String protocol = null;\r
-\r
- StringBuffer resetLastRes = new StringBuffer();\r
-\r
- /**\r
- * sequences mapped to each pdbentry\r
- */\r
- public SequenceI[][] sequence;\r
-\r
- public StructureSelectionManager ssm;\r
-\r
- public JmolViewer viewer;\r
-\r
- public JalviewJmolBinding(StructureSelectionManager ssm, PDBEntry[] pdbentry, SequenceI[][] sequenceIs,\r
- String[][] chains, String protocol)\r
- {\r
- this.ssm = ssm;\r
- this.sequence = sequenceIs;\r
- this.chains = chains;\r
- this.pdbentry = pdbentry;\r
- this.protocol = protocol;\r
- if (chains == null)\r
- {\r
- this.chains = new String[pdbentry.length][];\r
- }\r
- /*\r
- * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),\r
- * "jalviewJmol", ap.av.applet .getDocumentBase(),\r
- * ap.av.applet.getCodeBase(), "", this);\r
- * \r
- * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);\r
- */\r
- }\r
-\r
- public JalviewJmolBinding(StructureSelectionManager ssm, JmolViewer viewer2)\r
- {\r
- this.ssm = ssm;\r
- viewer = viewer2;\r
- viewer.setJmolStatusListener(this);\r
- viewer.addSelectionListener(this);\r
- }\r
-\r
- /**\r
- * construct a title string for the viewer window based on the data jalview\r
- * knows about\r
- * \r
- * @return\r
- */\r
- public String getViewerTitle()\r
- {\r
- if (sequence == null || pdbentry == null || sequence.length < 1\r
- || pdbentry.length < 1 || sequence[0].length < 1)\r
- {\r
- return ("Jalview Jmol Window");\r
- }\r
- // TODO: give a more informative title when multiple structures are\r
- // displayed.\r
- StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"\r
- + pdbentry[0].getId());\r
-\r
- if (pdbentry[0].getProperty() != null)\r
- {\r
- if (pdbentry[0].getProperty().get("method") != null)\r
- {\r
- title.append(" Method: ");\r
- title.append(pdbentry[0].getProperty().get("method"));\r
- }\r
- if (pdbentry[0].getProperty().get("chains") != null)\r
- {\r
- title.append(" Chain:");\r
- title.append(pdbentry[0].getProperty().get("chains"));\r
- }\r
- }\r
- return title.toString();\r
- }\r
-\r
- /**\r
- * prepare the view for a given set of models/chains. chainList contains\r
- * strings of the form 'pdbfilename:Chaincode'\r
- * \r
- * @param chainList\r
- * list of chains to make visible\r
- */\r
- public void centerViewer(Vector chainList)\r
- {\r
- StringBuffer cmd = new StringBuffer();\r
- String lbl;\r
- int mlength, p;\r
- for (int i = 0, iSize = chainList.size(); i < iSize; i++)\r
- {\r
- mlength = 0;\r
- lbl = (String) chainList.elementAt(i);\r
- do\r
- {\r
- p = mlength;\r
- mlength = lbl.indexOf(":", p);\r
- } while (p < mlength && mlength < (lbl.length() - 2));\r
- // TODO: lookup each pdb id and recover proper model number for it.\r
- cmd.append(":" + lbl.substring(mlength + 1) + " /"\r
- + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");\r
- }\r
- if (cmd.length() > 0)\r
- cmd.setLength(cmd.length() - 4);\r
- evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);\r
- }\r
-\r
- public void closeViewer()\r
- {\r
- viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);\r
- // remove listeners for all structures in viewer\r
- ssm.removeStructureViewerListener(this, this.getPdbFile());\r
- // and shut down jmol\r
- viewer.evalStringQuiet("zap");\r
- viewer.setJmolStatusListener(null);\r
- lastCommand = null;\r
- viewer = null;\r
- releaseUIResources();\r
- }\r
-\r
- /**\r
- * called by JalviewJmolbinding after closeViewer is called - release any\r
- * resources and references so they can be garbage collected.\r
- */\r
- protected abstract void releaseUIResources();\r
-\r
- public void colourByChain()\r
- {\r
- colourBySequence = false;\r
- // TODO: colour by chain should colour each chain distinctly across all\r
- // visible models\r
- // TODO: http://issues.jalview.org/browse/JAL-628\r
- evalStateCommand("select *;color chain");\r
- }\r
-\r
- public void colourByCharge()\r
- {\r
- colourBySequence = false;\r
- evalStateCommand("select *;color white;select ASP,GLU;color red;"\r
- + "select LYS,ARG;color blue;select CYS;color yellow");\r
- }\r
-\r
- /**\r
- * superpose the structures associated with sequences in the alignment\r
- * according to their corresponding positions.\r
- */\r
- public void superposeStructures(AlignmentI alignment)\r
- {\r
- superposeStructures(alignment, -1, null);\r
- }\r
-\r
- /**\r
- * superpose the structures associated with sequences in the alignment\r
- * according to their corresponding positions. ded)\r
- * \r
- * @param refStructure\r
- * - select which pdb file to use as reference (default is -1 - the\r
- * first structure in the alignment)\r
- */\r
- public void superposeStructures(AlignmentI alignment, int refStructure)\r
- {\r
- superposeStructures(alignment, refStructure, null);\r
- }\r
-\r
- /**\r
- * superpose the structures associated with sequences in the alignment\r
- * according to their corresponding positions. ded)\r
- * \r
- * @param refStructure\r
- * - select which pdb file to use as reference (default is -1 - the\r
- * first structure in the alignment)\r
- * @param hiddenCols\r
- * TODO\r
- */\r
- public void superposeStructures(AlignmentI alignment, int refStructure,\r
- ColumnSelection hiddenCols)\r
- {\r
- superposeStructures(new AlignmentI[]\r
- { alignment }, new int[]\r
- { refStructure }, new ColumnSelection[]\r
- { hiddenCols });\r
- }\r
-\r
- public void superposeStructures(AlignmentI[] _alignment,\r
- int[] _refStructure, ColumnSelection[] _hiddenCols)\r
- {\r
- String[] files = getPdbFile();\r
- StringBuffer selectioncom = new StringBuffer();\r
- assert (_alignment.length == _refStructure.length && _alignment.length != _hiddenCols.length);\r
- // union of all aligned positions are collected together.\r
- for (int a = 0; a < _alignment.length; a++)\r
- {\r
- int refStructure = _refStructure[a];\r
- AlignmentI alignment = _alignment[a];\r
- ColumnSelection hiddenCols = _hiddenCols[a];\r
- if (a > 0\r
- && selectioncom.length() > 0\r
- && !selectioncom.substring(selectioncom.length() - 1).equals(\r
- "|"))\r
- {\r
- selectioncom.append("|");\r
- }\r
- // process this alignment\r
- if (refStructure >= files.length)\r
- {\r
- System.err.println("Invalid reference structure value "\r
- + refStructure);\r
- refStructure = -1;\r
- }\r
- if (refStructure < -1)\r
- {\r
- refStructure = -1;\r
- }\r
- StringBuffer command = new StringBuffer();\r
-\r
- boolean matched[] = new boolean[alignment.getWidth()];\r
- for (int m = 0; m < matched.length; m++)\r
- {\r
-\r
- matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;\r
- }\r
-\r
- int commonrpositions[][] = new int[files.length][alignment.getWidth()];\r
- String isel[] = new String[files.length];\r
- // reference structure - all others are superposed in it\r
- String[] targetC = new String[files.length];\r
- String[] chainNames = new String[files.length];\r
- for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)\r
- {\r
- StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);\r
- // RACE CONDITION - getMapping only returns Jmol loaded filenames once Jmol callback has completed. \r
- if (mapping == null || mapping.length < 1)\r
- continue;\r
-\r
- int lastPos = -1;\r
- for (int s = 0; s < sequence[pdbfnum].length; s++)\r
- {\r
- for (int sp, m = 0; m < mapping.length; m++)\r
- {\r
- if (mapping[m].getSequence() == sequence[pdbfnum][s]\r
- && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)\r
- {\r
- if (refStructure == -1)\r
- {\r
- refStructure = pdbfnum;\r
- }\r
- SequenceI asp = alignment.getSequenceAt(sp);\r
- for (int r = 0; r < matched.length; r++)\r
- {\r
- if (!matched[r])\r
- {\r
- continue;\r
- }\r
- matched[r] = false; // assume this is not a good site\r
- if (r >= asp.getLength())\r
- {\r
- continue;\r
- }\r
-\r
- if (jalview.util.Comparison.isGap(asp.getCharAt(r)))\r
- {\r
- // no mapping to gaps in sequence\r
- continue;\r
- }\r
- int t = asp.findPosition(r); // sequence position\r
- int apos = mapping[m].getAtomNum(t);\r
- int pos = mapping[m].getPDBResNum(t);\r
-\r
- if (pos < 1 || pos == lastPos)\r
- {\r
- // can't align unmapped sequence\r
- continue;\r
- }\r
- matched[r] = true; // this is a good ite\r
- lastPos = pos;\r
- // just record this residue position\r
- commonrpositions[pdbfnum][r] = pos;\r
- }\r
- // create model selection suffix\r
- isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";\r
- if (mapping[m].getChain() == null\r
- || mapping[m].getChain().trim().length() == 0)\r
- {\r
- targetC[pdbfnum] = "";\r
- }\r
- else\r
- {\r
- targetC[pdbfnum] = ":" + mapping[m].getChain();\r
- }\r
- chainNames[pdbfnum] = mapping[m].getPdbId()\r
- + targetC[pdbfnum];\r
- // move on to next pdb file\r
- s = sequence[pdbfnum].length;\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- String[] selcom = new String[files.length];\r
- int nmatched = 0;\r
- // generate select statements to select regions to superimpose structures\r
- {\r
- for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)\r
- {\r
- String chainCd = targetC[pdbfnum];\r
- int lpos = -1;\r
- boolean run = false;\r
- StringBuffer molsel = new StringBuffer();\r
- molsel.append("{");\r
- for (int r = 0; r < matched.length; r++)\r
- {\r
- if (matched[r])\r
- {\r
- if (pdbfnum == 0)\r
- {\r
- nmatched++;\r
- }\r
- if (lpos != commonrpositions[pdbfnum][r] - 1)\r
- {\r
- // discontinuity\r
- if (lpos != -1)\r
- {\r
- molsel.append(lpos);\r
- molsel.append(chainCd);\r
- // molsel.append("} {");\r
- molsel.append("|");\r
- }\r
- }\r
- else\r
- {\r
- // continuous run - and lpos >-1\r
- if (!run)\r
- {\r
- // at the beginning, so add dash\r
- molsel.append(lpos);\r
- molsel.append("-");\r
- }\r
- run = true;\r
- }\r
- lpos = commonrpositions[pdbfnum][r];\r
- // molsel.append(lpos);\r
- }\r
- }\r
- // add final selection phrase\r
- if (lpos != -1)\r
- {\r
- molsel.append(lpos);\r
- molsel.append(chainCd);\r
- molsel.append("}");\r
- }\r
- selcom[pdbfnum] = molsel.toString();\r
- selectioncom.append("((");\r
- selectioncom.append(selcom[pdbfnum].substring(1,\r
- selcom[pdbfnum].length() - 1));\r
- selectioncom.append(" )& ");\r
- selectioncom.append(pdbfnum + 1);\r
- selectioncom.append(".1)");\r
- if (pdbfnum < files.length - 1)\r
- {\r
- selectioncom.append("|");\r
- }\r
- }\r
- }\r
- // TODO: consider bailing if nmatched less than 4 because superposition\r
- // not\r
- // well defined.\r
- // TODO: refactor superposable position search (above) from jmol selection\r
- // construction (below)\r
- for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)\r
- {\r
- if (pdbfnum == refStructure)\r
- {\r
- continue;\r
- }\r
- command.append("echo ");\r
- command.append("\"Superposing (");\r
- command.append(chainNames[pdbfnum]);\r
- command.append(") against reference (");\r
- command.append(chainNames[refStructure]);\r
- command.append(")\";\ncompare ");\r
- command.append("{");\r
- command.append(1 + pdbfnum);\r
- command.append(".1} {");\r
- command.append(1 + refStructure);\r
- command.append(".1} SUBSET {*.CA | *.P} ATOMS ");\r
-\r
- // form the matched pair strings\r
- String sep = "";\r
- for (int s = 0; s < 2; s++)\r
- {\r
- command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);\r
- }\r
- command.append(" ROTATE TRANSLATE;\n");\r
- }\r
- System.out.println("Select regions:\n" + selectioncom.toString());\r
- evalStateCommand("select *; cartoons off; backbone; select ("\r
- + selectioncom.toString() + "); cartoons; ");\r
- // selcom.append("; ribbons; ");\r
- System.out.println("Superimpose command(s):\n" + command.toString());\r
-\r
- evalStateCommand(command.toString());\r
- }\r
- if (selectioncom.length() > 0)\r
- {// finally, mark all regions that were superposed.\r
- if (selectioncom.substring(selectioncom.length() - 1).equals("|"))\r
- {\r
- selectioncom.setLength(selectioncom.length() - 1);\r
- }\r
- System.out.println("Select regions:\n" + selectioncom.toString());\r
- evalStateCommand("select *; cartoons off; backbone; select ("\r
- + selectioncom.toString() + "); cartoons; ");\r
- // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());\r
- }\r
- }\r
-\r
- public void evalStateCommand(String command)\r
- {\r
- jmolHistory(false);\r
- if (lastCommand == null || !lastCommand.equals(command))\r
- {\r
- viewer.evalStringQuiet(command + "\n");\r
- }\r
- jmolHistory(true);\r
- lastCommand = command;\r
- }\r
-\r
- /**\r
- * colour any structures associated with sequences in the given alignment\r
- * using the getFeatureRenderer() and getSequenceRenderer() renderers but only\r
- * if colourBySequence is enabled.\r
- */\r
- public void colourBySequence(boolean showFeatures,\r
- jalview.api.AlignmentViewPanel alignmentv)\r
- {\r
- if (!colourBySequence)\r
- return;\r
- if (ssm == null)\r
- {\r
- return;\r
- }\r
- String[] files = getPdbFile();\r
-\r
- SequenceRenderer sr = getSequenceRenderer(alignmentv);\r
-\r
- FeatureRenderer fr = null;\r
- if (showFeatures)\r
- {\r
- fr = getFeatureRenderer(alignmentv);\r
- }\r
- AlignmentI alignment = alignmentv.getAlignment();\r
-\r
- for (jalview.structure.StructureMappingcommandSet cpdbbyseq: JmolCommands.getColourBySequenceCommand(ssm, files, sequence, sr, fr, alignment))\r
- for (String cbyseq : cpdbbyseq.commands) {\r
- evalStateCommand(cbyseq);\r
- }\r
- }\r
- \r
- public boolean isColourBySequence()\r
- {\r
- return colourBySequence;\r
- }\r
-\r
- public void setColourBySequence(boolean colourBySequence)\r
- {\r
- this.colourBySequence = colourBySequence;\r
- }\r
-\r
- public void createImage(String file, String type, int quality)\r
- {\r
- System.out.println("JMOL CREATE IMAGE");\r
- }\r
-\r
- public String createImage(String fileName, String type,\r
- Object textOrBytes, int quality)\r
- {\r
- System.out.println("JMOL CREATE IMAGE");\r
- return null;\r
- }\r
-\r
- public String eval(String strEval)\r
- {\r
- // System.out.println(strEval);\r
- // "# 'eval' is implemented only for the applet.";\r
- return null;\r
- }\r
-\r
- // End StructureListener\r
- // //////////////////////////\r
-\r
- public float[][] functionXY(String functionName, int x, int y)\r
- {\r
- return null;\r
- }\r
-\r
- public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)\r
- {\r
- // TODO Auto-generated method stub\r
- return null;\r
- }\r
-\r
- public Color getColour(int atomIndex, int pdbResNum, String chain,\r
- String pdbfile)\r
- {\r
- if (getModelNum(pdbfile) < 0)\r
- return null;\r
- // TODO: verify atomIndex is selecting correct model.\r
- return new Color(viewer.getAtomArgb(atomIndex));\r
- }\r
-\r
- /**\r
- * returns the current featureRenderer that should be used to colour the\r
- * structures\r
- * \r
- * @param alignment\r
- * \r
- * @return\r
- */\r
- public abstract FeatureRenderer getFeatureRenderer(\r
- AlignmentViewPanel alignment);\r
-\r
- /**\r
- * instruct the Jalview binding to update the pdbentries vector if necessary\r
- * prior to matching the jmol view's contents to the list of structure files\r
- * Jalview knows about.\r
- */\r
- public abstract void refreshPdbEntries();\r
-\r
- private int getModelNum(String modelFileName)\r
- {\r
- String[] mfn = getPdbFile();\r
- if (mfn == null)\r
- {\r
- return -1;\r
- }\r
- for (int i = 0; i < mfn.length; i++)\r
- {\r
- if (mfn[i].equalsIgnoreCase(modelFileName))\r
- return i;\r
- }\r
- return -1;\r
- }\r
-\r
- /**\r
- * map between index of model filename returned from getPdbFile and the first\r
- * index of models from this file in the viewer. Note - this is not trimmed -\r
- * use getPdbFile to get number of unique models.\r
- */\r
- private int _modelFileNameMap[];\r
-\r
- // ////////////////////////////////\r
- // /StructureListener\r
- public synchronized String[] getPdbFile()\r
- {\r
- if (viewer == null)\r
- {\r
- return new String[0];\r
- }\r
- if (modelFileNames == null)\r
- {\r
-\r
- String mset[] = new String[viewer.getModelCount()];\r
- _modelFileNameMap = new int[mset.length];\r
- int j = 1;\r
- String m=viewer.getModelFileName(0);\r
- if (m!=null)\r
- {\r
- try {\r
- mset[0] = new File(m).getAbsolutePath();\r
- } catch (AccessControlException x) {\r
- // usually not allowed to do this in applet, so keep raw handle\r
- mset[0] = m;\r
- //System.err.println("jmolBinding: Using local file string from Jmol: "+m); \r
- }\r
- }\r
- for (int i = 1; i < mset.length; i++)\r
- {\r
- m=viewer.getModelFileName(i);\r
- if (m!=null) {\r
- try {\r
- mset[j] = new File(m).getAbsolutePath();\r
- } catch (AccessControlException x) {\r
- // usually not allowed to do this in applet, so keep raw handle\r
- mset[j] = m;\r
- //System.err.println("jmolBinding: Using local file string from Jmol: "+m); \r
- }\r
- }\r
- _modelFileNameMap[j] = i; // record the model index for the filename\r
- // skip any additional models in the same file (NMR structures)\r
- if ((mset[j] == null ? mset[j] != mset[j - 1]\r
- : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))\r
- {\r
- j++;\r
- }\r
- }\r
- modelFileNames = new String[j];\r
- System.arraycopy(mset, 0, modelFileNames, 0, j);\r
- }\r
- return modelFileNames;\r
- }\r
-\r
- /**\r
- * map from string to applet\r
- */\r
- public Map getRegistryInfo()\r
- {\r
- // TODO Auto-generated method stub\r
- return null;\r
- }\r
-\r
- /**\r
- * returns the current sequenceRenderer that should be used to colour the\r
- * structures\r
- * \r
- * @param alignment\r
- * \r
- * @return\r
- */\r
- public abstract SequenceRenderer getSequenceRenderer(\r
- AlignmentViewPanel alignment);\r
-\r
- // ///////////////////////////////\r
- // JmolStatusListener\r
-\r
- public void handlePopupMenu(int x, int y)\r
- {\r
- jmolpopup.show(x, y);\r
- }\r
-\r
- // jmol/ssm only\r
- public void highlightAtom(int atomIndex, int pdbResNum, String chain,\r
- String pdbfile)\r
- {\r
- if (modelFileNames == null)\r
- {\r
- return;\r
- }\r
-\r
- // look up file model number for this pdbfile\r
- int mdlNum = 0;\r
- String fn;\r
- // may need to adjust for URLencoding here - we don't worry about that yet.\r
- while (mdlNum < modelFileNames.length\r
- && !pdbfile.equals(modelFileNames[mdlNum]))\r
- {\r
- // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);\r
- mdlNum++;\r
- }\r
- if (mdlNum == modelFileNames.length)\r
- {\r
- return;\r
- }\r
-\r
- jmolHistory(false);\r
- // if (!pdbfile.equals(pdbentry.getFile()))\r
- // return;\r
- if (resetLastRes.length() > 0)\r
- {\r
- viewer.evalStringQuiet(resetLastRes.toString());\r
- }\r
-\r
- eval.setLength(0);\r
- eval.append("select " + pdbResNum); // +modelNum\r
-\r
- resetLastRes.setLength(0);\r
- resetLastRes.append("select " + pdbResNum); // +modelNum\r
-\r
- eval.append(":");\r
- resetLastRes.append(":");\r
- if (!chain.equals(" "))\r
- {\r
- eval.append(chain);\r
- resetLastRes.append(chain);\r
- }\r
- {\r
- eval.append(" /" + (mdlNum + 1));\r
- resetLastRes.append("/" + (mdlNum + 1));\r
- }\r
- eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");\r
-\r
- resetLastRes.append(";wireframe 0;" + resetLastRes.toString()\r
- + " and not hetero; spacefill 0;");\r
-\r
- eval.append("spacefill 200;select none");\r
-\r
- viewer.evalStringQuiet(eval.toString());\r
- jmolHistory(true);\r
-\r
- }\r
-\r
- boolean debug = true;\r
-\r
- private void jmolHistory(boolean enable)\r
- {\r
- viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));\r
- }\r
-\r
- public void loadInline(String string)\r
- {\r
- loadedInline = true;\r
- // TODO: re JAL-623\r
- // viewer.loadInline(strModel, isAppend);\r
- // could do this:\r
- // construct fake fullPathName and fileName so we can identify the file\r
- // later.\r
- // Then, construct pass a reader for the string to Jmol.\r
- // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,\r
- // fileName, null, reader, false, null, null, 0);\r
- viewer.openStringInline(string);\r
- }\r
-\r
- public void mouseOverStructure(int atomIndex, String strInfo)\r
- {\r
- int pdbResNum;\r
- int alocsep = strInfo.indexOf("^");\r
- int mdlSep = strInfo.indexOf("/");\r
- int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;\r
-\r
- if (chainSeparator == -1)\r
- {\r
- chainSeparator = strInfo.indexOf(".");\r
- if (mdlSep > -1 && mdlSep < chainSeparator)\r
- {\r
- chainSeparator1 = chainSeparator;\r
- chainSeparator = mdlSep;\r
- }\r
- }\r
- // handle insertion codes\r
- if (alocsep != -1)\r
- {\r
- pdbResNum = Integer.parseInt(strInfo.substring(\r
- strInfo.indexOf("]") + 1, alocsep));\r
-\r
- }\r
- else\r
- {\r
- pdbResNum = Integer.parseInt(strInfo.substring(\r
- strInfo.indexOf("]") + 1, chainSeparator));\r
- }\r
- String chainId;\r
-\r
- if (strInfo.indexOf(":") > -1)\r
- chainId = strInfo.substring(strInfo.indexOf(":") + 1,\r
- strInfo.indexOf("."));\r
- else\r
- {\r
- chainId = " ";\r
- }\r
-\r
- String pdbfilename = modelFileNames[frameNo]; // default is first or current\r
- // model\r
- if (mdlSep > -1)\r
- {\r
- if (chainSeparator1 == -1)\r
- {\r
- chainSeparator1 = strInfo.indexOf(".", mdlSep);\r
- }\r
- String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,\r
- chainSeparator1) : strInfo.substring(mdlSep + 1);\r
- try\r
- {\r
- // recover PDB filename for the model hovered over.\r
- int _mp=_modelFileNameMap.length-1,\r
- mnumber=new Integer(mdlId).intValue() - 1;\r
- while(mnumber<_modelFileNameMap[_mp])\r
- {\r
- _mp--;\r
- }\r
- pdbfilename = modelFileNames[_mp];\r
- if (pdbfilename==null) {pdbfilename=new File(viewer\r
- .getModelFileName(mnumber)).getAbsolutePath();\r
- }\r
- \r
- } catch (Exception e)\r
- {\r
- }\r
- ;\r
- }\r
- if (lastMessage == null || !lastMessage.equals(strInfo))\r
- ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);\r
-\r
- lastMessage = strInfo;\r
- }\r
-\r
- public void notifyAtomHovered(int atomIndex, String strInfo, String data)\r
- {\r
- if (data != null)\r
- {\r
- System.err.println("Ignoring additional hover info: " + data\r
- + " (other info: '" + strInfo + "' pos " + atomIndex + ")");\r
- }\r
- mouseOverStructure(atomIndex, strInfo);\r
- }\r
-\r
- /*\r
- * { if (history != null && strStatus != null &&\r
- * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);\r
- * } }\r
- */\r
-\r
- public void notifyAtomPicked(int atomIndex, String strInfo, String strData)\r
- {\r
- /**\r
- * this implements the toggle label behaviour copied from the original\r
- * structure viewer, MCView\r
- */\r
- if (strData != null)\r
- {\r
- System.err.println("Ignoring additional pick data string " + strData);\r
- }\r
- int chainSeparator = strInfo.indexOf(":");\r
- int p = 0;\r
- if (chainSeparator == -1)\r
- chainSeparator = strInfo.indexOf(".");\r
-\r
- String picked = strInfo.substring(strInfo.indexOf("]") + 1,\r
- chainSeparator);\r
- String mdlString = "";\r
- if ((p = strInfo.indexOf(":")) > -1)\r
- picked += strInfo.substring(p + 1, strInfo.indexOf("."));\r
-\r
- if ((p = strInfo.indexOf("/")) > -1)\r
- {\r
- mdlString += strInfo.substring(p, strInfo.indexOf(" #"));\r
- }\r
- picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"\r
- + mdlString + "))";\r
- jmolHistory(false);\r
-\r
- if (!atomsPicked.contains(picked))\r
- {\r
- viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");\r
- atomsPicked.addElement(picked);\r
- }\r
- else\r
- {\r
- viewer.evalString("select " + picked + ";label off");\r
- atomsPicked.removeElement(picked);\r
- }\r
- jmolHistory(true);\r
- // TODO: in application this happens\r
- //\r
- // if (scriptWindow != null)\r
- // {\r
- // scriptWindow.sendConsoleMessage(strInfo);\r
- // scriptWindow.sendConsoleMessage("\n");\r
- // }\r
-\r
- }\r
-\r
- @Override\r
- public void notifyCallback(EnumCallback type, Object[] data)\r
- {\r
- try\r
- {\r
- switch (type)\r
- {\r
- case LOADSTRUCT:\r
- notifyFileLoaded((String) data[1], (String) data[2],\r
- (String) data[3], (String) data[4],\r
- ((Integer) data[5]).intValue());\r
-\r
- break;\r
- case PICK:\r
- notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],\r
- (String) data[0]);\r
- // also highlight in alignment\r
- case HOVER:\r
- notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],\r
- (String) data[0]);\r
- break;\r
- case SCRIPT:\r
- notifyScriptTermination((String) data[2],\r
- ((Integer) data[3]).intValue());\r
- break;\r
- case ECHO:\r
- sendConsoleEcho((String) data[1]);\r
- break;\r
- case MESSAGE:\r
- sendConsoleMessage((data == null) ? ((String) null)\r
- : (String) data[1]);\r
- break;\r
- case ERROR:\r
- // System.err.println("Ignoring error callback.");\r
- break;\r
- case SYNC:\r
- case RESIZE:\r
- refreshGUI();\r
- break;\r
- case MEASURE:\r
-\r
- case CLICK:\r
- default:\r
- System.err.println("Unhandled callback " + type + " "\r
- + data[1].toString());\r
- break;\r
- }\r
- } catch (Exception e)\r
- {\r
- System.err.println("Squashed Jmol callback handler error:");\r
- e.printStackTrace();\r
- }\r
- }\r
-\r
- @Override\r
- public boolean notifyEnabled(EnumCallback callbackPick)\r
- {\r
- switch (callbackPick)\r
- {\r
- case ECHO:\r
- case LOADSTRUCT:\r
- case MEASURE:\r
- case MESSAGE:\r
- case PICK:\r
- case SCRIPT:\r
- case HOVER:\r
- case ERROR:\r
- return true;\r
- case RESIZE:\r
- case SYNC:\r
- case CLICK:\r
- case ANIMFRAME:\r
- case MINIMIZATION:\r
- }\r
- return false;\r
- }\r
-\r
- // incremented every time a load notification is successfully handled -\r
- // lightweight mechanism for other threads to detect when they can start\r
- // referrring to new structures.\r
- private long loadNotifiesHandled = 0;\r
-\r
- public long getLoadNotifiesHandled()\r
- {\r
- return loadNotifiesHandled;\r
- }\r
-\r
- public void notifyFileLoaded(String fullPathName, String fileName2,\r
- String modelName, String errorMsg, int modelParts)\r
- {\r
- if (errorMsg != null)\r
- {\r
- fileLoadingError = errorMsg;\r
- refreshGUI();\r
- return;\r
- }\r
- // TODO: deal sensibly with models loaded inLine:\r
- // modelName will be null, as will fullPathName.\r
-\r
- // the rest of this routine ignores the arguments, and simply interrogates\r
- // the Jmol view to find out what structures it contains, and adds them to\r
- // the structure selection manager.\r
- fileLoadingError = null;\r
- String[] oldmodels = modelFileNames;\r
- modelFileNames = null;\r
- chainNames = new Vector();\r
- chainFile = new Hashtable();\r
- boolean notifyLoaded = false;\r
- String[] modelfilenames = getPdbFile();\r
- // first check if we've lost any structures\r
- if (oldmodels != null && oldmodels.length > 0)\r
- {\r
- int oldm = 0;\r
- for (int i = 0; i < oldmodels.length; i++)\r
- {\r
- for (int n = 0; n < modelfilenames.length; n++)\r
- {\r
- if (modelfilenames[n] == oldmodels[i])\r
- {\r
- oldmodels[i] = null;\r
- break;\r
- }\r
- }\r
- if (oldmodels[i] != null)\r
- {\r
- oldm++;\r
- }\r
- }\r
- if (oldm > 0)\r
- {\r
- String[] oldmfn = new String[oldm];\r
- oldm = 0;\r
- for (int i = 0; i < oldmodels.length; i++)\r
- {\r
- if (oldmodels[i] != null)\r
- {\r
- oldmfn[oldm++] = oldmodels[i];\r
- }\r
- }\r
- // deregister the Jmol instance for these structures - we'll add\r
- // ourselves again at the end for the current structure set.\r
- ssm.removeStructureViewerListener(this, oldmfn);\r
- }\r
- }\r
- refreshPdbEntries();\r
- for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)\r
- {\r
- String fileName = modelfilenames[modelnum];\r
- boolean foundEntry = false;\r
- MCview.PDBfile pdb = null;\r
- String pdbfile = null, pdbfhash = null;\r
- // model was probably loaded inline - so check the pdb file hashcode\r
- if (loadedInline)\r
- {\r
- // calculate essential attributes for the pdb data imported inline.\r
- // prolly need to resolve modelnumber properly - for now just use our\r
- // 'best guess'\r
- pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])\r
- + ".0", "PDB");\r
- pdbfhash = "" + pdbfile.hashCode();\r
- }\r
- if (pdbentry != null)\r
- {\r
- // search pdbentries and sequences to find correct pdbentry for this\r
- // model\r
- for (int pe = 0; pe < pdbentry.length; pe++)\r
- {\r
- boolean matches = false;\r
- if (fileName == null)\r
- {\r
- if (false)\r
- // see JAL-623 - need method of matching pasted data up\r
- {\r
- pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,\r
- AppletFormatAdapter.PASTE);\r
- pdbentry[modelnum].setFile("INLINE" + pdb.id);\r
- matches = true;\r
- foundEntry = true;\r
- }\r
- }\r
- else\r
- {\r
- File fl;\r
- if (matches = (fl=new File(pdbentry[pe].getFile())).equals(new File(fileName)))\r
- {\r
- foundEntry = true;\r
- // TODO: Jmol can in principle retrieve from CLASSLOADER but\r
- // this\r
- // needs\r
- // to be tested. See mantis bug\r
- // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605\r
- String protocol = AppletFormatAdapter.URL;\r
- try\r
- {\r
- if (fl.exists())\r
- {\r
- protocol = AppletFormatAdapter.FILE;\r
- }\r
- } catch (Exception e)\r
- {\r
- } catch (Error e)\r
- {\r
- }\r
- //Explicitly map to the filename used by Jmol ;\r
- pdb = ssm.setMapping(sequence[pe], chains[pe],\r
- fileName, protocol);\r
- //pdbentry[pe].getFile(), protocol);\r
-\r
- }\r
- }\r
- if (matches)\r
- {\r
- // add an entry for every chain in the model\r
- for (int i = 0; i < pdb.chains.size(); i++)\r
- {\r
- String chid = new String(pdb.id + ":"\r
- + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);\r
- chainFile.put(chid, fileName);\r
- chainNames.addElement(chid);\r
- }\r
- notifyLoaded = true;\r
- }\r
- }\r
- }\r
- if (!foundEntry && associateNewStructs)\r
- {\r
- // this is a foreign pdb file that jalview doesn't know about - add\r
- // it to the dataset and try to find a home - either on a matching\r
- // sequence or as a new sequence.\r
- String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",\r
- "PDB");\r
- // parse pdb file into a chain, etc.\r
- // locate best match for pdb in associated views and add mapping to\r
- // ssm\r
- // if properly registered then\r
- notifyLoaded = true;\r
-\r
- }\r
- }\r
- // FILE LOADED OK\r
- // so finally, update the jmol bits and pieces\r
- if (jmolpopup != null)\r
- {\r
- // potential for deadlock here:\r
- // jmolpopup.updateComputedMenus();\r
- }\r
- if (!isLoadingFromArchive())\r
- {\r
- viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");\r
- }\r
- // register ourselves as a listener and notify the gui that it needs to\r
- // update itself.\r
- ssm.addStructureViewerListener(this);\r
- if (notifyLoaded)\r
- {\r
- FeatureRenderer fr = getFeatureRenderer(null);\r
- if (fr != null)\r
- {\r
- fr.featuresAdded();\r
- }\r
- refreshGUI();\r
- loadNotifiesHandled++;\r
- }\r
- setLoadingFromArchive(false);\r
- }\r
-\r
- public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)\r
- {\r
- notifyAtomPicked(iatom, strMeasure, null);\r
- }\r
-\r
- public abstract void notifyScriptTermination(String strStatus,\r
- int msWalltime);\r
-\r
- /**\r
- * display a message echoed from the jmol viewer\r
- * \r
- * @param strEcho\r
- */\r
- public abstract void sendConsoleEcho(String strEcho); /*\r
- * { showConsole(true);\r
- * \r
- * history.append("\n" +\r
- * strEcho); }\r
- */\r
-\r
- // /End JmolStatusListener\r
- // /////////////////////////////\r
-\r
- /**\r
- * @param strStatus\r
- * status message - usually the response received after a script\r
- * executed\r
- */\r
- public abstract void sendConsoleMessage(String strStatus);\r
-\r
- public void setCallbackFunction(String callbackType,\r
- String callbackFunction)\r
- {\r
- System.err.println("Ignoring set-callback request to associate "\r
- + callbackType + " with function " + callbackFunction);\r
-\r
- }\r
-\r
- public void setJalviewColourScheme(ColourSchemeI cs)\r
- {\r
- colourBySequence = false;\r
-\r
- if (cs == null)\r
- return;\r
-\r
- String res;\r
- int index;\r
- Color col;\r
- jmolHistory(false);\r
- // TODO: Switch between nucleotide or aa selection expressions\r
- Enumeration en = ResidueProperties.aa3Hash.keys();\r
- StringBuffer command = new StringBuffer("select *;color white;");\r
- while (en.hasMoreElements())\r
- {\r
- res = en.nextElement().toString();\r
- index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();\r
- if (index > 20)\r
- continue;\r
-\r
- col = cs.findColour(ResidueProperties.aa[index].charAt(0));\r
-\r
- command.append("select " + res + ";color[" + col.getRed() + ","\r
- + col.getGreen() + "," + col.getBlue() + "];");\r
- }\r
-\r
- evalStateCommand(command.toString());\r
- jmolHistory(true);\r
- }\r
-\r
- public void showHelp()\r
- {\r
- showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");\r
- }\r
-\r
- /**\r
- * open the URL somehow\r
- * \r
- * @param target\r
- */\r
- public abstract void showUrl(String url, String target);\r
-\r
- /**\r
- * called when the binding thinks the UI needs to be refreshed after a Jmol\r
- * state change. this could be because structures were loaded, or because an\r
- * error has occured.\r
- */\r
- public abstract void refreshGUI();\r
-\r
- /**\r
- * called to show or hide the associated console window container.\r
- * \r
- * @param show\r
- */\r
- public abstract void showConsole(boolean show);\r
-\r
- /**\r
- * @param renderPanel\r
- * @param jmolfileio\r
- * - when true will initialise jmol's file IO system (should be false\r
- * in applet context)\r
- * @param htmlName\r
- * @param documentBase\r
- * @param codeBase\r
- * @param commandOptions\r
- */\r
- public void allocateViewer(Container renderPanel, boolean jmolfileio,\r
- String htmlName, URL documentBase, URL codeBase,\r
- String commandOptions)\r
- {\r
- allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,\r
- codeBase, commandOptions, null, null);\r
- }\r
-\r
- /**\r
- * \r
- * @param renderPanel\r
- * @param jmolfileio\r
- * - when true will initialise jmol's file IO system (should be false\r
- * in applet context)\r
- * @param htmlName\r
- * @param documentBase\r
- * @param codeBase\r
- * @param commandOptions\r
- * @param consolePanel\r
- * - panel to contain Jmol console\r
- * @param buttonsToShow\r
- * - buttons to show on the console, in ordr\r
- */\r
- public void allocateViewer(Container renderPanel, boolean jmolfileio,\r
- String htmlName, URL documentBase, URL codeBase,\r
- String commandOptions, final Container consolePanel,\r
- String buttonsToShow)\r
- {\r
- if (commandOptions==null) {
- commandOptions="";