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());
172 releaseUIResources();
176 public void colourByChain()
178 colourBySequence = false;
179 // TODO: colour by chain should colour each chain distinctly across all
181 // TODO: http://issues.jalview.org/browse/JAL-628
182 evalStateCommand("select *;color chain");
186 public void colourByCharge()
188 colourBySequence = false;
189 evalStateCommand("select *;color white;select ASP,GLU;color red;"
190 + "select LYS,ARG;color blue;select CYS;color yellow");
194 * superpose the structures associated with sequences in the alignment
195 * according to their corresponding positions.
197 public void superposeStructures(AlignmentI alignment)
199 superposeStructures(alignment, -1, null);
203 * superpose the structures associated with sequences in the alignment
204 * according to their corresponding positions. ded)
206 * @param refStructure
207 * - select which pdb file to use as reference (default is -1 - the
208 * first structure in the alignment)
210 public void superposeStructures(AlignmentI alignment, int refStructure)
212 superposeStructures(alignment, refStructure, null);
216 * superpose the structures associated with sequences in the alignment
217 * according to their corresponding positions. ded)
219 * @param refStructure
220 * - select which pdb file to use as reference (default is -1 - the
221 * first structure in the alignment)
225 public void superposeStructures(AlignmentI alignment, int refStructure,
226 HiddenColumns hiddenCols)
228 superposeStructures(new AlignmentI[] { alignment },
230 { refStructure }, new HiddenColumns[] { hiddenCols });
237 public String superposeStructures(AlignmentI[] _alignment,
238 int[] _refStructure, HiddenColumns[] _hiddenCols)
240 while (viewer.isScriptExecuting())
245 } catch (InterruptedException i)
251 * get the distinct structure files modelled
252 * (a file with multiple chains may map to multiple sequences)
254 String[] files = getStructureFiles();
255 if (!waitForFileLoad(files))
260 StringBuilder selectioncom = new StringBuilder(256);
261 // In principle - nSeconds specifies the speed of animation for each
262 // superposition - but is seems to behave weirdly, so we don't specify it.
263 String nSeconds = " ";
264 if (files.length > 10)
266 nSeconds = " 0.005 ";
270 nSeconds = " " + (2.0 / files.length) + " ";
271 // if (nSeconds).substring(0,5)+" ";
274 // see JAL-1345 - should really automatically turn off the animation for
275 // large numbers of structures, but Jmol doesn't seem to allow that.
277 // union of all aligned positions are collected together.
278 for (int a = 0; a < _alignment.length; a++)
280 int refStructure = _refStructure[a];
281 AlignmentI alignment = _alignment[a];
282 HiddenColumns hiddenCols = _hiddenCols[a];
283 if (a > 0 && selectioncom.length() > 0 && !selectioncom
284 .substring(selectioncom.length() - 1).equals("|"))
286 selectioncom.append("|");
288 // process this alignment
289 if (refStructure >= files.length)
292 "Invalid reference structure value " + refStructure);
297 * 'matched' bit j will be set for visible alignment columns j where
298 * all sequences have a residue with a mapping to the PDB structure
300 BitSet matched = new BitSet();
301 for (int m = 0; m < alignment.getWidth(); m++)
303 if (hiddenCols == null || hiddenCols.isVisible(m))
309 SuperposeData[] structures = new SuperposeData[files.length];
310 for (int f = 0; f < files.length; f++)
312 structures[f] = new SuperposeData(alignment.getWidth());
316 * Calculate the superposable alignment columns ('matched'), and the
317 * corresponding structure residue positions (structures.pdbResNo)
319 int candidateRefStructure = findSuperposableResidues(alignment,
320 matched, structures);
321 if (refStructure < 0)
324 * If no reference structure was specified, pick the first one that has
325 * a mapping in the alignment
327 refStructure = candidateRefStructure;
330 String[] selcom = new String[files.length];
331 int nmatched = matched.cardinality();
334 return (MessageManager.formatMessage("label.insufficient_residues",
339 * generate select statements to select regions to superimpose structures
342 // TODO extract method to construct selection statements
343 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
345 String chainCd = ":" + structures[pdbfnum].chain;
348 StringBuilder molsel = new StringBuilder();
351 int nextColumnMatch = matched.nextSetBit(0);
352 while (nextColumnMatch != -1)
354 int pdbResNo = structures[pdbfnum].pdbResNo[nextColumnMatch];
355 if (lpos != pdbResNo - 1)
361 molsel.append(chainCd);
368 // continuous run - and lpos >-1
371 // at the beginning, so add dash
378 nextColumnMatch = matched.nextSetBit(nextColumnMatch + 1);
381 * add final selection phrase
386 molsel.append(chainCd);
389 if (molsel.length() > 1)
391 selcom[pdbfnum] = molsel.toString();
392 selectioncom.append("((");
393 selectioncom.append(selcom[pdbfnum].substring(1,
394 selcom[pdbfnum].length() - 1));
395 selectioncom.append(" )& ");
396 selectioncom.append(pdbfnum + 1);
397 selectioncom.append(".1)");
398 if (pdbfnum < files.length - 1)
400 selectioncom.append("|");
405 selcom[pdbfnum] = null;
409 StringBuilder command = new StringBuilder(256);
410 // command.append("set spinFps 10;\n");
412 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
414 if (pdbfnum == refStructure || selcom[pdbfnum] == null
415 || selcom[refStructure] == null)
419 command.append("echo ");
420 command.append("\"Superposing (");
421 command.append(structures[pdbfnum].pdbId);
422 command.append(") against reference (");
423 command.append(structures[refStructure].pdbId);
424 command.append(")\";\ncompare " + nSeconds);
426 command.append(Integer.toString(1 + pdbfnum));
427 command.append(".1} {");
428 command.append(Integer.toString(1 + refStructure));
429 // conformation=1 excludes alternate locations for CA (JAL-1757)
431 ".1} SUBSET {(*.CA | *.P) and conformation=1} ATOMS ");
433 // for (int s = 0; s < 2; s++)
435 // command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
437 command.append(selcom[pdbfnum]);
438 command.append(selcom[refStructure]);
439 command.append(" ROTATE TRANSLATE;\n");
441 if (selectioncom.length() > 0)
443 // TODO is performing selectioncom redundant here? is done later on
444 // System.out.println("Select regions:\n" + selectioncom.toString());
445 evalStateCommand("select *; cartoons off; backbone; select ("
446 + selectioncom.toString() + "); cartoons; ");
447 // selcom.append("; ribbons; ");
448 String cmdString = command.toString();
449 // System.out.println("Superimpose command(s):\n" + cmdString);
451 evalStateCommand(cmdString);
454 if (selectioncom.length() > 0)
455 {// finally, mark all regions that were superposed.
456 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
458 selectioncom.setLength(selectioncom.length() - 1);
460 // System.out.println("Select regions:\n" + selectioncom.toString());
461 evalStateCommand("select *; cartoons off; backbone; select ("
462 + selectioncom.toString() + "); cartoons; ");
463 // evalStateCommand("select *; backbone; select "+selcom.toString()+";
464 // cartoons; center "+selcom.toString());
470 public void evalStateCommand(String command)
473 if (lastCommand == null || !lastCommand.equals(command))
475 viewer.evalStringQuiet(command + "\n");
478 lastCommand = command;
481 Thread colourby = null;
483 * Sends a set of colour commands to the structure viewer
485 * @param colourBySequenceCommands
488 protected void colourBySequence(
489 final StructureMappingcommandSet[] colourBySequenceCommands)
491 if (colourby != null)
493 colourby.interrupt();
496 colourby = new Thread(new Runnable()
501 for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands)
503 for (String cbyseq : cpdbbyseq.commands)
505 executeWhenReady(cbyseq);
520 protected StructureMappingcommandSet[] getColourBySequenceCommands(
521 String[] files, SequenceRenderer sr, AlignmentViewPanel viewPanel)
523 return JmolCommands.getColourBySequenceCommand(getSsm(), files,
524 getSequence(), sr, viewPanel);
530 protected void executeWhenReady(String command)
532 evalStateCommand(command);
535 public void createImage(String file, String type, int quality)
537 System.out.println("JMOL CREATE IMAGE");
541 public String createImage(String fileName, String type,
542 Object textOrBytes, int quality)
544 System.out.println("JMOL CREATE IMAGE");
549 public String eval(String strEval)
551 // System.out.println(strEval);
552 // "# 'eval' is implemented only for the applet.";
556 // End StructureListener
557 // //////////////////////////
560 public float[][] functionXY(String functionName, int x, int y)
566 public float[][][] functionXYZ(String functionName, int nx, int ny,
569 // TODO Auto-generated method stub
573 public Color getColour(int atomIndex, int pdbResNum, String chain,
576 if (getModelNum(pdbfile) < 0)
580 // TODO: verify atomIndex is selecting correct model.
581 // return new Color(viewer.getAtomArgb(atomIndex)); Jmol 12.2.4
582 int colour = viewer.ms.at[atomIndex].atomPropertyInt(T.color);
583 return new Color(colour);
587 * instruct the Jalview binding to update the pdbentries vector if necessary
588 * prior to matching the jmol view's contents to the list of structure files
589 * Jalview knows about.
591 public abstract void refreshPdbEntries();
593 private int getModelNum(String modelFileName)
595 String[] mfn = getStructureFiles();
600 for (int i = 0; i < mfn.length; i++)
602 if (mfn[i].equalsIgnoreCase(modelFileName))
611 * map between index of model filename returned from getPdbFile and the first
612 * index of models from this file in the viewer. Note - this is not trimmed -
613 * use getPdbFile to get number of unique models.
615 private int _modelFileNameMap[];
617 // ////////////////////////////////
618 // /StructureListener
620 public synchronized String[] getPdbFilex()
624 return new String[0];
626 if (modelFileNames == null)
628 List<String> mset = new ArrayList<>();
629 _modelFileNameMap = new int[viewer.ms.mc];
630 String m = viewer.ms.getModelFileName(0);
636 filePath = new File(m).getAbsolutePath();
637 } catch (AccessControlException x)
639 // usually not allowed to do this in applet
641 "jmolBinding: Using local file string from Jmol: " + m);
643 if (filePath.indexOf("/file:") != -1)
645 // applet path with docroot - discard as format won't match pdbfile
649 _modelFileNameMap[0] = 0; // filename index for first model is always 0.
652 for (int i = 1; i < viewer.ms.mc; i++)
654 m = viewer.ms.getModelFileName(i);
660 filePath = new File(m).getAbsolutePath();
661 } catch (AccessControlException x)
663 // usually not allowed to do this in applet, so keep raw handle
664 // System.err.println("jmolBinding: Using local file string from
670 * add this model unless it is read from a structure file we have
671 * already seen (example: 2MJW is an NMR structure with 10 models)
673 if (!mset.contains(filePath))
676 _modelFileNameMap[j] = i; // record the model index for the filename
680 modelFileNames = mset.toArray(new String[mset.size()]);
682 return modelFileNames;
686 public synchronized String[] getStructureFiles()
688 List<String> mset = new ArrayList<>();
691 return new String[0];
694 if (modelFileNames == null)
696 int modelCount = viewer.ms.mc;
697 String filePath = null;
698 for (int i = 0; i < modelCount; ++i)
700 filePath = viewer.ms.getModelFileName(i);
701 if (!mset.contains(filePath))
706 modelFileNames = mset.toArray(new String[mset.size()]);
709 return modelFileNames;
713 * map from string to applet
716 public Map<String, Object> getRegistryInfo()
718 // TODO Auto-generated method stub
722 // ///////////////////////////////
723 // JmolStatusListener
725 public void handlePopupMenu(int x, int y)
727 // jmolpopup.show(x, y);
728 // jmolpopup.jpiShow(x, y);
732 * Highlight zero, one or more atoms on the structure
735 public void highlightAtoms(List<AtomSpec> atoms)
739 if (resetLastRes.length() > 0)
741 viewer.evalStringQuiet(resetLastRes.toString());
742 resetLastRes.setLength(0);
744 for (AtomSpec atom : atoms)
746 highlightAtom(atom.getAtomIndex(), atom.getPdbResNum(),
747 atom.getChain(), atom.getPdbFile());
753 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
756 if (modelFileNames == null)
761 // look up file model number for this pdbfile
763 // may need to adjust for URLencoding here - we don't worry about that yet.
764 while (mdlNum < modelFileNames.length
765 && !pdbfile.equals(modelFileNames[mdlNum]))
769 if (mdlNum == modelFileNames.length)
776 StringBuilder cmd = new StringBuilder(64);
777 cmd.append("select " + pdbResNum); // +modelNum
779 resetLastRes.append("select " + pdbResNum); // +modelNum
782 resetLastRes.append(":");
783 if (!chain.equals(" "))
786 resetLastRes.append(chain);
789 cmd.append(" /" + (mdlNum + 1));
790 resetLastRes.append("/" + (mdlNum + 1));
792 cmd.append(";wireframe 100;" + cmd.toString() + " and not hetero;");
794 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
795 + " and not hetero; spacefill 0;");
797 cmd.append("spacefill 200;select none");
799 viewer.evalStringQuiet(cmd.toString());
804 boolean debug = true;
806 private void jmolHistory(boolean enable)
808 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
811 public void loadInline(String string)
815 // viewer.loadInline(strModel, isAppend);
817 // construct fake fullPathName and fileName so we can identify the file
819 // Then, construct pass a reader for the string to Jmol.
820 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
821 // fileName, null, reader, false, null, null, 0);
822 viewer.openStringInline(string);
825 public void mouseOverStructure(int atomIndex, String strInfo)
828 int alocsep = strInfo.indexOf("^");
829 int mdlSep = strInfo.indexOf("/");
830 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
832 if (chainSeparator == -1)
834 chainSeparator = strInfo.indexOf(".");
835 if (mdlSep > -1 && mdlSep < chainSeparator)
837 chainSeparator1 = chainSeparator;
838 chainSeparator = mdlSep;
841 // handle insertion codes
844 pdbResNum = Integer.parseInt(
845 strInfo.substring(strInfo.indexOf("]") + 1, alocsep));
850 pdbResNum = Integer.parseInt(
851 strInfo.substring(strInfo.indexOf("]") + 1, chainSeparator));
855 if (strInfo.indexOf(":") > -1)
857 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
858 strInfo.indexOf("."));
865 String pdbfilename = modelFileNames[frameNo]; // default is first or current
869 if (chainSeparator1 == -1)
871 chainSeparator1 = strInfo.indexOf(".", mdlSep);
873 String mdlId = (chainSeparator1 > -1)
874 ? strInfo.substring(mdlSep + 1, chainSeparator1)
875 : strInfo.substring(mdlSep + 1);
878 // recover PDB filename for the model hovered over.
879 int mnumber = Integer.valueOf(mdlId).intValue() - 1;
880 if (_modelFileNameMap != null)
882 int _mp = _modelFileNameMap.length - 1;
884 while (mnumber < _modelFileNameMap[_mp])
888 pdbfilename = modelFileNames[_mp];
892 if (mnumber >= 0 && mnumber < modelFileNames.length)
894 pdbfilename = modelFileNames[mnumber];
897 if (pdbfilename == null)
899 pdbfilename = new File(viewer.ms.getModelFileName(mnumber))
903 } catch (Exception e)
908 if (lastMessage == null || !lastMessage.equals(strInfo))
910 getSsm().mouseOverStructure(pdbResNum, chainId, pdbfilename);
913 lastMessage = strInfo;
916 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
920 System.err.println("Ignoring additional hover info: " + data
921 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
923 mouseOverStructure(atomIndex, strInfo);
927 * { if (history != null && strStatus != null &&
928 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
932 public void notifyAtomPicked(int atomIndex, String strInfo,
936 * this implements the toggle label behaviour copied from the original
937 * structure viewer, MCView
941 System.err.println("Ignoring additional pick data string " + strData);
943 int chainSeparator = strInfo.indexOf(":");
945 if (chainSeparator == -1)
947 chainSeparator = strInfo.indexOf(".");
950 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
952 String mdlString = "";
953 if ((p = strInfo.indexOf(":")) > -1)
955 picked += strInfo.substring(p, strInfo.indexOf("."));
958 if ((p = strInfo.indexOf("/")) > -1)
960 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
962 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
966 if (!atomsPicked.contains(picked))
968 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
969 atomsPicked.addElement(picked);
973 viewer.evalString("select " + picked + ";label off");
974 atomsPicked.removeElement(picked);
977 // TODO: in application this happens
979 // if (scriptWindow != null)
981 // scriptWindow.sendConsoleMessage(strInfo);
982 // scriptWindow.sendConsoleMessage("\n");
988 public void notifyCallback(CBK type, Object[] data)
995 notifyFileLoaded((String) data[1], (String) data[2],
996 (String) data[3], (String) data[4],
997 ((Integer) data[5]).intValue());
1001 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
1003 // also highlight in alignment
1004 // deliberate fall through
1006 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1010 notifyScriptTermination((String) data[2],
1011 ((Integer) data[3]).intValue());
1014 sendConsoleEcho((String) data[1]);
1018 (data == null) ? ((String) null) : (String) data[1]);
1021 // System.err.println("Ignoring error callback.");
1032 "Unhandled callback " + type + " " + data[1].toString());
1035 } catch (Exception e)
1037 System.err.println("Squashed Jmol callback handler error:");
1038 e.printStackTrace();
1043 public boolean notifyEnabled(CBK callbackPick)
1045 switch (callbackPick)
1061 // incremented every time a load notification is successfully handled -
1062 // lightweight mechanism for other threads to detect when they can start
1063 // referrring to new structures.
1064 private long loadNotifiesHandled = 0;
1066 public long getLoadNotifiesHandled()
1068 return loadNotifiesHandled;
1071 public void notifyFileLoaded(String fullPathName, String fileName2,
1072 String modelName, String errorMsg, int modelParts)
1074 if (errorMsg != null)
1076 fileLoadingError = errorMsg;
1080 // TODO: deal sensibly with models loaded inLine:
1081 // modelName will be null, as will fullPathName.
1083 // the rest of this routine ignores the arguments, and simply interrogates
1084 // the Jmol view to find out what structures it contains, and adds them to
1085 // the structure selection manager.
1086 fileLoadingError = null;
1087 String[] oldmodels = modelFileNames;
1088 modelFileNames = null;
1089 chainNames = new ArrayList<>();
1090 chainFile = new Hashtable<>();
1091 boolean notifyLoaded = false;
1092 String[] modelfilenames = getStructureFiles();
1093 // first check if we've lost any structures
1094 if (oldmodels != null && oldmodels.length > 0)
1097 for (int i = 0; i < oldmodels.length; i++)
1099 for (int n = 0; n < modelfilenames.length; n++)
1101 if (modelfilenames[n] == oldmodels[i])
1103 oldmodels[i] = null;
1107 if (oldmodels[i] != null)
1114 String[] oldmfn = new String[oldm];
1116 for (int i = 0; i < oldmodels.length; i++)
1118 if (oldmodels[i] != null)
1120 oldmfn[oldm++] = oldmodels[i];
1123 // deregister the Jmol instance for these structures - we'll add
1124 // ourselves again at the end for the current structure set.
1125 getSsm().removeStructureViewerListener(this, oldmfn);
1128 refreshPdbEntries();
1129 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1131 String fileName = modelfilenames[modelnum];
1132 boolean foundEntry = false;
1133 StructureFile pdb = null;
1134 String pdbfile = null;
1135 // model was probably loaded inline - so check the pdb file hashcode
1138 // calculate essential attributes for the pdb data imported inline.
1139 // prolly need to resolve modelnumber properly - for now just use our
1141 pdbfile = viewer.getData(
1142 "" + (1 + _modelFileNameMap[modelnum]) + ".0", "PDB");
1144 // search pdbentries and sequences to find correct pdbentry for this
1146 for (int pe = 0; pe < getPdbCount(); pe++)
1148 boolean matches = false;
1149 addSequence(pe, getSequence()[pe]);
1150 if (fileName == null)
1153 // see JAL-623 - need method of matching pasted data up
1155 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1156 pdbfile, DataSourceType.PASTE,
1157 getIProgressIndicator());
1158 getPdbEntry(modelnum).setFile("INLINE" + pdb.getId());
1165 File fl = new File(getPdbEntry(pe).getFile());
1166 matches = fl.equals(new File(fileName));
1170 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1173 // to be tested. See mantis bug
1174 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1175 DataSourceType protocol = DataSourceType.URL;
1180 protocol = DataSourceType.FILE;
1182 } catch (Exception e)
1187 // Explicitly map to the filename used by Jmol ;
1188 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1189 fileName, protocol, getIProgressIndicator());
1190 // pdbentry[pe].getFile(), protocol);
1196 // add an entry for every chain in the model
1197 for (int i = 0; i < pdb.getChains().size(); i++)
1199 String chid = new String(
1200 pdb.getId() + ":" + pdb.getChains().elementAt(i).id);
1201 chainFile.put(chid, fileName);
1202 chainNames.add(chid);
1204 notifyLoaded = true;
1208 if (!foundEntry && associateNewStructs)
1210 // this is a foreign pdb file that jalview doesn't know about - add
1211 // it to the dataset and try to find a home - either on a matching
1212 // sequence or as a new sequence.
1213 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1215 // parse pdb file into a chain, etc.
1216 // locate best match for pdb in associated views and add mapping to
1218 // if properly registered then
1219 notifyLoaded = true;
1224 // so finally, update the jmol bits and pieces
1225 // if (jmolpopup != null)
1227 // // potential for deadlock here:
1228 // // jmolpopup.updateComputedMenus();
1230 if (!isLoadingFromArchive())
1232 viewer.evalStringQuiet(
1233 "model *; select backbone;restrict;cartoon;wireframe off;spacefill off");
1235 // register ourselves as a listener and notify the gui that it needs to
1237 getSsm().addStructureViewerListener(this);
1240 FeatureRenderer fr = getFeatureRenderer(null);
1246 loadNotifiesHandled++;
1248 setLoadingFromArchive(false);
1252 public List<String> getChainNames()
1257 protected IProgressIndicator getIProgressIndicator()
1262 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1264 notifyAtomPicked(iatom, strMeasure, null);
1267 public abstract void notifyScriptTermination(String strStatus,
1271 * display a message echoed from the jmol viewer
1275 public abstract void sendConsoleEcho(String strEcho); /*
1276 * { showConsole(true);
1278 * history.append("\n" +
1282 // /End JmolStatusListener
1283 // /////////////////////////////
1287 * status message - usually the response received after a script
1290 public abstract void sendConsoleMessage(String strStatus);
1293 public void setCallbackFunction(String callbackType,
1294 String callbackFunction)
1296 System.err.println("Ignoring set-callback request to associate "
1297 + callbackType + " with function " + callbackFunction);
1302 public void setJalviewColourScheme(ColourSchemeI cs)
1304 colourBySequence = false;
1312 StringBuilder command = new StringBuilder(128);
1313 command.append("select *;color white;");
1314 List<String> residueSet = ResidueProperties.getResidues(isNucleotide(),
1316 for (String resName : residueSet)
1318 char res = resName.length() == 3
1319 ? ResidueProperties.getSingleCharacterCode(resName)
1320 : resName.charAt(0);
1321 Color col = cs.findColour(res, 0, null, null, 0f);
1322 command.append("select " + resName + ";color[" + col.getRed() + ","
1323 + col.getGreen() + "," + col.getBlue() + "];");
1326 evalStateCommand(command.toString());
1330 public void showHelp()
1332 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1336 * open the URL somehow
1340 public abstract void showUrl(String url, String target);
1343 * called when the binding thinks the UI needs to be refreshed after a Jmol
1344 * state change. this could be because structures were loaded, or because an
1345 * error has occured.
1347 public abstract void refreshGUI();
1350 * called to show or hide the associated console window container.
1354 public abstract void showConsole(boolean show);
1357 * @param renderPanel
1359 * - when true will initialise jmol's file IO system (should be false
1360 * in applet context)
1362 * @param documentBase
1364 * @param commandOptions
1366 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1367 String htmlName, URL documentBase, URL codeBase,
1368 String commandOptions)
1370 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1371 codeBase, commandOptions, null, null);
1376 * @param renderPanel
1378 * - when true will initialise jmol's file IO system (should be false
1379 * in applet context)
1381 * @param documentBase
1383 * @param commandOptions
1384 * @param consolePanel
1385 * - panel to contain Jmol console
1386 * @param buttonsToShow
1387 * - buttons to show on the console, in ordr
1389 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1390 String htmlName, URL documentBase, URL codeBase,
1391 String commandOptions, final Container consolePanel,
1392 String buttonsToShow)
1394 if (commandOptions == null)
1396 commandOptions = "";
1398 viewer = (Viewer) JmolViewer.allocateViewer(renderPanel,
1399 (jmolfileio ? new SmarterJmolAdapter() : null),
1400 htmlName + ((Object) this).toString(), documentBase, codeBase,
1401 commandOptions, this);
1403 viewer.setJmolStatusListener(this); // extends JmolCallbackListener
1405 console = createJmolConsole(consolePanel, buttonsToShow);
1406 if (consolePanel != null)
1408 consolePanel.addComponentListener(this);
1414 protected abstract JmolAppConsoleInterface createJmolConsole(
1415 Container consolePanel, String buttonsToShow);
1417 protected org.jmol.api.JmolAppConsoleInterface console = null;
1420 public void setBackgroundColour(java.awt.Color col)
1423 viewer.evalStringQuiet("background [" + col.getRed() + ","
1424 + col.getGreen() + "," + col.getBlue() + "];");
1429 public int[] resizeInnerPanel(String data)
1431 // Jalview doesn't honour resize panel requests
1438 protected void closeConsole()
1440 if (console != null)
1444 console.setVisible(false);
1447 } catch (Exception x)
1456 * ComponentListener method
1459 public void componentMoved(ComponentEvent e)
1464 * ComponentListener method
1467 public void componentResized(ComponentEvent e)
1472 * ComponentListener method
1475 public void componentShown(ComponentEvent e)
1481 * ComponentListener method
1484 public void componentHidden(ComponentEvent e)