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.ColumnSelection;
28 import jalview.datamodel.PDBEntry;
29 import jalview.datamodel.SequenceI;
30 import jalview.io.AppletFormatAdapter;
31 import jalview.io.StructureFile;
32 import jalview.schemes.ColourSchemeI;
33 import jalview.schemes.ResidueProperties;
34 import jalview.structure.AtomSpec;
35 import jalview.structure.StructureMappingcommandSet;
36 import jalview.structure.StructureSelectionManager;
37 import jalview.structures.models.AAStructureBindingModel;
39 import java.awt.Color;
40 import java.awt.Container;
41 import java.awt.event.ComponentEvent;
42 import java.awt.event.ComponentListener;
45 import java.security.AccessControlException;
46 import java.util.ArrayList;
47 import java.util.Hashtable;
48 import java.util.List;
50 import java.util.Vector;
52 import javajs.awt.Dimension;
54 import org.jmol.adapter.smarter.SmarterJmolAdapter;
55 import org.jmol.api.JmolAppConsoleInterface;
56 import org.jmol.api.JmolSelectionListener;
57 import org.jmol.api.JmolStatusListener;
58 import org.jmol.api.JmolViewer;
59 import org.jmol.c.CBK;
60 import org.jmol.script.T;
61 import org.jmol.viewer.Viewer;
63 public abstract class JalviewJmolBinding extends AAStructureBindingModel
64 implements JmolStatusListener, JmolSelectionListener,
67 boolean allChainsSelected = false;
70 * when true, try to search the associated datamodel for sequences that are
71 * associated with any unknown structures in the Jmol view.
73 private boolean associateNewStructs = false;
75 Vector<String> atomsPicked = new Vector<String>();
77 public Vector<String> chainNames;
79 Hashtable<String, String> chainFile;
81 public String fileLoadingError;
84 * the default or current model displayed if the model cannot be identified
85 * from the selection message
89 // protected JmolGenericPopup jmolpopup; // not used - remove?
97 StringBuffer resetLastRes = new StringBuffer();
101 public JalviewJmolBinding(StructureSelectionManager ssm,
102 PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
105 super(ssm, pdbentry, sequenceIs, chains, protocol);
107 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
108 * "jalviewJmol", ap.av.applet .getDocumentBase(),
109 * ap.av.applet.getCodeBase(), "", this);
111 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
115 public JalviewJmolBinding(StructureSelectionManager ssm,
116 SequenceI[][] seqs, Viewer theViewer)
121 viewer.setJmolStatusListener(this);
122 viewer.addSelectionListener(this);
126 * construct a title string for the viewer window based on the data jalview
131 public String getViewerTitle()
133 return getViewerTitle("Jmol", true);
137 * prepare the view for a given set of models/chains. chainList contains
138 * strings of the form 'pdbfilename:Chaincode'
141 * list of chains to make visible
143 public void centerViewer(Vector<String> chainList)
145 StringBuilder cmd = new StringBuilder(128);
147 for (String lbl : chainList)
153 mlength = lbl.indexOf(":", p);
154 } while (p < mlength && mlength < (lbl.length() - 2));
155 // TODO: lookup each pdb id and recover proper model number for it.
156 cmd.append(":" + lbl.substring(mlength + 1) + " /"
157 + (1 + getModelNum(chainFile.get(lbl))) + " or ");
159 if (cmd.length() > 0)
161 cmd.setLength(cmd.length() - 4);
163 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
166 public void closeViewer()
168 // remove listeners for all structures in viewer
169 getSsm().removeStructureViewerListener(this, this.getPdbFile());
173 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");
185 public void colourByCharge()
187 colourBySequence = false;
188 evalStateCommand("select *;color white;select ASP,GLU;color red;"
189 + "select LYS,ARG;color blue;select CYS;color yellow");
193 * superpose the structures associated with sequences in the alignment
194 * according to their corresponding positions.
196 public void superposeStructures(AlignmentI alignment)
198 superposeStructures(alignment, -1, null);
202 * superpose the structures associated with sequences in the alignment
203 * according to their corresponding positions. ded)
205 * @param refStructure
206 * - select which pdb file to use as reference (default is -1 - the
207 * first structure in the alignment)
209 public void superposeStructures(AlignmentI alignment, int refStructure)
211 superposeStructures(alignment, refStructure, null);
215 * superpose the structures associated with sequences in the alignment
216 * according to their corresponding positions. ded)
218 * @param refStructure
219 * - select which pdb file to use as reference (default is -1 - the
220 * first structure in the alignment)
224 public void superposeStructures(AlignmentI alignment, int refStructure,
225 ColumnSelection hiddenCols)
227 superposeStructures(new AlignmentI[] { alignment },
228 new int[] { refStructure },
229 new ColumnSelection[] { hiddenCols });
233 * Construct and send a command to align structures against a reference
234 * structure, based on one or more sequence alignments
237 * an array of alignments to process
238 * @param _refStructure
239 * an array of corresponding reference structures (index into pdb
240 * file array); if a negative value is passed, the first PDB file
241 * mapped to an alignment sequence is used as the reference for
244 * an array of corresponding hidden columns for each alignment
246 public void superposeStructures(AlignmentI[] _alignment,
247 int[] _refStructure, ColumnSelection[] _hiddenCols)
249 while (viewer.isScriptExecuting())
254 } catch (InterruptedException i)
260 * get the distinct structure files modelled
261 * (a file with multiple chains may map to multiple sequences)
263 String[] files = getPdbFile();
264 if (!waitForFileLoad(files))
269 StringBuilder selectioncom = new StringBuilder(256);
270 // In principle - nSeconds specifies the speed of animation for each
271 // superposition - but is seems to behave weirdly, so we don't specify it.
272 String nSeconds = " ";
273 if (files.length > 10)
275 nSeconds = " 0.005 ";
279 nSeconds = " " + (2.0 / files.length) + " ";
280 // if (nSeconds).substring(0,5)+" ";
282 // see JAL-1345 - should really automatically turn off the animation for
283 // large numbers of structures, but Jmol doesn't seem to allow that.
285 // union of all aligned positions are collected together.
286 for (int a = 0; a < _alignment.length; a++)
288 int refStructure = _refStructure[a];
289 AlignmentI alignment = _alignment[a];
290 ColumnSelection hiddenCols = _hiddenCols[a];
292 && selectioncom.length() > 0
293 && !selectioncom.substring(selectioncom.length() - 1).equals(
296 selectioncom.append("|");
298 // process this alignment
299 if (refStructure >= files.length)
301 System.err.println("Invalid reference structure value "
307 * 'matched' array will hold 'true' for visible alignment columns where
308 * all sequences have a residue with a mapping to the PDB structure
310 // TODO could use a BitSet for matched
311 boolean matched[] = new boolean[alignment.getWidth()];
312 for (int m = 0; m < matched.length; m++)
314 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
317 SuperposeData[] structures = new SuperposeData[files.length];
318 for (int f = 0; f < files.length; f++)
320 structures[f] = new SuperposeData(alignment.getWidth());
324 * Calculate the superposable alignment columns ('matched'), and the
325 * corresponding structure residue positions (structures.pdbResNo)
327 int candidateRefStructure = findSuperposableResidues(alignment,
328 matched, structures);
329 if (refStructure < 0)
332 * If no reference structure was specified, pick the first one that has
333 * a mapping in the alignment
335 refStructure = candidateRefStructure;
338 String[] selcom = new String[files.length];
340 for (boolean b : matched)
349 // TODO: bail out here because superposition illdefined?
353 * generate select statements to select regions to superimpose structures
356 // TODO extract method to construct selection statements
357 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
359 String chainCd = ":" + structures[pdbfnum].chain;
362 StringBuilder molsel = new StringBuilder();
364 for (int r = 0; r < matched.length; r++)
368 int pdbResNo = structures[pdbfnum].pdbResNo[r];
369 if (lpos != pdbResNo - 1)
375 molsel.append(chainCd);
382 // continuous run - and lpos >-1
385 // at the beginning, so add dash
395 * add final selection phrase
400 molsel.append(chainCd);
403 if (molsel.length() > 1)
405 selcom[pdbfnum] = molsel.toString();
406 selectioncom.append("((");
407 selectioncom.append(selcom[pdbfnum].substring(1,
408 selcom[pdbfnum].length() - 1));
409 selectioncom.append(" )& ");
410 selectioncom.append(pdbfnum + 1);
411 selectioncom.append(".1)");
412 if (pdbfnum < files.length - 1)
414 selectioncom.append("|");
419 selcom[pdbfnum] = null;
423 StringBuilder command = new StringBuilder(256);
424 // command.append("set spinFps 10;\n");
426 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
428 if (pdbfnum == refStructure || selcom[pdbfnum] == null
429 || selcom[refStructure] == null)
433 command.append("echo ");
434 command.append("\"Superposing (");
435 command.append(structures[pdbfnum].pdbId);
436 command.append(") against reference (");
437 command.append(structures[refStructure].pdbId);
438 command.append(")\";\ncompare " + nSeconds);
440 command.append(Integer.toString(1 + pdbfnum));
441 command.append(".1} {");
442 command.append(Integer.toString(1 + refStructure));
443 // conformation=1 excludes alternate locations for CA (JAL-1757)
444 command.append(".1} SUBSET {(*.CA | *.P) and conformation=1} ATOMS ");
446 // for (int s = 0; s < 2; s++)
448 // command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
450 command.append(selcom[pdbfnum]);
451 command.append(selcom[refStructure]);
452 command.append(" ROTATE TRANSLATE;\n");
454 if (selectioncom.length() > 0)
456 // TODO is performing selectioncom redundant here? is done later on
457 // System.out.println("Select regions:\n" + selectioncom.toString());
458 evalStateCommand("select *; cartoons off; backbone; select ("
459 + selectioncom.toString() + "); cartoons; ");
460 // selcom.append("; ribbons; ");
461 String cmdString = command.toString();
462 // System.out.println("Superimpose command(s):\n" + cmdString);
464 evalStateCommand(cmdString);
467 if (selectioncom.length() > 0)
468 {// finally, mark all regions that were superposed.
469 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
471 selectioncom.setLength(selectioncom.length() - 1);
473 // System.out.println("Select regions:\n" + selectioncom.toString());
474 evalStateCommand("select *; cartoons off; backbone; select ("
475 + selectioncom.toString() + "); cartoons; ");
476 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
480 public void evalStateCommand(String command)
483 if (lastCommand == null || !lastCommand.equals(command))
485 viewer.evalStringQuiet(command + "\n");
488 lastCommand = command;
492 * colour any structures associated with sequences in the given alignment
493 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
494 * if colourBySequence is enabled.
496 public void colourBySequence(AlignmentViewPanel alignmentv)
498 boolean showFeatures = alignmentv.getAlignViewport()
499 .isShowSequenceFeatures();
500 if (!colourBySequence || !isLoadingFinished())
504 if (getSsm() == null)
508 String[] files = getPdbFile();
510 SequenceRenderer sr = getSequenceRenderer(alignmentv);
512 FeatureRenderer fr = null;
515 fr = getFeatureRenderer(alignmentv);
517 AlignmentI alignment = alignmentv.getAlignment();
519 for (jalview.structure.StructureMappingcommandSet cpdbbyseq : getColourBySequenceCommands(
520 files, sr, fr, alignment))
522 for (String cbyseq : cpdbbyseq.commands)
524 executeWhenReady(cbyseq);
536 protected StructureMappingcommandSet[] getColourBySequenceCommands(
537 String[] files, SequenceRenderer sr, FeatureRenderer fr,
538 AlignmentI alignment)
540 return JmolCommands.getColourBySequenceCommand(getSsm(), files,
541 getSequence(), sr, fr, alignment);
547 protected void executeWhenReady(String command)
549 evalStateCommand(command);
552 public void createImage(String file, String type, int quality)
554 System.out.println("JMOL CREATE IMAGE");
558 public String createImage(String fileName, String type,
559 Object textOrBytes, int quality)
561 System.out.println("JMOL CREATE IMAGE");
566 public String eval(String strEval)
568 // System.out.println(strEval);
569 // "# 'eval' is implemented only for the applet.";
573 // End StructureListener
574 // //////////////////////////
577 public float[][] functionXY(String functionName, int x, int y)
583 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
585 // TODO Auto-generated method stub
589 public Color getColour(int atomIndex, int pdbResNum, String chain,
592 if (getModelNum(pdbfile) < 0)
596 // TODO: verify atomIndex is selecting correct model.
597 // return new Color(viewer.getAtomArgb(atomIndex)); Jmol 12.2.4
598 int colour = viewer.ms.at[atomIndex].atomPropertyInt(T.color);
599 return new Color(colour);
603 * returns the current featureRenderer that should be used to colour the
610 public abstract FeatureRenderer getFeatureRenderer(
611 AlignmentViewPanel alignment);
614 * instruct the Jalview binding to update the pdbentries vector if necessary
615 * prior to matching the jmol view's contents to the list of structure files
616 * Jalview knows about.
618 public abstract void refreshPdbEntries();
620 private int getModelNum(String modelFileName)
622 String[] mfn = getPdbFile();
627 for (int i = 0; i < mfn.length; i++)
629 if (mfn[i].equalsIgnoreCase(modelFileName))
638 * map between index of model filename returned from getPdbFile and the first
639 * index of models from this file in the viewer. Note - this is not trimmed -
640 * use getPdbFile to get number of unique models.
642 private int _modelFileNameMap[];
644 // ////////////////////////////////
645 // /StructureListener
647 public synchronized String[] getPdbFile()
651 return new String[0];
653 if (modelFileNames == null)
655 List<String> mset = new ArrayList<String>();
656 _modelFileNameMap = new int[viewer.ms.mc];
657 String m = viewer.ms.getModelFileName(0);
663 filePath = new File(m).getAbsolutePath();
664 } catch (AccessControlException x)
666 // usually not allowed to do this in applet
668 .println("jmolBinding: Using local file string from Jmol: "
671 if (filePath.indexOf("/file:") != -1)
673 // applet path with docroot - discard as format won't match pdbfile
677 _modelFileNameMap[0] = 0; // filename index for first model is always 0.
680 for (int i = 1; i < viewer.ms.mc; i++)
682 m = viewer.ms.getModelFileName(i);
688 filePath = new File(m).getAbsolutePath();
689 } catch (AccessControlException x)
691 // usually not allowed to do this in applet, so keep raw handle
692 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
697 * add this model unless it is read from a structure file we have
698 * already seen (example: 2MJW is an NMR structure with 10 models)
700 if (!mset.contains(filePath))
703 _modelFileNameMap[j] = i; // record the model index for the filename
707 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
723 * returns the current sequenceRenderer that should be used to colour the
730 public abstract SequenceRenderer getSequenceRenderer(
731 AlignmentViewPanel alignment);
733 // ///////////////////////////////
734 // JmolStatusListener
736 public void handlePopupMenu(int x, int y)
738 // jmolpopup.show(x, y);
739 // jmolpopup.jpiShow(x, y);
743 * Highlight zero, one or more atoms on the structure
746 public void highlightAtoms(List<AtomSpec> atoms)
750 if (resetLastRes.length() > 0)
752 viewer.evalStringQuiet(resetLastRes.toString());
753 resetLastRes.setLength(0);
755 for (AtomSpec atom : atoms)
757 highlightAtom(atom.getAtomIndex(), atom.getPdbResNum(),
758 atom.getChain(), atom.getPdbFile());
764 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
767 if (modelFileNames == null)
772 // look up file model number for this pdbfile
774 // may need to adjust for URLencoding here - we don't worry about that yet.
775 while (mdlNum < modelFileNames.length
776 && !pdbfile.equals(modelFileNames[mdlNum]))
780 if (mdlNum == modelFileNames.length)
787 StringBuilder cmd = new StringBuilder(64);
788 cmd.append("select " + pdbResNum); // +modelNum
790 resetLastRes.append("select " + pdbResNum); // +modelNum
793 resetLastRes.append(":");
794 if (!chain.equals(" "))
797 resetLastRes.append(chain);
800 cmd.append(" /" + (mdlNum + 1));
801 resetLastRes.append("/" + (mdlNum + 1));
803 cmd.append(";wireframe 100;" + cmd.toString() + " and not hetero;");
805 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
806 + " and not hetero; spacefill 0;");
808 cmd.append("spacefill 200;select none");
810 viewer.evalStringQuiet(cmd.toString());
815 boolean debug = true;
817 private void jmolHistory(boolean enable)
819 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
822 public void loadInline(String string)
826 // viewer.loadInline(strModel, isAppend);
828 // construct fake fullPathName and fileName so we can identify the file
830 // Then, construct pass a reader for the string to Jmol.
831 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
832 // fileName, null, reader, false, null, null, 0);
833 viewer.openStringInline(string);
836 public void mouseOverStructure(int atomIndex, String strInfo)
839 int alocsep = strInfo.indexOf("^");
840 int mdlSep = strInfo.indexOf("/");
841 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
843 if (chainSeparator == -1)
845 chainSeparator = strInfo.indexOf(".");
846 if (mdlSep > -1 && mdlSep < chainSeparator)
848 chainSeparator1 = chainSeparator;
849 chainSeparator = mdlSep;
852 // handle insertion codes
855 pdbResNum = Integer.parseInt(strInfo.substring(
856 strInfo.indexOf("]") + 1, alocsep));
861 pdbResNum = Integer.parseInt(strInfo.substring(
862 strInfo.indexOf("]") + 1, chainSeparator));
866 if (strInfo.indexOf(":") > -1)
868 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
869 strInfo.indexOf("."));
876 String pdbfilename = modelFileNames[frameNo]; // default is first or current
880 if (chainSeparator1 == -1)
882 chainSeparator1 = strInfo.indexOf(".", mdlSep);
884 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
885 chainSeparator1) : strInfo.substring(mdlSep + 1);
888 // recover PDB filename for the model hovered over.
889 int _mp = _modelFileNameMap.length - 1, mnumber = new Integer(mdlId)
891 while (mnumber < _modelFileNameMap[_mp])
895 pdbfilename = modelFileNames[_mp];
896 if (pdbfilename == null)
898 pdbfilename = new File(viewer.ms.getModelFileName(mnumber))
902 } catch (Exception e)
907 if (lastMessage == null || !lastMessage.equals(strInfo))
909 getSsm().mouseOverStructure(pdbResNum, chainId, pdbfilename);
912 lastMessage = strInfo;
915 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
919 System.err.println("Ignoring additional hover info: " + data
920 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
922 mouseOverStructure(atomIndex, strInfo);
926 * { if (history != null && strStatus != null &&
927 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
931 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
934 * this implements the toggle label behaviour copied from the original
935 * structure viewer, MCView
939 System.err.println("Ignoring additional pick data string " + strData);
941 int chainSeparator = strInfo.indexOf(":");
943 if (chainSeparator == -1)
945 chainSeparator = strInfo.indexOf(".");
948 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
950 String mdlString = "";
951 if ((p = strInfo.indexOf(":")) > -1)
953 picked += strInfo.substring(p, strInfo.indexOf("."));
956 if ((p = strInfo.indexOf("/")) > -1)
958 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
960 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
964 if (!atomsPicked.contains(picked))
966 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
967 atomsPicked.addElement(picked);
971 viewer.evalString("select " + picked + ";label off");
972 atomsPicked.removeElement(picked);
975 // TODO: in application this happens
977 // if (scriptWindow != null)
979 // scriptWindow.sendConsoleMessage(strInfo);
980 // scriptWindow.sendConsoleMessage("\n");
986 public void notifyCallback(CBK type, Object[] data)
993 notifyFileLoaded((String) data[1], (String) data[2],
994 (String) data[3], (String) data[4],
995 ((Integer) data[5]).intValue());
999 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
1001 // also highlight in alignment
1003 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1007 notifyScriptTermination((String) data[2],
1008 ((Integer) data[3]).intValue());
1011 sendConsoleEcho((String) data[1]);
1014 sendConsoleMessage((data == null) ? ((String) null)
1015 : (String) data[1]);
1018 // System.err.println("Ignoring error callback.");
1028 System.err.println("Unhandled callback " + type + " "
1029 + data[1].toString());
1032 } catch (Exception e)
1034 System.err.println("Squashed Jmol callback handler error:");
1035 e.printStackTrace();
1040 public boolean notifyEnabled(CBK callbackPick)
1042 switch (callbackPick)
1058 // incremented every time a load notification is successfully handled -
1059 // lightweight mechanism for other threads to detect when they can start
1060 // referrring to new structures.
1061 private long loadNotifiesHandled = 0;
1063 public long getLoadNotifiesHandled()
1065 return loadNotifiesHandled;
1068 public void notifyFileLoaded(String fullPathName, String fileName2,
1069 String modelName, String errorMsg, int modelParts)
1071 if (errorMsg != null)
1073 fileLoadingError = errorMsg;
1077 // TODO: deal sensibly with models loaded inLine:
1078 // modelName will be null, as will fullPathName.
1080 // the rest of this routine ignores the arguments, and simply interrogates
1081 // the Jmol view to find out what structures it contains, and adds them to
1082 // the structure selection manager.
1083 fileLoadingError = null;
1084 String[] oldmodels = modelFileNames;
1085 modelFileNames = null;
1086 chainNames = new Vector<String>();
1087 chainFile = new Hashtable<String, String>();
1088 boolean notifyLoaded = false;
1089 String[] modelfilenames = getPdbFile();
1090 // first check if we've lost any structures
1091 if (oldmodels != null && oldmodels.length > 0)
1094 for (int i = 0; i < oldmodels.length; i++)
1096 for (int n = 0; n < modelfilenames.length; n++)
1098 if (modelfilenames[n] == oldmodels[i])
1100 oldmodels[i] = null;
1104 if (oldmodels[i] != null)
1111 String[] oldmfn = new String[oldm];
1113 for (int i = 0; i < oldmodels.length; i++)
1115 if (oldmodels[i] != null)
1117 oldmfn[oldm++] = oldmodels[i];
1120 // deregister the Jmol instance for these structures - we'll add
1121 // ourselves again at the end for the current structure set.
1122 getSsm().removeStructureViewerListener(this, oldmfn);
1125 refreshPdbEntries();
1126 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1128 String fileName = modelfilenames[modelnum];
1129 boolean foundEntry = false;
1130 StructureFile pdb = null;
1131 String pdbfile = null;
1132 // model was probably loaded inline - so check the pdb file hashcode
1135 // calculate essential attributes for the pdb data imported inline.
1136 // prolly need to resolve modelnumber properly - for now just use our
1138 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1141 // search pdbentries and sequences to find correct pdbentry for this
1143 for (int pe = 0; pe < getPdbCount(); pe++)
1145 boolean matches = false;
1146 if (fileName == null)
1149 // see JAL-623 - need method of matching pasted data up
1151 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1152 pdbfile, AppletFormatAdapter.PASTE);
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 String protocol = AppletFormatAdapter.URL;
1175 protocol = AppletFormatAdapter.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);
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(pdb.getId() + ":"
1195 + pdb.getChains().elementAt(i).id);
1196 chainFile.put(chid, fileName);
1197 chainNames.addElement(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("model *; select backbone;restrict;cartoon;wireframe off;spacefill off");
1229 // register ourselves as a listener and notify the gui that it needs to
1231 getSsm().addStructureViewerListener(this);
1234 FeatureRenderer fr = getFeatureRenderer(null);
1240 loadNotifiesHandled++;
1242 setLoadingFromArchive(false);
1245 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1247 notifyAtomPicked(iatom, strMeasure, null);
1250 public abstract void notifyScriptTermination(String strStatus,
1254 * display a message echoed from the jmol viewer
1258 public abstract void sendConsoleEcho(String strEcho); /*
1259 * { showConsole(true);
1261 * history.append("\n" +
1265 // /End JmolStatusListener
1266 // /////////////////////////////
1270 * status message - usually the response received after a script
1273 public abstract void sendConsoleMessage(String strStatus);
1276 public void setCallbackFunction(String callbackType,
1277 String callbackFunction)
1279 System.err.println("Ignoring set-callback request to associate "
1280 + callbackType + " with function " + callbackFunction);
1284 public void setJalviewColourScheme(ColourSchemeI cs)
1286 colourBySequence = false;
1294 StringBuilder command = new StringBuilder(128);
1295 command.append("select *;color white;");
1296 List<String> residueSet = ResidueProperties.getResidues(isNucleotide(),
1298 for (String res : residueSet)
1300 Color col = cs.findColour(res.charAt(0));
1301 command.append("select " + res + ";color[" + col.getRed() + ","
1302 + col.getGreen() + "," + col.getBlue() + "];");
1305 evalStateCommand(command.toString());
1309 public void showHelp()
1311 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1315 * open the URL somehow
1319 public abstract void showUrl(String url, String target);
1322 * called when the binding thinks the UI needs to be refreshed after a Jmol
1323 * state change. this could be because structures were loaded, or because an
1324 * error has occured.
1326 public abstract void refreshGUI();
1329 * called to show or hide the associated console window container.
1333 public abstract void showConsole(boolean show);
1336 * @param renderPanel
1338 * - when true will initialise jmol's file IO system (should be false
1339 * in applet context)
1341 * @param documentBase
1343 * @param commandOptions
1345 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1346 String htmlName, URL documentBase, URL codeBase,
1347 String commandOptions)
1349 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1350 codeBase, commandOptions, null, null);
1355 * @param renderPanel
1357 * - when true will initialise jmol's file IO system (should be false
1358 * in applet context)
1360 * @param documentBase
1362 * @param commandOptions
1363 * @param consolePanel
1364 * - panel to contain Jmol console
1365 * @param buttonsToShow
1366 * - buttons to show on the console, in ordr
1368 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1369 String htmlName, URL documentBase, URL codeBase,
1370 String commandOptions, final Container consolePanel,
1371 String buttonsToShow)
1373 if (commandOptions == null)
1375 commandOptions = "";
1377 viewer = (Viewer) JmolViewer.allocateViewer(renderPanel,
1378 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1379 + ((Object) this).toString(), documentBase, codeBase,
1380 commandOptions, this);
1382 viewer.setJmolStatusListener(this); // extends JmolCallbackListener
1384 console = createJmolConsole(consolePanel, buttonsToShow);
1385 if (consolePanel != null)
1387 consolePanel.addComponentListener(this);
1393 protected abstract JmolAppConsoleInterface createJmolConsole(
1394 Container consolePanel, String buttonsToShow);
1396 protected org.jmol.api.JmolAppConsoleInterface console = null;
1398 public void setBackgroundColour(java.awt.Color col)
1401 viewer.evalStringQuiet("background [" + col.getRed() + ","
1402 + col.getGreen() + "," + col.getBlue() + "];");
1407 public Dimension resizeInnerPanel(String data)
1409 // Jalview doesn't honour resize panel requests
1416 protected void closeConsole()
1418 if (console != null)
1422 console.setVisible(false);
1425 } catch (Exception x)
1434 * ComponentListener method
1437 public void componentMoved(ComponentEvent e)
1442 * ComponentListener method
1445 public void componentResized(ComponentEvent e)
1450 * ComponentListener method
1453 public void componentShown(ComponentEvent e)
1459 * ComponentListener method
1462 public void componentHidden(ComponentEvent e)