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());
175 releaseUIResources();
179 public void colourByChain()
181 colourBySequence = false;
182 // TODO: colour by chain should colour each chain distinctly across all
184 // TODO: http://issues.jalview.org/browse/JAL-628
185 evalStateCommand("select *;color chain");
189 public void colourByCharge()
191 colourBySequence = false;
192 evalStateCommand("select *;color white;select ASP,GLU;color red;"
193 + "select LYS,ARG;color blue;select CYS;color yellow");
197 * superpose the structures associated with sequences in the alignment
198 * according to their corresponding positions.
200 public void superposeStructures(AlignmentI alignment)
202 superposeStructures(alignment, -1, null);
206 * superpose the structures associated with sequences in the alignment
207 * according to their corresponding positions. ded)
209 * @param refStructure
210 * - select which pdb file to use as reference (default is -1 - the
211 * first structure in the alignment)
213 public void superposeStructures(AlignmentI alignment, int refStructure)
215 superposeStructures(alignment, refStructure, null);
219 * superpose the structures associated with sequences in the alignment
220 * according to their corresponding positions. ded)
222 * @param refStructure
223 * - select which pdb file to use as reference (default is -1 - the
224 * first structure in the alignment)
228 public void superposeStructures(AlignmentI alignment, int refStructure,
229 HiddenColumns hiddenCols)
231 superposeStructures(new AlignmentI[] { alignment },
233 { refStructure }, new HiddenColumns[] { hiddenCols });
240 public String superposeStructures(AlignmentI[] _alignment,
241 int[] _refStructure, HiddenColumns[] _hiddenCols)
243 while (viewer.isScriptExecuting())
248 } catch (InterruptedException i)
254 * get the distinct structure files modelled
255 * (a file with multiple chains may map to multiple sequences)
257 String[] files = getStructureFiles();
258 if (!waitForFileLoad(files))
263 StringBuilder selectioncom = new StringBuilder(256);
264 // In principle - nSeconds specifies the speed of animation for each
265 // superposition - but is seems to behave weirdly, so we don't specify it.
266 String nSeconds = " ";
267 if (files.length > 10)
269 nSeconds = " 0.005 ";
273 nSeconds = " " + (2.0 / files.length) + " ";
274 // if (nSeconds).substring(0,5)+" ";
277 // see JAL-1345 - should really automatically turn off the animation for
278 // large numbers of structures, but Jmol doesn't seem to allow that.
280 // union of all aligned positions are collected together.
281 for (int a = 0; a < _alignment.length; a++)
283 int refStructure = _refStructure[a];
284 AlignmentI alignment = _alignment[a];
285 HiddenColumns hiddenCols = _hiddenCols[a];
286 if (a > 0 && selectioncom.length() > 0 && !selectioncom
287 .substring(selectioncom.length() - 1).equals("|"))
289 selectioncom.append("|");
291 // process this alignment
292 if (refStructure >= files.length)
295 "Invalid reference structure value " + refStructure);
300 * 'matched' bit j will be set for visible alignment columns j where
301 * all sequences have a residue with a mapping to the PDB structure
303 BitSet matched = new BitSet();
304 for (int m = 0; m < alignment.getWidth(); m++)
306 if (hiddenCols == null || hiddenCols.isVisible(m))
312 SuperposeData[] structures = new SuperposeData[files.length];
313 for (int f = 0; f < files.length; f++)
315 structures[f] = new SuperposeData(alignment.getWidth());
319 * Calculate the superposable alignment columns ('matched'), and the
320 * corresponding structure residue positions (structures.pdbResNo)
322 int candidateRefStructure = findSuperposableResidues(alignment,
323 matched, structures);
324 if (refStructure < 0)
327 * If no reference structure was specified, pick the first one that has
328 * a mapping in the alignment
330 refStructure = candidateRefStructure;
333 String[] selcom = new String[files.length];
334 int nmatched = matched.cardinality();
337 return (MessageManager.formatMessage("label.insufficient_residues",
342 * generate select statements to select regions to superimpose structures
345 // TODO extract method to construct selection statements
346 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
348 String chainCd = ":" + structures[pdbfnum].chain;
351 StringBuilder molsel = new StringBuilder();
354 int nextColumnMatch = matched.nextSetBit(0);
355 while (nextColumnMatch != -1)
357 int pdbResNo = structures[pdbfnum].pdbResNo[nextColumnMatch];
358 if (lpos != pdbResNo - 1)
364 molsel.append(chainCd);
371 // continuous run - and lpos >-1
374 // at the beginning, so add dash
381 nextColumnMatch = matched.nextSetBit(nextColumnMatch + 1);
384 * add final selection phrase
389 molsel.append(chainCd);
392 if (molsel.length() > 1)
394 selcom[pdbfnum] = molsel.toString();
395 selectioncom.append("((");
396 selectioncom.append(selcom[pdbfnum].substring(1,
397 selcom[pdbfnum].length() - 1));
398 selectioncom.append(" )& ");
399 selectioncom.append(pdbfnum + 1);
400 selectioncom.append(".1)");
401 if (pdbfnum < files.length - 1)
403 selectioncom.append("|");
408 selcom[pdbfnum] = null;
412 StringBuilder command = new StringBuilder(256);
413 // command.append("set spinFps 10;\n");
415 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
417 if (pdbfnum == refStructure || selcom[pdbfnum] == null
418 || selcom[refStructure] == null)
422 command.append("echo ");
423 command.append("\"Superposing (");
424 command.append(structures[pdbfnum].pdbId);
425 command.append(") against reference (");
426 command.append(structures[refStructure].pdbId);
427 command.append(")\";\ncompare " + nSeconds);
429 command.append(Integer.toString(1 + pdbfnum));
430 command.append(".1} {");
431 command.append(Integer.toString(1 + refStructure));
432 // conformation=1 excludes alternate locations for CA (JAL-1757)
434 ".1} SUBSET {(*.CA | *.P) and conformation=1} ATOMS ");
436 // for (int s = 0; s < 2; s++)
438 // command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
440 command.append(selcom[pdbfnum]);
441 command.append(selcom[refStructure]);
442 command.append(" ROTATE TRANSLATE;\n");
444 if (selectioncom.length() > 0)
446 // TODO is performing selectioncom redundant here? is done later on
447 // System.out.println("Select regions:\n" + selectioncom.toString());
448 evalStateCommand("select *; cartoons off; backbone; select ("
449 + selectioncom.toString() + "); cartoons; ");
450 // selcom.append("; ribbons; ");
451 String cmdString = command.toString();
452 // System.out.println("Superimpose command(s):\n" + cmdString);
454 evalStateCommand(cmdString);
457 if (selectioncom.length() > 0)
458 {// finally, mark all regions that were superposed.
459 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
461 selectioncom.setLength(selectioncom.length() - 1);
463 // System.out.println("Select regions:\n" + selectioncom.toString());
464 evalStateCommand("select *; cartoons off; backbone; select ("
465 + selectioncom.toString() + "); cartoons; ");
466 // evalStateCommand("select *; backbone; select "+selcom.toString()+";
467 // cartoons; center "+selcom.toString());
473 public void evalStateCommand(String command)
476 if (lastCommand == null || !lastCommand.equals(command))
478 jmolScript(command + "\n");
481 lastCommand = command;
484 Thread colourby = null;
487 * Sends a set of colour commands to the structure viewer
489 * @param colourBySequenceCommands
492 protected void colourBySequence(
493 final StructureMappingcommandSet[] colourBySequenceCommands)
495 if (colourby != null)
497 colourby.interrupt();
500 Thread colourby = new Thread(new Runnable()
505 for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands)
507 for (String cbyseq : cpdbbyseq.commands)
509 executeWhenReady(cbyseq);
515 this.colourby = colourby;
525 protected StructureMappingcommandSet[] getColourBySequenceCommands(
526 String[] files, SequenceRenderer sr, AlignmentViewPanel viewPanel)
528 return JmolCommands.getColourBySequenceCommand(getSsm(), files,
529 getSequence(), sr, viewPanel);
535 protected void executeWhenReady(String command)
537 evalStateCommand(command);
540 public void createImage(String file, String type, int quality)
542 System.out.println("JMOL CREATE IMAGE");
546 public String createImage(String fileName, String type,
547 Object textOrBytes, int quality)
549 System.out.println("JMOL CREATE IMAGE");
554 public String eval(String strEval)
556 // System.out.println(strEval);
557 // "# 'eval' is implemented only for the applet.";
561 // End StructureListener
562 // //////////////////////////
565 public float[][] functionXY(String functionName, int x, int y)
571 public float[][][] functionXYZ(String functionName, int nx, int ny,
574 // TODO Auto-generated method stub
578 public Color getColour(int atomIndex, int pdbResNum, String chain,
581 if (getModelNum(pdbfile) < 0)
585 // TODO: verify atomIndex is selecting correct model.
586 // return new Color(viewer.getAtomArgb(atomIndex)); Jmol 12.2.4
587 int colour = viewer.ms.at[atomIndex].atomPropertyInt(T.color);
588 return new Color(colour);
592 * instruct the Jalview binding to update the pdbentries vector if necessary
593 * prior to matching the jmol view's contents to the list of structure files
594 * Jalview knows about.
596 public abstract void refreshPdbEntries();
598 private int getModelNum(String modelFileName)
600 String[] mfn = getStructureFiles();
605 for (int i = 0; i < mfn.length; i++)
607 if (mfn[i].equalsIgnoreCase(modelFileName))
616 * map between index of model filename returned from getPdbFile and the first
617 * index of models from this file in the viewer. Note - this is not trimmed -
618 * use getPdbFile to get number of unique models.
620 private int _modelFileNameMap[];
622 // ////////////////////////////////
623 // /StructureListener
625 public synchronized String[] getPdbFilex()
629 return new String[0];
631 if (modelFileNames == null)
633 List<String> mset = new ArrayList<>();
634 _modelFileNameMap = new int[viewer.ms.mc];
635 String m = viewer.ms.getModelFileName(0);
641 filePath = new File(m).getAbsolutePath();
642 } catch (AccessControlException x)
644 // usually not allowed to do this in applet
646 "jmolBinding: Using local file string from Jmol: " + m);
648 if (filePath.indexOf("/file:") != -1)
650 // applet path with docroot - discard as format won't match pdbfile
654 _modelFileNameMap[0] = 0; // filename index for first model is always 0.
657 for (int i = 1; i < viewer.ms.mc; i++)
659 m = viewer.ms.getModelFileName(i);
665 filePath = new File(m).getAbsolutePath();
666 } catch (AccessControlException x)
668 // usually not allowed to do this in applet, so keep raw handle
669 // System.err.println("jmolBinding: Using local file string from
675 * add this model unless it is read from a structure file we have
676 * already seen (example: 2MJW is an NMR structure with 10 models)
678 if (!mset.contains(filePath))
681 _modelFileNameMap[j] = i; // record the model index for the filename
685 modelFileNames = mset.toArray(new String[mset.size()]);
687 return modelFileNames;
691 public synchronized String[] getStructureFiles()
693 List<String> mset = new ArrayList<>();
696 return new String[0];
699 if (modelFileNames == null)
701 int modelCount = viewer.ms.mc;
702 String filePath = null;
703 for (int i = 0; i < modelCount; ++i)
705 filePath = viewer.ms.getModelFileName(i);
706 if (!mset.contains(filePath))
711 modelFileNames = mset.toArray(new String[mset.size()]);
714 return modelFileNames;
718 * map from string to applet
721 public Map<String, Object> getRegistryInfo()
723 // TODO Auto-generated method stub
727 // ///////////////////////////////
728 // JmolStatusListener
730 public void handlePopupMenu(int x, int y)
732 // jmolpopup.show(x, y);
733 // jmolpopup.jpiShow(x, y);
737 * Highlight zero, one or more atoms on the structure
740 public void highlightAtoms(List<AtomSpec> atoms)
744 if (resetLastRes.length() > 0)
746 jmolScript(resetLastRes.toString());
747 resetLastRes.setLength(0);
749 for (AtomSpec atom : atoms)
751 highlightAtom(atom.getAtomIndex(), atom.getPdbResNum(),
752 atom.getChain(), atom.getPdbFile());
758 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
761 if (modelFileNames == null)
766 // look up file model number for this pdbfile
768 // may need to adjust for URLencoding here - we don't worry about that yet.
769 while (mdlNum < modelFileNames.length
770 && !pdbfile.equals(modelFileNames[mdlNum]))
774 if (mdlNum == modelFileNames.length)
781 StringBuilder cmd = new StringBuilder(64);
782 cmd.append("select " + pdbResNum); // +modelNum
784 resetLastRes.append("select " + pdbResNum); // +modelNum
787 resetLastRes.append(":");
788 if (!chain.equals(" "))
791 resetLastRes.append(chain);
794 cmd.append(" /" + (mdlNum + 1));
795 resetLastRes.append("/" + (mdlNum + 1));
797 cmd.append(";wireframe 100;" + cmd.toString() + " and not hetero;");
799 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
800 + " and not hetero; spacefill 0;");
802 cmd.append("spacefill 200;select none");
804 jmolScript(cmd.toString());
809 boolean debug = true;
811 private void jmolHistory(boolean enable)
813 jmolScript("History " + ((debug || enable) ? "on" : "off"));
816 public void loadInline(String string)
820 // viewer.loadInline(strModel, isAppend);
822 // construct fake fullPathName and fileName so we can identify the file
824 // Then, construct pass a reader for the string to Jmol.
825 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
826 // fileName, null, reader, false, null, null, 0);
827 viewer.openStringInline(string);
830 public void mouseOverStructure(int atomIndex, String strInfo)
833 int alocsep = strInfo.indexOf("^");
834 int mdlSep = strInfo.indexOf("/");
835 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
837 if (chainSeparator == -1)
839 chainSeparator = strInfo.indexOf(".");
840 if (mdlSep > -1 && mdlSep < chainSeparator)
842 chainSeparator1 = chainSeparator;
843 chainSeparator = mdlSep;
846 // handle insertion codes
849 pdbResNum = Integer.parseInt(
850 strInfo.substring(strInfo.indexOf("]") + 1, alocsep));
855 pdbResNum = Integer.parseInt(
856 strInfo.substring(strInfo.indexOf("]") + 1, chainSeparator));
860 if (strInfo.indexOf(":") > -1)
862 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
863 strInfo.indexOf("."));
870 String pdbfilename = modelFileNames[frameNo]; // default is first or current
874 if (chainSeparator1 == -1)
876 chainSeparator1 = strInfo.indexOf(".", mdlSep);
878 String mdlId = (chainSeparator1 > -1)
879 ? strInfo.substring(mdlSep + 1, chainSeparator1)
880 : strInfo.substring(mdlSep + 1);
883 // recover PDB filename for the model hovered over.
884 int mnumber = new Integer(mdlId).intValue() - 1;
885 if (_modelFileNameMap != null)
887 int _mp = _modelFileNameMap.length - 1;
889 while (mnumber < _modelFileNameMap[_mp])
893 pdbfilename = modelFileNames[_mp];
897 if (mnumber >= 0 && mnumber < modelFileNames.length)
899 pdbfilename = modelFileNames[mnumber];
902 if (pdbfilename == null)
904 pdbfilename = new File(viewer.ms.getModelFileName(mnumber))
908 } catch (Exception e)
913 if (lastMessage == null || !lastMessage.equals(strInfo))
915 getSsm().mouseOverStructure(pdbResNum, chainId, pdbfilename);
918 lastMessage = strInfo;
921 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
925 System.err.println("Ignoring additional hover info: " + data
926 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
928 mouseOverStructure(atomIndex, strInfo);
932 * { if (history != null && strStatus != null &&
933 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
937 public void notifyAtomPicked(int atomIndex, String strInfo,
941 * this implements the toggle label behaviour copied from the original
942 * structure viewer, mc_view
946 System.err.println("Ignoring additional pick data string " + strData);
948 int chainSeparator = strInfo.indexOf(":");
950 if (chainSeparator == -1)
952 chainSeparator = strInfo.indexOf(".");
955 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
957 String mdlString = "";
958 if ((p = strInfo.indexOf(":")) > -1)
960 picked += strInfo.substring(p, strInfo.indexOf("."));
963 if ((p = strInfo.indexOf("/")) > -1)
965 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
967 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
971 if (!atomsPicked.contains(picked))
973 jmolScript("select " + picked + ";label %n %r:%c");
974 atomsPicked.addElement(picked);
978 viewer.evalString("select " + picked + ";label off");
979 atomsPicked.removeElement(picked);
982 // TODO: in application this happens
984 // if (scriptWindow != null)
986 // scriptWindow.sendConsoleMessage(strInfo);
987 // scriptWindow.sendConsoleMessage("\n");
993 public void notifyCallback(CBK type, Object[] data)
1000 notifyFileLoaded((String) data[1], (String) data[2],
1001 (String) data[3], (String) data[4],
1002 ((Integer) data[5]).intValue());
1006 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
1008 // also highlight in alignment
1009 // deliberate fall through
1011 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1015 notifyScriptTermination((String) data[2],
1016 ((Integer) data[3]).intValue());
1019 sendConsoleEcho((String) data[1]);
1023 (data == null) ? ((String) null) : (String) data[1]);
1026 // System.err.println("Ignoring error callback.");
1037 "Unhandled callback " + type + " " + data[1].toString());
1040 } catch (Exception e)
1042 System.err.println("Squashed Jmol callback handler error:");
1043 e.printStackTrace();
1048 public boolean notifyEnabled(CBK callbackPick)
1050 switch (callbackPick)
1066 // incremented every time a load notification is successfully handled -
1067 // lightweight mechanism for other threads to detect when they can start
1068 // referrring to new structures.
1069 private long loadNotifiesHandled = 0;
1071 public long getLoadNotifiesHandled()
1073 return loadNotifiesHandled;
1076 public void notifyFileLoaded(String fullPathName, String fileName2,
1077 String modelName, String errorMsg, int modelParts)
1079 if (errorMsg != null)
1081 fileLoadingError = errorMsg;
1085 // TODO: deal sensibly with models loaded inLine:
1086 // modelName will be null, as will fullPathName.
1088 // the rest of this routine ignores the arguments, and simply interrogates
1089 // the Jmol view to find out what structures it contains, and adds them to
1090 // the structure selection manager.
1091 fileLoadingError = null;
1092 String[] oldmodels = modelFileNames;
1093 modelFileNames = null;
1094 chainNames = new ArrayList<>();
1095 chainFile = new Hashtable<>();
1096 boolean notifyLoaded = false;
1097 String[] modelfilenames = getStructureFiles();
1098 // first check if we've lost any structures
1099 if (oldmodels != null && oldmodels.length > 0)
1102 for (int i = 0; i < oldmodels.length; i++)
1104 for (int n = 0; n < modelfilenames.length; n++)
1106 if (modelfilenames[n] == oldmodels[i])
1108 oldmodels[i] = null;
1112 if (oldmodels[i] != null)
1119 String[] oldmfn = new String[oldm];
1121 for (int i = 0; i < oldmodels.length; i++)
1123 if (oldmodels[i] != null)
1125 oldmfn[oldm++] = oldmodels[i];
1128 // deregister the Jmol instance for these structures - we'll add
1129 // ourselves again at the end for the current structure set.
1130 getSsm().removeStructureViewerListener(this, oldmfn);
1133 refreshPdbEntries();
1134 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1136 String fileName = modelfilenames[modelnum];
1137 boolean foundEntry = false;
1138 StructureFile pdb = null;
1139 String pdbfile = null;
1140 // model was probably loaded inline - so check the pdb file hashcode
1143 // calculate essential attributes for the pdb data imported inline.
1144 // prolly need to resolve modelnumber properly - for now just use our
1146 pdbfile = viewer.getData(
1147 "" + (1 + _modelFileNameMap[modelnum]) + ".0", "PDB");
1149 // search pdbentries and sequences to find correct pdbentry for this
1151 for (int pe = 0; pe < getPdbCount(); pe++)
1153 boolean matches = false;
1154 addSequence(pe, getSequence()[pe]);
1155 if (fileName == null)
1158 // see JAL-623 - need method of matching pasted data up
1160 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1161 pdbfile, DataSourceType.PASTE, getIProgressIndicator());
1162 getPdbEntry(modelnum).setFile("INLINE" + pdb.getId());
1169 File fl = new File(getPdbEntry(pe).getFile());
1170 matches = fl.equals(new File(fileName));
1174 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1177 // to be tested. See mantis bug
1178 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1179 DataSourceType protocol = DataSourceType.URL;
1184 protocol = DataSourceType.FILE;
1186 } catch (Exception e)
1191 // Explicitly map to the filename used by Jmol ;
1192 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1193 fileName, protocol, getIProgressIndicator());
1194 // pdbentry[pe].getFile(), protocol);
1200 // add an entry for every chain in the model
1201 for (int i = 0; i < pdb.getChains().size(); i++)
1203 String chid = new String(
1204 pdb.getId() + ":" + pdb.getChains().elementAt(i).id);
1205 chainFile.put(chid, fileName);
1206 chainNames.add(chid);
1208 notifyLoaded = true;
1212 if (!foundEntry && associateNewStructs)
1214 // this is a foreign pdb file that jalview doesn't know about - add
1215 // it to the dataset and try to find a home - either on a matching
1216 // sequence or as a new sequence.
1217 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1219 // parse pdb file into a chain, etc.
1220 // locate best match for pdb in associated views and add mapping to
1222 // if properly registered then
1223 notifyLoaded = true;
1228 // so finally, update the jmol bits and pieces
1229 // if (jmolpopup != null)
1231 // // potential for deadlock here:
1232 // // jmolpopup.updateComputedMenus();
1234 if (!isLoadingFromArchive())
1237 "model *; select backbone;restrict;cartoon;wireframe off;spacefill off");
1239 // register ourselves as a listener and notify the gui that it needs to
1241 getSsm().addStructureViewerListener(this);
1244 FeatureRenderer fr = getFeatureRenderer(null);
1250 loadNotifiesHandled++;
1252 setLoadingFromArchive(false);
1256 public List<String> getChainNames()
1261 protected IProgressIndicator getIProgressIndicator()
1266 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1268 notifyAtomPicked(iatom, strMeasure, null);
1271 public abstract void notifyScriptTermination(String strStatus,
1275 * display a message echoed from the jmol viewer
1279 public abstract void sendConsoleEcho(String strEcho); /*
1280 * { showConsole(true);
1282 * history.append("\n" +
1286 // /End JmolStatusListener
1287 // /////////////////////////////
1291 * status message - usually the response received after a script
1294 public abstract void sendConsoleMessage(String strStatus);
1297 public void setCallbackFunction(String callbackType,
1298 String callbackFunction)
1300 System.err.println("Ignoring set-callback request to associate "
1301 + callbackType + " with function " + callbackFunction);
1306 public void setJalviewColourScheme(ColourSchemeI cs)
1308 colourBySequence = false;
1316 StringBuilder command = new StringBuilder(128);
1317 command.append("select *;color white;");
1318 List<String> residueSet = ResidueProperties.getResidues(isNucleotide(),
1320 for (String resName : residueSet)
1322 char res = resName.length() == 3
1323 ? ResidueProperties.getSingleCharacterCode(resName)
1324 : resName.charAt(0);
1325 Color col = cs.findColour(res, 0, null, null, 0f);
1326 command.append("select " + resName + ";color[" + col.getRed() + ","
1327 + col.getGreen() + "," + col.getBlue() + "];");
1330 evalStateCommand(command.toString());
1334 public void showHelp()
1336 showUrl("http://wiki.jmol.org"
1337 // BH 2018 "http://jmol.sourceforge.net/docs/JmolUserGuide/"
1342 * open the URL somehow
1346 public abstract void showUrl(String url, String target);
1349 * called when the binding thinks the UI needs to be refreshed after a Jmol
1350 * state change. this could be because structures were loaded, or because an
1351 * error has occured.
1353 public abstract void refreshGUI();
1356 * called to show or hide the associated console window container.
1360 public abstract void showConsole(boolean show);
1362 public static Viewer getJmolData(JmolParser jmolParser)
1364 return (Viewer) JmolViewer.allocateViewer(null, null, null, null, null,
1365 "-x -o -n", jmolParser);
1372 * @param renderPanel
1374 * - when true will initialise jmol's file IO system (should be false
1375 * in applet context)
1377 * @param documentBase
1379 * @param commandOptions
1381 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1382 String htmlName, URL documentBase, URL codeBase,
1383 String commandOptions)
1385 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1386 codeBase, commandOptions, null, null);
1391 * @param renderPanel
1393 * - when true will initialise jmol's file IO system (should be false
1394 * in applet context)
1396 * @param documentBase
1398 * @param commandOptions
1399 * @param consolePanel
1400 * - panel to contain Jmol console
1401 * @param buttonsToShow
1402 * - buttons to show on the console, in order
1404 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1405 String htmlName, URL documentBase, URL codeBase,
1406 String commandOptions, final Container consolePanel,
1407 String buttonsToShow)
1410 System.err.println("Allocating Jmol Viewer: " + commandOptions);
1412 if (commandOptions == null)
1414 commandOptions = "";
1416 viewer = (Viewer) JmolViewer.allocateViewer(renderPanel,
1417 (jmolfileio ? new SmarterJmolAdapter() : null),
1418 htmlName + ((Object) this).toString(), documentBase, codeBase,
1419 commandOptions, this);
1421 viewer.setJmolStatusListener(this); // extends JmolCallbackListener
1425 console = createJmolConsole(consolePanel, buttonsToShow);
1426 } catch (Throwable e)
1428 System.err.println("Could not create Jmol application console. "
1430 e.printStackTrace();
1432 if (consolePanel != null)
1434 consolePanel.addComponentListener(this);
1440 protected abstract JmolAppConsoleInterface createJmolConsole(
1441 Container consolePanel, String buttonsToShow);
1443 // BH 2018 -- Jmol console is not working due to problems with styled
1446 protected org.jmol.api.JmolAppConsoleInterface console = null;
1449 public void setBackgroundColour(java.awt.Color col)
1452 jmolScript("background [" + col.getRed() + "," + col.getGreen() + ","
1453 + col.getBlue() + "];");
1457 private String jmolScript(String script)
1460 System.err.println(">>Jmol>> " + script);
1462 String s = viewer.scriptWait(script);
1464 System.err.println("<<Jmol<< " + s);
1470 public int[] resizeInnerPanel(String data)
1472 // Jalview doesn't honour resize panel requests
1479 protected void closeConsole()
1481 if (console != null)
1485 console.setVisible(false);
1488 } catch (Exception x)
1497 * ComponentListener method
1500 public void componentMoved(ComponentEvent e)
1505 * ComponentListener method
1508 public void componentResized(ComponentEvent e)
1513 * ComponentListener method
1516 public void componentShown(ComponentEvent e)
1522 * ComponentListener method
1525 public void componentHidden(ComponentEvent e)