2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.ext.jmol;
23 import jalview.api.AlignmentViewPanel;
24 import jalview.api.FeatureRenderer;
25 import jalview.api.SequenceRenderer;
26 import jalview.datamodel.AlignmentI;
27 import jalview.datamodel.HiddenColumns;
28 import jalview.datamodel.PDBEntry;
29 import jalview.datamodel.SequenceI;
30 import jalview.gui.IProgressIndicator;
31 import jalview.io.DataSourceType;
32 import jalview.io.StructureFile;
33 import jalview.schemes.ColourSchemeI;
34 import jalview.schemes.ResidueProperties;
35 import jalview.structure.AtomSpec;
36 import jalview.structure.StructureMappingcommandSet;
37 import jalview.structure.StructureSelectionManager;
38 import jalview.structures.models.AAStructureBindingModel;
39 import jalview.util.MessageManager;
41 import java.awt.Color;
42 import java.awt.Container;
43 import java.awt.event.ComponentEvent;
44 import java.awt.event.ComponentListener;
47 import java.security.AccessControlException;
48 import java.util.ArrayList;
49 import java.util.BitSet;
50 import java.util.Hashtable;
51 import java.util.List;
53 import java.util.Vector;
55 import org.jmol.adapter.smarter.SmarterJmolAdapter;
56 import org.jmol.api.JmolAppConsoleInterface;
57 import org.jmol.api.JmolSelectionListener;
58 import org.jmol.api.JmolStatusListener;
59 import org.jmol.api.JmolViewer;
60 import org.jmol.c.CBK;
61 import org.jmol.script.T;
62 import org.jmol.viewer.Viewer;
64 public abstract class JalviewJmolBinding extends AAStructureBindingModel
65 implements JmolStatusListener, JmolSelectionListener,
68 boolean allChainsSelected = false;
71 * when true, try to search the associated datamodel for sequences that are
72 * associated with any unknown structures in the Jmol view.
74 private boolean associateNewStructs = false;
76 Vector<String> atomsPicked = new Vector<>();
78 private List<String> chainNames;
80 Hashtable<String, String> chainFile;
83 * the default or current model displayed if the model cannot be identified
84 * from the selection message
88 // protected JmolGenericPopup jmolpopup; // not used - remove?
96 StringBuffer resetLastRes = new StringBuffer();
100 public JalviewJmolBinding(StructureSelectionManager ssm,
101 PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
102 DataSourceType protocol)
104 super(ssm, pdbentry, sequenceIs, protocol);
106 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
107 * "jalviewJmol", ap.av.applet .getDocumentBase(),
108 * ap.av.applet.getCodeBase(), "", this);
110 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
114 public JalviewJmolBinding(StructureSelectionManager ssm,
115 SequenceI[][] seqs, Viewer theViewer)
120 viewer.setJmolStatusListener(this);
121 viewer.addSelectionListener(this);
125 * construct a title string for the viewer window based on the data jalview
130 public String getViewerTitle()
132 return getViewerTitle("Jmol", true);
136 * prepare the view for a given set of models/chains. chainList contains
137 * strings of the form 'pdbfilename:Chaincode'
140 * list of chains to make visible
142 public void centerViewer(Vector<String> chainList)
144 StringBuilder cmd = new StringBuilder(128);
146 for (String lbl : chainList)
152 mlength = lbl.indexOf(":", p);
153 } while (p < mlength && mlength < (lbl.length() - 2));
154 // TODO: lookup each pdb id and recover proper model number for it.
155 cmd.append(":" + lbl.substring(mlength + 1) + " /"
156 + (1 + getModelNum(chainFile.get(lbl))) + " or ");
158 if (cmd.length() > 0)
160 cmd.setLength(cmd.length() - 4);
162 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
165 public void closeViewer()
167 // remove listeners for all structures in viewer
168 getSsm().removeStructureViewerListener(this, this.getStructureFiles());
173 releaseUIResources();
177 public void colourByChain()
179 colourBySequence = false;
180 // TODO: colour by chain should colour each chain distinctly across all
182 // TODO: http://issues.jalview.org/browse/JAL-628
183 evalStateCommand("select *;color chain");
187 public void colourByCharge()
189 colourBySequence = false;
190 evalStateCommand("select *;color white;select ASP,GLU;color red;"
191 + "select LYS,ARG;color blue;select CYS;color yellow");
195 * superpose the structures associated with sequences in the alignment
196 * according to their corresponding positions.
198 public void superposeStructures(AlignmentI alignment)
200 superposeStructures(alignment, -1, null);
204 * superpose the structures associated with sequences in the alignment
205 * according to their corresponding positions. ded)
207 * @param refStructure
208 * - select which pdb file to use as reference (default is -1 - the
209 * first structure in the alignment)
211 public void superposeStructures(AlignmentI alignment, int refStructure)
213 superposeStructures(alignment, refStructure, null);
217 * superpose the structures associated with sequences in the alignment
218 * according to their corresponding positions. ded)
220 * @param refStructure
221 * - select which pdb file to use as reference (default is -1 - the
222 * first structure in the alignment)
226 public void superposeStructures(AlignmentI alignment, int refStructure,
227 HiddenColumns hiddenCols)
229 superposeStructures(new AlignmentI[] { alignment },
231 { refStructure }, new HiddenColumns[] { hiddenCols });
238 public String superposeStructures(AlignmentI[] _alignment,
239 int[] _refStructure, HiddenColumns[] _hiddenCols)
241 while (viewer.isScriptExecuting())
246 } catch (InterruptedException i)
252 * get the distinct structure files modelled
253 * (a file with multiple chains may map to multiple sequences)
255 String[] files = getStructureFiles();
256 if (!waitForFileLoad(files))
261 StringBuilder selectioncom = new StringBuilder(256);
262 // In principle - nSeconds specifies the speed of animation for each
263 // superposition - but is seems to behave weirdly, so we don't specify it.
264 String nSeconds = " ";
265 if (files.length > 10)
267 nSeconds = " 0.005 ";
271 nSeconds = " " + (2.0 / files.length) + " ";
272 // if (nSeconds).substring(0,5)+" ";
275 // see JAL-1345 - should really automatically turn off the animation for
276 // large numbers of structures, but Jmol doesn't seem to allow that.
278 // union of all aligned positions are collected together.
279 for (int a = 0; a < _alignment.length; a++)
281 int refStructure = _refStructure[a];
282 AlignmentI alignment = _alignment[a];
283 HiddenColumns hiddenCols = _hiddenCols[a];
284 if (a > 0 && selectioncom.length() > 0 && !selectioncom
285 .substring(selectioncom.length() - 1).equals("|"))
287 selectioncom.append("|");
289 // process this alignment
290 if (refStructure >= files.length)
293 "Invalid reference structure value " + refStructure);
298 * 'matched' bit j will be set for visible alignment columns j where
299 * all sequences have a residue with a mapping to the PDB structure
301 BitSet matched = new BitSet();
302 for (int m = 0; m < alignment.getWidth(); m++)
304 if (hiddenCols == null || hiddenCols.isVisible(m))
310 SuperposeData[] structures = new SuperposeData[files.length];
311 for (int f = 0; f < files.length; f++)
313 structures[f] = new SuperposeData(alignment.getWidth());
317 * Calculate the superposable alignment columns ('matched'), and the
318 * corresponding structure residue positions (structures.pdbResNo)
320 int candidateRefStructure = findSuperposableResidues(alignment,
321 matched, structures);
322 if (refStructure < 0)
325 * If no reference structure was specified, pick the first one that has
326 * a mapping in the alignment
328 refStructure = candidateRefStructure;
331 String[] selcom = new String[files.length];
332 int nmatched = matched.cardinality();
335 return (MessageManager.formatMessage("label.insufficient_residues",
340 * generate select statements to select regions to superimpose structures
343 // TODO extract method to construct selection statements
344 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
346 String chainCd = ":" + structures[pdbfnum].chain;
349 StringBuilder molsel = new StringBuilder();
352 int nextColumnMatch = matched.nextSetBit(0);
353 while (nextColumnMatch != -1)
355 int pdbResNo = structures[pdbfnum].pdbResNo[nextColumnMatch];
356 if (lpos != pdbResNo - 1)
362 molsel.append(chainCd);
369 // continuous run - and lpos >-1
372 // at the beginning, so add dash
379 nextColumnMatch = matched.nextSetBit(nextColumnMatch + 1);
382 * add final selection phrase
387 molsel.append(chainCd);
390 if (molsel.length() > 1)
392 selcom[pdbfnum] = molsel.toString();
393 selectioncom.append("((");
394 selectioncom.append(selcom[pdbfnum].substring(1,
395 selcom[pdbfnum].length() - 1));
396 selectioncom.append(" )& ");
397 selectioncom.append(pdbfnum + 1);
398 selectioncom.append(".1)");
399 if (pdbfnum < files.length - 1)
401 selectioncom.append("|");
406 selcom[pdbfnum] = null;
410 StringBuilder command = new StringBuilder(256);
411 // command.append("set spinFps 10;\n");
413 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
415 if (pdbfnum == refStructure || selcom[pdbfnum] == null
416 || selcom[refStructure] == null)
420 command.append("echo ");
421 command.append("\"Superposing (");
422 command.append(structures[pdbfnum].pdbId);
423 command.append(") against reference (");
424 command.append(structures[refStructure].pdbId);
425 command.append(")\";\ncompare " + nSeconds);
427 command.append(Integer.toString(1 + pdbfnum));
428 command.append(".1} {");
429 command.append(Integer.toString(1 + refStructure));
430 // conformation=1 excludes alternate locations for CA (JAL-1757)
432 ".1} SUBSET {(*.CA | *.P) and conformation=1} ATOMS ");
434 // for (int s = 0; s < 2; s++)
436 // command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
438 command.append(selcom[pdbfnum]);
439 command.append(selcom[refStructure]);
440 command.append(" ROTATE TRANSLATE;\n");
442 if (selectioncom.length() > 0)
444 // TODO is performing selectioncom redundant here? is done later on
445 // System.out.println("Select regions:\n" + selectioncom.toString());
446 evalStateCommand("select *; cartoons off; backbone; select ("
447 + selectioncom.toString() + "); cartoons; ");
448 // selcom.append("; ribbons; ");
449 String cmdString = command.toString();
450 // System.out.println("Superimpose command(s):\n" + cmdString);
452 evalStateCommand(cmdString);
455 if (selectioncom.length() > 0)
456 {// finally, mark all regions that were superposed.
457 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
459 selectioncom.setLength(selectioncom.length() - 1);
461 // System.out.println("Select regions:\n" + selectioncom.toString());
462 evalStateCommand("select *; cartoons off; backbone; select ("
463 + selectioncom.toString() + "); cartoons; ");
464 // evalStateCommand("select *; backbone; select "+selcom.toString()+";
465 // cartoons; center "+selcom.toString());
471 public void evalStateCommand(String command)
474 if (lastCommand == null || !lastCommand.equals(command))
476 jmolScript(command + "\n");
479 lastCommand = command;
482 Thread colourby = null;
484 * Sends a set of colour commands to the structure viewer
486 * @param colourBySequenceCommands
489 protected void colourBySequence(
490 final StructureMappingcommandSet[] colourBySequenceCommands)
492 if (colourby != null)
494 colourby.interrupt();
497 colourby = new Thread(new Runnable()
502 for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands)
504 for (String cbyseq : cpdbbyseq.commands)
506 executeWhenReady(cbyseq);
521 protected StructureMappingcommandSet[] getColourBySequenceCommands(
522 String[] files, SequenceRenderer sr, AlignmentViewPanel viewPanel)
524 return JmolCommands.getColourBySequenceCommand(getSsm(), files,
525 getSequence(), sr, viewPanel);
531 protected void executeWhenReady(String command)
533 evalStateCommand(command);
536 public void createImage(String file, String type, int quality)
538 System.out.println("JMOL CREATE IMAGE");
542 public String createImage(String fileName, String type,
543 Object textOrBytes, int quality)
545 System.out.println("JMOL CREATE IMAGE");
550 public String eval(String strEval)
552 // System.out.println(strEval);
553 // "# 'eval' is implemented only for the applet.";
557 // End StructureListener
558 // //////////////////////////
561 public float[][] functionXY(String functionName, int x, int y)
567 public float[][][] functionXYZ(String functionName, int nx, int ny,
570 // TODO Auto-generated method stub
574 public Color getColour(int atomIndex, int pdbResNum, String chain,
577 if (getModelNum(pdbfile) < 0)
581 // TODO: verify atomIndex is selecting correct model.
582 // return new Color(viewer.getAtomArgb(atomIndex)); Jmol 12.2.4
583 int colour = viewer.ms.at[atomIndex].atomPropertyInt(T.color);
584 return new Color(colour);
588 * instruct the Jalview binding to update the pdbentries vector if necessary
589 * prior to matching the jmol view's contents to the list of structure files
590 * Jalview knows about.
592 public abstract void refreshPdbEntries();
594 private int getModelNum(String modelFileName)
596 String[] mfn = getStructureFiles();
601 for (int i = 0; i < mfn.length; i++)
603 if (mfn[i].equalsIgnoreCase(modelFileName))
612 * map between index of model filename returned from getPdbFile and the first
613 * index of models from this file in the viewer. Note - this is not trimmed -
614 * use getPdbFile to get number of unique models.
616 private int _modelFileNameMap[];
618 // ////////////////////////////////
619 // /StructureListener
621 public synchronized String[] getPdbFilex()
625 return new String[0];
627 if (modelFileNames == null)
629 List<String> mset = new ArrayList<>();
630 _modelFileNameMap = new int[viewer.ms.mc];
631 String m = viewer.ms.getModelFileName(0);
637 filePath = new File(m).getAbsolutePath();
638 } catch (AccessControlException x)
640 // usually not allowed to do this in applet
642 "jmolBinding: Using local file string from Jmol: " + m);
644 if (filePath.indexOf("/file:") != -1)
646 // applet path with docroot - discard as format won't match pdbfile
650 _modelFileNameMap[0] = 0; // filename index for first model is always 0.
653 for (int i = 1; i < viewer.ms.mc; i++)
655 m = viewer.ms.getModelFileName(i);
661 filePath = new File(m).getAbsolutePath();
662 } catch (AccessControlException x)
664 // usually not allowed to do this in applet, so keep raw handle
665 // System.err.println("jmolBinding: Using local file string from
671 * add this model unless it is read from a structure file we have
672 * already seen (example: 2MJW is an NMR structure with 10 models)
674 if (!mset.contains(filePath))
677 _modelFileNameMap[j] = i; // record the model index for the filename
681 modelFileNames = mset.toArray(new String[mset.size()]);
683 return modelFileNames;
687 public synchronized String[] getStructureFiles()
689 List<String> mset = new ArrayList<>();
692 return new String[0];
695 if (modelFileNames == null)
697 int modelCount = viewer.ms.mc;
698 String filePath = null;
699 for (int i = 0; i < modelCount; ++i)
701 filePath = viewer.ms.getModelFileName(i);
702 if (!mset.contains(filePath))
707 modelFileNames = mset.toArray(new String[mset.size()]);
710 return modelFileNames;
714 * map from string to applet
717 public Map<String, Object> getRegistryInfo()
719 // TODO Auto-generated method stub
723 // ///////////////////////////////
724 // JmolStatusListener
726 public void handlePopupMenu(int x, int y)
728 // jmolpopup.show(x, y);
729 // jmolpopup.jpiShow(x, y);
733 * Highlight zero, one or more atoms on the structure
736 public void highlightAtoms(List<AtomSpec> atoms)
740 if (resetLastRes.length() > 0)
742 jmolScript(resetLastRes.toString());
743 resetLastRes.setLength(0);
745 for (AtomSpec atom : atoms)
747 highlightAtom(atom.getAtomIndex(), atom.getPdbResNum(),
748 atom.getChain(), atom.getPdbFile());
754 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
757 if (modelFileNames == null)
762 // look up file model number for this pdbfile
764 // may need to adjust for URLencoding here - we don't worry about that yet.
765 while (mdlNum < modelFileNames.length
766 && !pdbfile.equals(modelFileNames[mdlNum]))
770 if (mdlNum == modelFileNames.length)
777 StringBuilder cmd = new StringBuilder(64);
778 cmd.append("select " + pdbResNum); // +modelNum
780 resetLastRes.append("select " + pdbResNum); // +modelNum
783 resetLastRes.append(":");
784 if (!chain.equals(" "))
787 resetLastRes.append(chain);
790 cmd.append(" /" + (mdlNum + 1));
791 resetLastRes.append("/" + (mdlNum + 1));
793 cmd.append(";wireframe 100;" + cmd.toString() + " and not hetero;");
795 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
796 + " and not hetero; spacefill 0;");
798 cmd.append("spacefill 200;select none");
800 jmolScript(cmd.toString());
805 boolean debug = true;
807 private void jmolHistory(boolean enable)
809 jmolScript("History " + ((debug || enable) ? "on" : "off"));
812 public void loadInline(String string)
816 // viewer.loadInline(strModel, isAppend);
818 // construct fake fullPathName and fileName so we can identify the file
820 // Then, construct pass a reader for the string to Jmol.
821 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
822 // fileName, null, reader, false, null, null, 0);
823 viewer.openStringInline(string);
826 public void mouseOverStructure(int atomIndex, String strInfo)
829 int alocsep = strInfo.indexOf("^");
830 int mdlSep = strInfo.indexOf("/");
831 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
833 if (chainSeparator == -1)
835 chainSeparator = strInfo.indexOf(".");
836 if (mdlSep > -1 && mdlSep < chainSeparator)
838 chainSeparator1 = chainSeparator;
839 chainSeparator = mdlSep;
842 // handle insertion codes
845 pdbResNum = Integer.parseInt(
846 strInfo.substring(strInfo.indexOf("]") + 1, alocsep));
851 pdbResNum = Integer.parseInt(
852 strInfo.substring(strInfo.indexOf("]") + 1, chainSeparator));
856 if (strInfo.indexOf(":") > -1)
858 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
859 strInfo.indexOf("."));
866 String pdbfilename = modelFileNames[frameNo]; // default is first or current
870 if (chainSeparator1 == -1)
872 chainSeparator1 = strInfo.indexOf(".", mdlSep);
874 String mdlId = (chainSeparator1 > -1)
875 ? strInfo.substring(mdlSep + 1, chainSeparator1)
876 : strInfo.substring(mdlSep + 1);
879 // recover PDB filename for the model hovered over.
880 int mnumber = new Integer(mdlId).intValue() - 1;
881 if (_modelFileNameMap != null)
883 int _mp = _modelFileNameMap.length - 1;
885 while (mnumber < _modelFileNameMap[_mp])
889 pdbfilename = modelFileNames[_mp];
893 if (mnumber >= 0 && mnumber < modelFileNames.length)
895 pdbfilename = modelFileNames[mnumber];
898 if (pdbfilename == null)
900 pdbfilename = new File(viewer.ms.getModelFileName(mnumber))
904 } catch (Exception e)
909 if (lastMessage == null || !lastMessage.equals(strInfo))
911 getSsm().mouseOverStructure(pdbResNum, chainId, pdbfilename);
914 lastMessage = strInfo;
917 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
921 System.err.println("Ignoring additional hover info: " + data
922 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
924 mouseOverStructure(atomIndex, strInfo);
928 * { if (history != null && strStatus != null &&
929 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
933 public void notifyAtomPicked(int atomIndex, String strInfo,
937 * this implements the toggle label behaviour copied from the original
938 * structure viewer, mc_view
942 System.err.println("Ignoring additional pick data string " + strData);
944 int chainSeparator = strInfo.indexOf(":");
946 if (chainSeparator == -1)
948 chainSeparator = strInfo.indexOf(".");
951 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
953 String mdlString = "";
954 if ((p = strInfo.indexOf(":")) > -1)
956 picked += strInfo.substring(p, strInfo.indexOf("."));
959 if ((p = strInfo.indexOf("/")) > -1)
961 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
963 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
967 if (!atomsPicked.contains(picked))
969 jmolScript("select " + picked + ";label %n %r:%c");
970 atomsPicked.addElement(picked);
974 viewer.evalString("select " + picked + ";label off");
975 atomsPicked.removeElement(picked);
978 // TODO: in application this happens
980 // if (scriptWindow != null)
982 // scriptWindow.sendConsoleMessage(strInfo);
983 // scriptWindow.sendConsoleMessage("\n");
989 public void notifyCallback(CBK type, Object[] data)
996 notifyFileLoaded((String) data[1], (String) data[2],
997 (String) data[3], (String) data[4],
998 ((Integer) data[5]).intValue());
1002 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
1004 // also highlight in alignment
1005 // deliberate fall through
1007 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1011 notifyScriptTermination((String) data[2],
1012 ((Integer) data[3]).intValue());
1015 sendConsoleEcho((String) data[1]);
1019 (data == null) ? ((String) null) : (String) data[1]);
1022 // System.err.println("Ignoring error callback.");
1033 "Unhandled callback " + type + " " + data[1].toString());
1036 } catch (Exception e)
1038 System.err.println("Squashed Jmol callback handler error:");
1039 e.printStackTrace();
1044 public boolean notifyEnabled(CBK callbackPick)
1046 switch (callbackPick)
1062 // incremented every time a load notification is successfully handled -
1063 // lightweight mechanism for other threads to detect when they can start
1064 // referrring to new structures.
1065 private long loadNotifiesHandled = 0;
1067 public long getLoadNotifiesHandled()
1069 return loadNotifiesHandled;
1072 public void notifyFileLoaded(String fullPathName, String fileName2,
1073 String modelName, String errorMsg, int modelParts)
1075 if (errorMsg != null)
1077 fileLoadingError = errorMsg;
1081 // TODO: deal sensibly with models loaded inLine:
1082 // modelName will be null, as will fullPathName.
1084 // the rest of this routine ignores the arguments, and simply interrogates
1085 // the Jmol view to find out what structures it contains, and adds them to
1086 // the structure selection manager.
1087 fileLoadingError = null;
1088 String[] oldmodels = modelFileNames;
1089 modelFileNames = null;
1090 chainNames = new ArrayList<>();
1091 chainFile = new Hashtable<>();
1092 boolean notifyLoaded = false;
1093 String[] modelfilenames = getStructureFiles();
1094 // first check if we've lost any structures
1095 if (oldmodels != null && oldmodels.length > 0)
1098 for (int i = 0; i < oldmodels.length; i++)
1100 for (int n = 0; n < modelfilenames.length; n++)
1102 if (modelfilenames[n] == oldmodels[i])
1104 oldmodels[i] = null;
1108 if (oldmodels[i] != null)
1115 String[] oldmfn = new String[oldm];
1117 for (int i = 0; i < oldmodels.length; i++)
1119 if (oldmodels[i] != null)
1121 oldmfn[oldm++] = oldmodels[i];
1124 // deregister the Jmol instance for these structures - we'll add
1125 // ourselves again at the end for the current structure set.
1126 getSsm().removeStructureViewerListener(this, oldmfn);
1129 refreshPdbEntries();
1130 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1132 String fileName = modelfilenames[modelnum];
1133 boolean foundEntry = false;
1134 StructureFile pdb = null;
1135 String pdbfile = null;
1136 // model was probably loaded inline - so check the pdb file hashcode
1139 // calculate essential attributes for the pdb data imported inline.
1140 // prolly need to resolve modelnumber properly - for now just use our
1142 pdbfile = viewer.getData(
1143 "" + (1 + _modelFileNameMap[modelnum]) + ".0", "PDB");
1145 // search pdbentries and sequences to find correct pdbentry for this
1147 for (int pe = 0; pe < getPdbCount(); pe++)
1149 boolean matches = false;
1150 addSequence(pe, getSequence()[pe]);
1151 if (fileName == null)
1154 // see JAL-623 - need method of matching pasted data up
1156 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1157 pdbfile, DataSourceType.PASTE,
1158 getIProgressIndicator());
1159 getPdbEntry(modelnum).setFile("INLINE" + pdb.getId());
1166 File fl = new File(getPdbEntry(pe).getFile());
1167 matches = fl.equals(new File(fileName));
1171 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1174 // to be tested. See mantis bug
1175 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1176 DataSourceType protocol = DataSourceType.URL;
1181 protocol = DataSourceType.FILE;
1183 } catch (Exception e)
1188 // Explicitly map to the filename used by Jmol ;
1189 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1190 fileName, protocol, getIProgressIndicator());
1191 // pdbentry[pe].getFile(), protocol);
1197 // add an entry for every chain in the model
1198 for (int i = 0; i < pdb.getChains().size(); i++)
1200 String chid = new String(
1201 pdb.getId() + ":" + pdb.getChains().elementAt(i).id);
1202 chainFile.put(chid, fileName);
1203 chainNames.add(chid);
1205 notifyLoaded = true;
1209 if (!foundEntry && associateNewStructs)
1211 // this is a foreign pdb file that jalview doesn't know about - add
1212 // it to the dataset and try to find a home - either on a matching
1213 // sequence or as a new sequence.
1214 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1216 // parse pdb file into a chain, etc.
1217 // locate best match for pdb in associated views and add mapping to
1219 // if properly registered then
1220 notifyLoaded = true;
1225 // so finally, update the jmol bits and pieces
1226 // if (jmolpopup != null)
1228 // // potential for deadlock here:
1229 // // jmolpopup.updateComputedMenus();
1231 if (!isLoadingFromArchive())
1234 "model *; select backbone;restrict;cartoon;wireframe off;spacefill off");
1236 // register ourselves as a listener and notify the gui that it needs to
1238 getSsm().addStructureViewerListener(this);
1241 FeatureRenderer fr = getFeatureRenderer(null);
1247 loadNotifiesHandled++;
1249 setLoadingFromArchive(false);
1253 public List<String> getChainNames()
1258 protected IProgressIndicator getIProgressIndicator()
1263 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1265 notifyAtomPicked(iatom, strMeasure, null);
1268 public abstract void notifyScriptTermination(String strStatus,
1272 * display a message echoed from the jmol viewer
1276 public abstract void sendConsoleEcho(String strEcho); /*
1277 * { showConsole(true);
1279 * history.append("\n" +
1283 // /End JmolStatusListener
1284 // /////////////////////////////
1288 * status message - usually the response received after a script
1291 public abstract void sendConsoleMessage(String strStatus);
1294 public void setCallbackFunction(String callbackType,
1295 String callbackFunction)
1297 System.err.println("Ignoring set-callback request to associate "
1298 + callbackType + " with function " + callbackFunction);
1303 public void setJalviewColourScheme(ColourSchemeI cs)
1305 colourBySequence = false;
1313 StringBuilder command = new StringBuilder(128);
1314 command.append("select *;color white;");
1315 List<String> residueSet = ResidueProperties.getResidues(isNucleotide(),
1317 for (String resName : residueSet)
1319 char res = resName.length() == 3
1320 ? ResidueProperties.getSingleCharacterCode(resName)
1321 : resName.charAt(0);
1322 Color col = cs.findColour(res, 0, null, null, 0f);
1323 command.append("select " + resName + ";color[" + col.getRed() + ","
1324 + col.getGreen() + "," + col.getBlue() + "];");
1327 evalStateCommand(command.toString());
1331 public void showHelp()
1333 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1337 * open the URL somehow
1341 public abstract void showUrl(String url, String target);
1344 * called when the binding thinks the UI needs to be refreshed after a Jmol
1345 * state change. this could be because structures were loaded, or because an
1346 * error has occured.
1348 public abstract void refreshGUI();
1351 * called to show or hide the associated console window container.
1355 public abstract void showConsole(boolean show);
1358 public static Viewer getJmolData(JmolParser jmolParser)
1360 return (Viewer) JmolViewer.allocateViewer(null, null, null, null, null,
1361 "-x -o -n", jmolParser);
1368 * @param renderPanel
1370 * - when true will initialise jmol's file IO system (should be false
1371 * in applet context)
1373 * @param documentBase
1375 * @param commandOptions
1377 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1378 String htmlName, URL documentBase, URL codeBase,
1379 String commandOptions)
1381 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1382 codeBase, commandOptions, null, null);
1387 * @param renderPanel
1389 * - when true will initialise jmol's file IO system (should be false
1390 * in applet context)
1392 * @param documentBase
1394 * @param commandOptions
1395 * @param consolePanel
1396 * - panel to contain Jmol console
1397 * @param buttonsToShow
1398 * - buttons to show on the console, in order
1400 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1401 String htmlName, URL documentBase, URL codeBase,
1402 String commandOptions, final Container consolePanel,
1403 String buttonsToShow)
1406 System.err.println("Allocating Jmol Viewer: " + commandOptions);
1408 if (commandOptions == null)
1410 commandOptions = "";
1412 viewer = (Viewer) JmolViewer.allocateViewer(renderPanel,
1413 (jmolfileio ? new SmarterJmolAdapter() : null),
1414 htmlName + ((Object) this).toString(), documentBase, codeBase,
1415 commandOptions, this);
1417 viewer.setJmolStatusListener(this); // extends JmolCallbackListener
1420 console = createJmolConsole(consolePanel, buttonsToShow);
1421 } catch (Throwable e) {
1422 System.err.println("Could not create Jmol application console. " + e.getMessage());
1423 e.printStackTrace();
1425 if (consolePanel != null)
1427 consolePanel.addComponentListener(this);
1433 protected abstract JmolAppConsoleInterface createJmolConsole(
1434 Container consolePanel, String buttonsToShow);
1436 // BH 2018 -- Jmol console is not working due to problems with styled documents.
1439 protected org.jmol.api.JmolAppConsoleInterface console = null;
1442 public void setBackgroundColour(java.awt.Color col)
1445 jmolScript("background [" + col.getRed() + ","
1446 + col.getGreen() + "," + col.getBlue() + "];");
1450 private String jmolScript(String script)
1453 System.err.println(">>Jmol>> " + script);
1455 String s = viewer.scriptWait(script);
1457 System.err.println("<<Jmol<< " + s);
1463 public int[] resizeInnerPanel(String data)
1465 // Jalview doesn't honour resize panel requests
1472 protected void closeConsole()
1474 if (console != null)
1478 console.setVisible(false);
1481 } catch (Exception x)
1490 * ComponentListener method
1493 public void componentMoved(ComponentEvent e)
1498 * ComponentListener method
1501 public void componentResized(ComponentEvent e)
1506 * ComponentListener method
1509 public void componentShown(ComponentEvent e)
1515 * ComponentListener method
1518 public void componentHidden(ComponentEvent e)