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 javax.swing.SwingUtilities;
57 import org.jmol.adapter.smarter.SmarterJmolAdapter;
58 import org.jmol.api.JmolAppConsoleInterface;
59 import org.jmol.api.JmolSelectionListener;
60 import org.jmol.api.JmolStatusListener;
61 import org.jmol.api.JmolViewer;
62 import org.jmol.c.CBK;
63 import org.jmol.script.T;
64 import org.jmol.viewer.Viewer;
66 public abstract class JalviewJmolBinding extends AAStructureBindingModel
67 implements JmolStatusListener, JmolSelectionListener,
70 boolean allChainsSelected = false;
73 * when true, try to search the associated datamodel for sequences that are
74 * associated with any unknown structures in the Jmol view.
76 private boolean associateNewStructs = false;
78 Vector<String> atomsPicked = new Vector<>();
80 private List<String> chainNames;
82 Hashtable<String, String> chainFile;
85 * the default or current model displayed if the model cannot be identified
86 * from the selection message
90 // protected JmolGenericPopup jmolpopup; // not used - remove?
98 StringBuffer resetLastRes = new StringBuffer();
100 public Viewer viewer;
102 public JalviewJmolBinding(StructureSelectionManager ssm,
103 PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
104 DataSourceType protocol)
106 super(ssm, pdbentry, sequenceIs, protocol);
108 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
109 * "jalviewJmol", ap.av.applet .getDocumentBase(),
110 * ap.av.applet.getCodeBase(), "", this);
112 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
116 public JalviewJmolBinding(StructureSelectionManager ssm,
117 SequenceI[][] seqs, Viewer theViewer)
122 viewer.setJmolStatusListener(this);
123 viewer.addSelectionListener(this);
127 * construct a title string for the viewer window based on the data jalview
132 public String getViewerTitle()
134 return getViewerTitle("Jmol", true);
138 * prepare the view for a given set of models/chains. chainList contains
139 * strings of the form 'pdbfilename:Chaincode'
142 * list of chains to make visible
144 public void centerViewer(Vector<String> chainList)
146 StringBuilder cmd = new StringBuilder(128);
148 for (String lbl : chainList)
154 mlength = lbl.indexOf(":", p);
155 } while (p < mlength && mlength < (lbl.length() - 2));
156 // TODO: lookup each pdb id and recover proper model number for it.
157 cmd.append(":" + lbl.substring(mlength + 1) + " /"
158 + (1 + getModelNum(chainFile.get(lbl))) + " or ");
160 if (cmd.length() > 0)
162 cmd.setLength(cmd.length() - 4);
164 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
167 public void closeViewer()
169 // remove listeners for all structures in viewer
170 getSsm().removeStructureViewerListener(this, this.getStructureFiles());
174 releaseUIResources();
178 public void colourByChain()
180 colourBySequence = false;
181 // TODO: colour by chain should colour each chain distinctly across all
183 // TODO: http://issues.jalview.org/browse/JAL-628
184 evalStateCommand("select *;color chain");
188 public void colourByCharge()
190 colourBySequence = false;
191 evalStateCommand("select *;color white;select ASP,GLU;color red;"
192 + "select LYS,ARG;color blue;select CYS;color yellow");
196 * superpose the structures associated with sequences in the alignment
197 * according to their corresponding positions.
199 public void superposeStructures(AlignmentI alignment)
201 superposeStructures(alignment, -1, null);
205 * superpose the structures associated with sequences in the alignment
206 * according to their corresponding positions. ded)
208 * @param refStructure
209 * - select which pdb file to use as reference (default is -1 - the
210 * first structure in the alignment)
212 public void superposeStructures(AlignmentI alignment, int refStructure)
214 superposeStructures(alignment, refStructure, null);
218 * superpose the structures associated with sequences in the alignment
219 * according to their corresponding positions. ded)
221 * @param refStructure
222 * - select which pdb file to use as reference (default is -1 - the
223 * first structure in the alignment)
227 public void superposeStructures(AlignmentI alignment, int refStructure,
228 HiddenColumns hiddenCols)
230 superposeStructures(new AlignmentI[] { alignment },
232 { refStructure }, new HiddenColumns[] { hiddenCols });
239 public String superposeStructures(AlignmentI[] _alignment,
240 int[] _refStructure, HiddenColumns[] _hiddenCols)
242 while (viewer.isScriptExecuting())
247 } catch (InterruptedException i)
253 * get the distinct structure files modelled
254 * (a file with multiple chains may map to multiple sequences)
256 String[] files = getStructureFiles();
257 if (!waitForFileLoad(files))
262 StringBuilder selectioncom = new StringBuilder(256);
263 // In principle - nSeconds specifies the speed of animation for each
264 // superposition - but is seems to behave weirdly, so we don't specify it.
265 String nSeconds = " ";
266 if (files.length > 10)
268 nSeconds = " 0.005 ";
272 nSeconds = " " + (2.0 / files.length) + " ";
273 // if (nSeconds).substring(0,5)+" ";
276 // see JAL-1345 - should really automatically turn off the animation for
277 // large numbers of structures, but Jmol doesn't seem to allow that.
279 // union of all aligned positions are collected together.
280 for (int a = 0; a < _alignment.length; a++)
282 int refStructure = _refStructure[a];
283 AlignmentI alignment = _alignment[a];
284 HiddenColumns hiddenCols = _hiddenCols[a];
285 if (a > 0 && selectioncom.length() > 0 && !selectioncom
286 .substring(selectioncom.length() - 1).equals("|"))
288 selectioncom.append("|");
290 // process this alignment
291 if (refStructure >= files.length)
294 "Invalid reference structure value " + refStructure);
299 * 'matched' bit j will be set for visible alignment columns j where
300 * all sequences have a residue with a mapping to the PDB structure
302 BitSet matched = new BitSet();
303 for (int m = 0; m < alignment.getWidth(); m++)
305 if (hiddenCols == null || hiddenCols.isVisible(m))
311 SuperposeData[] structures = new SuperposeData[files.length];
312 for (int f = 0; f < files.length; f++)
314 structures[f] = new SuperposeData(alignment.getWidth());
318 * Calculate the superposable alignment columns ('matched'), and the
319 * corresponding structure residue positions (structures.pdbResNo)
321 int candidateRefStructure = findSuperposableResidues(alignment,
322 matched, structures);
323 if (refStructure < 0)
326 * If no reference structure was specified, pick the first one that has
327 * a mapping in the alignment
329 refStructure = candidateRefStructure;
332 String[] selcom = new String[files.length];
333 int nmatched = matched.cardinality();
336 return (MessageManager.formatMessage("label.insufficient_residues",
341 * generate select statements to select regions to superimpose structures
344 // TODO extract method to construct selection statements
345 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
347 String chainCd = ":" + structures[pdbfnum].chain;
350 StringBuilder molsel = new StringBuilder();
353 int nextColumnMatch = matched.nextSetBit(0);
354 while (nextColumnMatch != -1)
356 int pdbResNo = structures[pdbfnum].pdbResNo[nextColumnMatch];
357 if (lpos != pdbResNo - 1)
363 molsel.append(chainCd);
370 // continuous run - and lpos >-1
373 // at the beginning, so add dash
380 nextColumnMatch = matched.nextSetBit(nextColumnMatch + 1);
383 * add final selection phrase
388 molsel.append(chainCd);
391 if (molsel.length() > 1)
393 selcom[pdbfnum] = molsel.toString();
394 selectioncom.append("((");
395 selectioncom.append(selcom[pdbfnum].substring(1,
396 selcom[pdbfnum].length() - 1));
397 selectioncom.append(" )& ");
398 selectioncom.append(pdbfnum + 1);
399 selectioncom.append(".1)");
400 if (pdbfnum < files.length - 1)
402 selectioncom.append("|");
407 selcom[pdbfnum] = null;
411 StringBuilder command = new StringBuilder(256);
412 // command.append("set spinFps 10;\n");
414 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
416 if (pdbfnum == refStructure || selcom[pdbfnum] == null
417 || selcom[refStructure] == null)
421 command.append("echo ");
422 command.append("\"Superposing (");
423 command.append(structures[pdbfnum].pdbId);
424 command.append(") against reference (");
425 command.append(structures[refStructure].pdbId);
426 command.append(")\";\ncompare " + nSeconds);
428 command.append(Integer.toString(1 + pdbfnum));
429 command.append(".1} {");
430 command.append(Integer.toString(1 + refStructure));
431 // conformation=1 excludes alternate locations for CA (JAL-1757)
433 ".1} SUBSET {(*.CA | *.P) and conformation=1} ATOMS ");
435 // for (int s = 0; s < 2; s++)
437 // command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
439 command.append(selcom[pdbfnum]);
440 command.append(selcom[refStructure]);
441 command.append(" ROTATE TRANSLATE;\n");
443 if (selectioncom.length() > 0)
445 // TODO is performing selectioncom redundant here? is done later on
446 // System.out.println("Select regions:\n" + selectioncom.toString());
447 evalStateCommand("select *; cartoons off; backbone; select ("
448 + selectioncom.toString() + "); cartoons; ");
449 // selcom.append("; ribbons; ");
450 String cmdString = command.toString();
451 // System.out.println("Superimpose command(s):\n" + cmdString);
453 evalStateCommand(cmdString);
456 if (selectioncom.length() > 0)
457 {// finally, mark all regions that were superposed.
458 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
460 selectioncom.setLength(selectioncom.length() - 1);
462 // System.out.println("Select regions:\n" + selectioncom.toString());
463 evalStateCommand("select *; cartoons off; backbone; select ("
464 + selectioncom.toString() + "); cartoons; ");
465 // evalStateCommand("select *; backbone; select "+selcom.toString()+";
466 // cartoons; center "+selcom.toString());
472 public void evalStateCommand(String command)
475 if (lastCommand == null || !lastCommand.equals(command))
477 viewer.evalStringQuiet(command + "\n");
480 lastCommand = command;
484 * Sends a set of colour commands to the structure viewer
486 * @param colourBySequenceCommands
489 protected void colourBySequence(
490 final StructureMappingcommandSet[] colourBySequenceCommands)
492 SwingUtilities.invokeLater(new Runnable()
497 for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands)
499 for (String cbyseq : cpdbbyseq.commands)
501 executeWhenReady(cbyseq);
515 protected StructureMappingcommandSet[] getColourBySequenceCommands(
516 String[] files, SequenceRenderer sr, AlignmentViewPanel viewPanel)
518 return JmolCommands.getColourBySequenceCommand(getSsm(), files,
519 getSequence(), sr, viewPanel);
525 protected void executeWhenReady(String command)
527 evalStateCommand(command);
530 public void createImage(String file, String type, int quality)
532 System.out.println("JMOL CREATE IMAGE");
536 public String createImage(String fileName, String type,
537 Object textOrBytes, int quality)
539 System.out.println("JMOL CREATE IMAGE");
544 public String eval(String strEval)
546 // System.out.println(strEval);
547 // "# 'eval' is implemented only for the applet.";
551 // End StructureListener
552 // //////////////////////////
555 public float[][] functionXY(String functionName, int x, int y)
561 public float[][][] functionXYZ(String functionName, int nx, int ny,
564 // TODO Auto-generated method stub
568 public Color getColour(int atomIndex, int pdbResNum, String chain,
571 if (getModelNum(pdbfile) < 0)
575 // TODO: verify atomIndex is selecting correct model.
576 // return new Color(viewer.getAtomArgb(atomIndex)); Jmol 12.2.4
577 int colour = viewer.ms.at[atomIndex].atomPropertyInt(T.color);
578 return new Color(colour);
582 * instruct the Jalview binding to update the pdbentries vector if necessary
583 * prior to matching the jmol view's contents to the list of structure files
584 * Jalview knows about.
586 public abstract void refreshPdbEntries();
588 private int getModelNum(String modelFileName)
590 String[] mfn = getStructureFiles();
595 for (int i = 0; i < mfn.length; i++)
597 if (mfn[i].equalsIgnoreCase(modelFileName))
606 * map between index of model filename returned from getPdbFile and the first
607 * index of models from this file in the viewer. Note - this is not trimmed -
608 * use getPdbFile to get number of unique models.
610 private int _modelFileNameMap[];
612 // ////////////////////////////////
613 // /StructureListener
615 public synchronized String[] getPdbFilex()
619 return new String[0];
621 if (modelFileNames == null)
623 List<String> mset = new ArrayList<>();
624 _modelFileNameMap = new int[viewer.ms.mc];
625 String m = viewer.ms.getModelFileName(0);
631 filePath = new File(m).getAbsolutePath();
632 } catch (AccessControlException x)
634 // usually not allowed to do this in applet
636 "jmolBinding: Using local file string from Jmol: " + m);
638 if (filePath.indexOf("/file:") != -1)
640 // applet path with docroot - discard as format won't match pdbfile
644 _modelFileNameMap[0] = 0; // filename index for first model is always 0.
647 for (int i = 1; i < viewer.ms.mc; i++)
649 m = viewer.ms.getModelFileName(i);
655 filePath = new File(m).getAbsolutePath();
656 } catch (AccessControlException x)
658 // usually not allowed to do this in applet, so keep raw handle
659 // System.err.println("jmolBinding: Using local file string from
665 * add this model unless it is read from a structure file we have
666 * already seen (example: 2MJW is an NMR structure with 10 models)
668 if (!mset.contains(filePath))
671 _modelFileNameMap[j] = i; // record the model index for the filename
675 modelFileNames = mset.toArray(new String[mset.size()]);
677 return modelFileNames;
681 public synchronized String[] getStructureFiles()
683 List<String> mset = new ArrayList<>();
686 return new String[0];
689 if (modelFileNames == null)
691 int modelCount = viewer.ms.mc;
692 String filePath = null;
693 for (int i = 0; i < modelCount; ++i)
695 filePath = viewer.ms.getModelFileName(i);
696 if (!mset.contains(filePath))
701 modelFileNames = mset.toArray(new String[mset.size()]);
704 return modelFileNames;
708 * map from string to applet
711 public Map<String, Object> getRegistryInfo()
713 // TODO Auto-generated method stub
717 // ///////////////////////////////
718 // JmolStatusListener
720 public void handlePopupMenu(int x, int y)
722 // jmolpopup.show(x, y);
723 // jmolpopup.jpiShow(x, y);
727 * Highlight zero, one or more atoms on the structure
730 public void highlightAtoms(List<AtomSpec> atoms)
734 if (resetLastRes.length() > 0)
736 viewer.evalStringQuiet(resetLastRes.toString());
737 resetLastRes.setLength(0);
739 for (AtomSpec atom : atoms)
741 highlightAtom(atom.getAtomIndex(), atom.getPdbResNum(),
742 atom.getChain(), atom.getPdbFile());
748 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
751 if (modelFileNames == null)
756 // look up file model number for this pdbfile
758 // may need to adjust for URLencoding here - we don't worry about that yet.
759 while (mdlNum < modelFileNames.length
760 && !pdbfile.equals(modelFileNames[mdlNum]))
764 if (mdlNum == modelFileNames.length)
771 StringBuilder cmd = new StringBuilder(64);
772 cmd.append("select " + pdbResNum); // +modelNum
774 resetLastRes.append("select " + pdbResNum); // +modelNum
777 resetLastRes.append(":");
778 if (!chain.equals(" "))
781 resetLastRes.append(chain);
784 cmd.append(" /" + (mdlNum + 1));
785 resetLastRes.append("/" + (mdlNum + 1));
787 cmd.append(";wireframe 100;" + cmd.toString() + " and not hetero;");
789 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
790 + " and not hetero; spacefill 0;");
792 cmd.append("spacefill 200;select none");
794 viewer.evalStringQuiet(cmd.toString());
799 boolean debug = true;
801 private void jmolHistory(boolean enable)
803 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
806 public void loadInline(String string)
810 // viewer.loadInline(strModel, isAppend);
812 // construct fake fullPathName and fileName so we can identify the file
814 // Then, construct pass a reader for the string to Jmol.
815 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
816 // fileName, null, reader, false, null, null, 0);
817 viewer.openStringInline(string);
820 public void mouseOverStructure(int atomIndex, String strInfo)
823 int alocsep = strInfo.indexOf("^");
824 int mdlSep = strInfo.indexOf("/");
825 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
827 if (chainSeparator == -1)
829 chainSeparator = strInfo.indexOf(".");
830 if (mdlSep > -1 && mdlSep < chainSeparator)
832 chainSeparator1 = chainSeparator;
833 chainSeparator = mdlSep;
836 // handle insertion codes
839 pdbResNum = Integer.parseInt(
840 strInfo.substring(strInfo.indexOf("]") + 1, alocsep));
845 pdbResNum = Integer.parseInt(
846 strInfo.substring(strInfo.indexOf("]") + 1, chainSeparator));
850 if (strInfo.indexOf(":") > -1)
852 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
853 strInfo.indexOf("."));
860 String pdbfilename = modelFileNames[frameNo]; // default is first or current
864 if (chainSeparator1 == -1)
866 chainSeparator1 = strInfo.indexOf(".", mdlSep);
868 String mdlId = (chainSeparator1 > -1)
869 ? strInfo.substring(mdlSep + 1, chainSeparator1)
870 : strInfo.substring(mdlSep + 1);
873 // recover PDB filename for the model hovered over.
874 int mnumber = new Integer(mdlId).intValue() - 1;
875 if (_modelFileNameMap != null)
877 int _mp = _modelFileNameMap.length - 1;
879 while (mnumber < _modelFileNameMap[_mp])
883 pdbfilename = modelFileNames[_mp];
887 if (mnumber >= 0 && mnumber < modelFileNames.length)
889 pdbfilename = modelFileNames[mnumber];
892 if (pdbfilename == null)
894 pdbfilename = new File(viewer.ms.getModelFileName(mnumber))
898 } catch (Exception e)
903 if (lastMessage == null || !lastMessage.equals(strInfo))
905 getSsm().mouseOverStructure(pdbResNum, chainId, pdbfilename);
908 lastMessage = strInfo;
911 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
915 System.err.println("Ignoring additional hover info: " + data
916 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
918 mouseOverStructure(atomIndex, strInfo);
922 * { if (history != null && strStatus != null &&
923 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
927 public void notifyAtomPicked(int atomIndex, String strInfo,
931 * this implements the toggle label behaviour copied from the original
932 * structure viewer, MCView
936 System.err.println("Ignoring additional pick data string " + strData);
938 int chainSeparator = strInfo.indexOf(":");
940 if (chainSeparator == -1)
942 chainSeparator = strInfo.indexOf(".");
945 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
947 String mdlString = "";
948 if ((p = strInfo.indexOf(":")) > -1)
950 picked += strInfo.substring(p, strInfo.indexOf("."));
953 if ((p = strInfo.indexOf("/")) > -1)
955 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
957 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
961 if (!atomsPicked.contains(picked))
963 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
964 atomsPicked.addElement(picked);
968 viewer.evalString("select " + picked + ";label off");
969 atomsPicked.removeElement(picked);
972 // TODO: in application this happens
974 // if (scriptWindow != null)
976 // scriptWindow.sendConsoleMessage(strInfo);
977 // scriptWindow.sendConsoleMessage("\n");
983 public void notifyCallback(CBK type, Object[] data)
990 notifyFileLoaded((String) data[1], (String) data[2],
991 (String) data[3], (String) data[4],
992 ((Integer) data[5]).intValue());
996 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
998 // also highlight in alignment
999 // deliberate fall through
1001 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1005 notifyScriptTermination((String) data[2],
1006 ((Integer) data[3]).intValue());
1009 sendConsoleEcho((String) data[1]);
1013 (data == null) ? ((String) null) : (String) data[1]);
1016 // System.err.println("Ignoring error callback.");
1027 "Unhandled callback " + type + " " + data[1].toString());
1030 } catch (Exception e)
1032 System.err.println("Squashed Jmol callback handler error:");
1033 e.printStackTrace();
1038 public boolean notifyEnabled(CBK callbackPick)
1040 switch (callbackPick)
1056 // incremented every time a load notification is successfully handled -
1057 // lightweight mechanism for other threads to detect when they can start
1058 // referrring to new structures.
1059 private long loadNotifiesHandled = 0;
1061 public long getLoadNotifiesHandled()
1063 return loadNotifiesHandled;
1066 public void notifyFileLoaded(String fullPathName, String fileName2,
1067 String modelName, String errorMsg, int modelParts)
1069 if (errorMsg != null)
1071 fileLoadingError = errorMsg;
1075 // TODO: deal sensibly with models loaded inLine:
1076 // modelName will be null, as will fullPathName.
1078 // the rest of this routine ignores the arguments, and simply interrogates
1079 // the Jmol view to find out what structures it contains, and adds them to
1080 // the structure selection manager.
1081 fileLoadingError = null;
1082 String[] oldmodels = modelFileNames;
1083 modelFileNames = null;
1084 chainNames = new ArrayList<>();
1085 chainFile = new Hashtable<>();
1086 boolean notifyLoaded = false;
1087 String[] modelfilenames = getStructureFiles();
1088 // first check if we've lost any structures
1089 if (oldmodels != null && oldmodels.length > 0)
1092 for (int i = 0; i < oldmodels.length; i++)
1094 for (int n = 0; n < modelfilenames.length; n++)
1096 if (modelfilenames[n] == oldmodels[i])
1098 oldmodels[i] = null;
1102 if (oldmodels[i] != null)
1109 String[] oldmfn = new String[oldm];
1111 for (int i = 0; i < oldmodels.length; i++)
1113 if (oldmodels[i] != null)
1115 oldmfn[oldm++] = oldmodels[i];
1118 // deregister the Jmol instance for these structures - we'll add
1119 // ourselves again at the end for the current structure set.
1120 getSsm().removeStructureViewerListener(this, oldmfn);
1123 refreshPdbEntries();
1124 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1126 String fileName = modelfilenames[modelnum];
1127 boolean foundEntry = false;
1128 StructureFile pdb = null;
1129 String pdbfile = null;
1130 // model was probably loaded inline - so check the pdb file hashcode
1133 // calculate essential attributes for the pdb data imported inline.
1134 // prolly need to resolve modelnumber properly - for now just use our
1136 pdbfile = viewer.getData(
1137 "" + (1 + _modelFileNameMap[modelnum]) + ".0", "PDB");
1139 // search pdbentries and sequences to find correct pdbentry for this
1141 for (int pe = 0; pe < getPdbCount(); pe++)
1143 boolean matches = false;
1144 addSequence(pe, getSequence()[pe]);
1145 if (fileName == null)
1148 // see JAL-623 - need method of matching pasted data up
1150 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1151 pdbfile, DataSourceType.PASTE,
1152 getIProgressIndicator());
1153 getPdbEntry(modelnum).setFile("INLINE" + pdb.getId());
1160 File fl = new File(getPdbEntry(pe).getFile());
1161 matches = fl.equals(new File(fileName));
1165 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1168 // to be tested. See mantis bug
1169 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1170 DataSourceType protocol = DataSourceType.URL;
1175 protocol = DataSourceType.FILE;
1177 } catch (Exception e)
1182 // Explicitly map to the filename used by Jmol ;
1183 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1184 fileName, protocol, getIProgressIndicator());
1185 // pdbentry[pe].getFile(), protocol);
1191 // add an entry for every chain in the model
1192 for (int i = 0; i < pdb.getChains().size(); i++)
1194 String chid = new String(
1195 pdb.getId() + ":" + pdb.getChains().elementAt(i).id);
1196 chainFile.put(chid, fileName);
1197 chainNames.add(chid);
1199 notifyLoaded = true;
1203 if (!foundEntry && associateNewStructs)
1205 // this is a foreign pdb file that jalview doesn't know about - add
1206 // it to the dataset and try to find a home - either on a matching
1207 // sequence or as a new sequence.
1208 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1210 // parse pdb file into a chain, etc.
1211 // locate best match for pdb in associated views and add mapping to
1213 // if properly registered then
1214 notifyLoaded = true;
1219 // so finally, update the jmol bits and pieces
1220 // if (jmolpopup != null)
1222 // // potential for deadlock here:
1223 // // jmolpopup.updateComputedMenus();
1225 if (!isLoadingFromArchive())
1227 viewer.evalStringQuiet(
1228 "model *; select backbone;restrict;cartoon;wireframe off;spacefill off");
1230 // register ourselves as a listener and notify the gui that it needs to
1232 getSsm().addStructureViewerListener(this);
1235 FeatureRenderer fr = getFeatureRenderer(null);
1241 loadNotifiesHandled++;
1243 setLoadingFromArchive(false);
1247 public List<String> getChainNames()
1252 protected abstract IProgressIndicator getIProgressIndicator();
1254 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1256 notifyAtomPicked(iatom, strMeasure, null);
1259 public abstract void notifyScriptTermination(String strStatus,
1263 * display a message echoed from the jmol viewer
1267 public abstract void sendConsoleEcho(String strEcho); /*
1268 * { showConsole(true);
1270 * history.append("\n" +
1274 // /End JmolStatusListener
1275 // /////////////////////////////
1279 * status message - usually the response received after a script
1282 public abstract void sendConsoleMessage(String strStatus);
1285 public void setCallbackFunction(String callbackType,
1286 String callbackFunction)
1288 System.err.println("Ignoring set-callback request to associate "
1289 + callbackType + " with function " + callbackFunction);
1294 public void setJalviewColourScheme(ColourSchemeI cs)
1296 colourBySequence = false;
1304 StringBuilder command = new StringBuilder(128);
1305 command.append("select *;color white;");
1306 List<String> residueSet = ResidueProperties.getResidues(isNucleotide(),
1308 for (String resName : residueSet)
1310 char res = resName.length() == 3
1311 ? ResidueProperties.getSingleCharacterCode(resName)
1312 : resName.charAt(0);
1313 Color col = cs.findColour(res, 0, null, null, 0f);
1314 command.append("select " + resName + ";color[" + col.getRed() + ","
1315 + col.getGreen() + "," + col.getBlue() + "];");
1318 evalStateCommand(command.toString());
1322 public void showHelp()
1324 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1328 * open the URL somehow
1332 public abstract void showUrl(String url, String target);
1335 * called when the binding thinks the UI needs to be refreshed after a Jmol
1336 * state change. this could be because structures were loaded, or because an
1337 * error has occured.
1339 public abstract void refreshGUI();
1342 * called to show or hide the associated console window container.
1346 public abstract void showConsole(boolean show);
1349 * @param renderPanel
1351 * - when true will initialise jmol's file IO system (should be false
1352 * in applet context)
1354 * @param documentBase
1356 * @param commandOptions
1358 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1359 String htmlName, URL documentBase, URL codeBase,
1360 String commandOptions)
1362 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1363 codeBase, commandOptions, null, null);
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
1376 * @param consolePanel
1377 * - panel to contain Jmol console
1378 * @param buttonsToShow
1379 * - buttons to show on the console, in ordr
1381 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1382 String htmlName, URL documentBase, URL codeBase,
1383 String commandOptions, final Container consolePanel,
1384 String buttonsToShow)
1386 if (commandOptions == null)
1388 commandOptions = "";
1390 viewer = (Viewer) JmolViewer.allocateViewer(renderPanel,
1391 (jmolfileio ? new SmarterJmolAdapter() : null),
1392 htmlName + ((Object) this).toString(), documentBase, codeBase,
1393 commandOptions, this);
1395 viewer.setJmolStatusListener(this); // extends JmolCallbackListener
1397 console = createJmolConsole(consolePanel, buttonsToShow);
1398 if (consolePanel != null)
1400 consolePanel.addComponentListener(this);
1406 protected abstract JmolAppConsoleInterface createJmolConsole(
1407 Container consolePanel, String buttonsToShow);
1409 protected org.jmol.api.JmolAppConsoleInterface console = null;
1412 public void setBackgroundColour(java.awt.Color col)
1415 viewer.evalStringQuiet("background [" + col.getRed() + ","
1416 + col.getGreen() + "," + col.getBlue() + "];");
1421 public int[] resizeInnerPanel(String data)
1423 // Jalview doesn't honour resize panel requests
1430 protected void closeConsole()
1432 if (console != null)
1436 console.setVisible(false);
1439 } catch (Exception x)
1448 * ComponentListener method
1451 public void componentMoved(ComponentEvent e)
1456 * ComponentListener method
1459 public void componentResized(ComponentEvent e)
1464 * ComponentListener method
1467 public void componentShown(ComponentEvent e)
1473 * ComponentListener method
1476 public void componentHidden(ComponentEvent e)