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 org.jmol.adapter.smarter.SmarterJmolAdapter;
53 import org.jmol.api.JmolAppConsoleInterface;
54 import org.jmol.api.JmolSelectionListener;
55 import org.jmol.api.JmolStatusListener;
56 import org.jmol.api.JmolViewer;
57 import org.jmol.c.CBK;
58 import org.jmol.script.T;
59 import org.jmol.viewer.Viewer;
61 public abstract class JalviewJmolBinding extends AAStructureBindingModel
62 implements JmolStatusListener, JmolSelectionListener,
65 boolean allChainsSelected = false;
68 * when true, try to search the associated datamodel for sequences that are
69 * associated with any unknown structures in the Jmol view.
71 private boolean associateNewStructs = false;
73 Vector<String> atomsPicked = new Vector<String>();
75 private List<String> chainNames;
77 Hashtable<String, String> chainFile;
79 public String fileLoadingError;
82 * the default or current model displayed if the model cannot be identified
83 * from the selection message
87 // protected JmolGenericPopup jmolpopup; // not used - remove?
95 StringBuffer resetLastRes = new StringBuffer();
99 public JalviewJmolBinding(StructureSelectionManager ssm,
100 PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
103 super(ssm, pdbentry, sequenceIs, protocol);
105 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
106 * "jalviewJmol", ap.av.applet .getDocumentBase(),
107 * ap.av.applet.getCodeBase(), "", this);
109 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
113 public JalviewJmolBinding(StructureSelectionManager ssm,
114 SequenceI[][] seqs, Viewer theViewer)
119 viewer.setJmolStatusListener(this);
120 viewer.addSelectionListener(this);
124 * construct a title string for the viewer window based on the data jalview
129 public String getViewerTitle()
131 return getViewerTitle("Jmol", true);
135 * prepare the view for a given set of models/chains. chainList contains
136 * strings of the form 'pdbfilename:Chaincode'
139 * list of chains to make visible
141 public void centerViewer(Vector<String> chainList)
143 StringBuilder cmd = new StringBuilder(128);
145 for (String lbl : chainList)
151 mlength = lbl.indexOf(":", p);
152 } while (p < mlength && mlength < (lbl.length() - 2));
153 // TODO: lookup each pdb id and recover proper model number for it.
154 cmd.append(":" + lbl.substring(mlength + 1) + " /"
155 + (1 + getModelNum(chainFile.get(lbl))) + " or ");
157 if (cmd.length() > 0)
159 cmd.setLength(cmd.length() - 4);
161 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
164 public void closeViewer()
166 // remove listeners for all structures in viewer
167 getSsm().removeStructureViewerListener(this, this.getPdbFile());
171 releaseUIResources();
174 public void colourByChain()
176 colourBySequence = false;
177 // TODO: colour by chain should colour each chain distinctly across all
179 // TODO: http://issues.jalview.org/browse/JAL-628
180 evalStateCommand("select *;color chain");
183 public void colourByCharge()
185 colourBySequence = false;
186 evalStateCommand("select *;color white;select ASP,GLU;color red;"
187 + "select LYS,ARG;color blue;select CYS;color yellow");
191 * superpose the structures associated with sequences in the alignment
192 * according to their corresponding positions.
194 public void superposeStructures(AlignmentI alignment)
196 superposeStructures(alignment, -1, null);
200 * superpose the structures associated with sequences in the alignment
201 * according to their corresponding positions. ded)
203 * @param refStructure
204 * - select which pdb file to use as reference (default is -1 - the
205 * first structure in the alignment)
207 public void superposeStructures(AlignmentI alignment, int refStructure)
209 superposeStructures(alignment, refStructure, null);
213 * superpose the structures associated with sequences in the alignment
214 * according to their corresponding positions. ded)
216 * @param refStructure
217 * - select which pdb file to use as reference (default is -1 - the
218 * first structure in the alignment)
222 public void superposeStructures(AlignmentI alignment, int refStructure,
223 ColumnSelection hiddenCols)
225 superposeStructures(new AlignmentI[] { alignment },
226 new int[] { refStructure },
227 new ColumnSelection[] { hiddenCols });
231 * Construct and send a command to align structures against a reference
232 * structure, based on one or more sequence alignments
235 * an array of alignments to process
236 * @param _refStructure
237 * an array of corresponding reference structures (index into pdb
238 * file array); if a negative value is passed, the first PDB file
239 * mapped to an alignment sequence is used as the reference for
242 * an array of corresponding hidden columns for each alignment
244 public void superposeStructures(AlignmentI[] _alignment,
245 int[] _refStructure, ColumnSelection[] _hiddenCols)
247 while (viewer.isScriptExecuting())
252 } catch (InterruptedException i)
258 * get the distinct structure files modelled
259 * (a file with multiple chains may map to multiple sequences)
261 String[] files = getPdbFile();
262 if (!waitForFileLoad(files))
267 StringBuilder selectioncom = new StringBuilder(256);
268 // In principle - nSeconds specifies the speed of animation for each
269 // superposition - but is seems to behave weirdly, so we don't specify it.
270 String nSeconds = " ";
271 if (files.length > 10)
273 nSeconds = " 0.005 ";
277 nSeconds = " " + (2.0 / files.length) + " ";
278 // if (nSeconds).substring(0,5)+" ";
280 // see JAL-1345 - should really automatically turn off the animation for
281 // large numbers of structures, but Jmol doesn't seem to allow that.
283 // union of all aligned positions are collected together.
284 for (int a = 0; a < _alignment.length; a++)
286 int refStructure = _refStructure[a];
287 AlignmentI alignment = _alignment[a];
288 ColumnSelection hiddenCols = _hiddenCols[a];
290 && selectioncom.length() > 0
291 && !selectioncom.substring(selectioncom.length() - 1).equals(
294 selectioncom.append("|");
296 // process this alignment
297 if (refStructure >= files.length)
299 System.err.println("Invalid reference structure value "
305 * 'matched' array will hold 'true' for visible alignment columns where
306 * all sequences have a residue with a mapping to the PDB structure
308 // TODO could use a BitSet for matched
309 boolean matched[] = new boolean[alignment.getWidth()];
310 for (int m = 0; m < matched.length; m++)
312 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
315 SuperposeData[] structures = new SuperposeData[files.length];
316 for (int f = 0; f < files.length; f++)
318 structures[f] = new SuperposeData(alignment.getWidth());
322 * Calculate the superposable alignment columns ('matched'), and the
323 * corresponding structure residue positions (structures.pdbResNo)
325 int candidateRefStructure = findSuperposableResidues(alignment,
326 matched, structures);
327 if (refStructure < 0)
330 * If no reference structure was specified, pick the first one that has
331 * a mapping in the alignment
333 refStructure = candidateRefStructure;
336 String[] selcom = new String[files.length];
338 for (boolean b : matched)
347 // TODO: bail out here because superposition illdefined?
351 * generate select statements to select regions to superimpose structures
354 // TODO extract method to construct selection statements
355 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
357 String chainCd = ":" + structures[pdbfnum].chain;
360 StringBuilder molsel = new StringBuilder();
362 for (int r = 0; r < matched.length; r++)
366 int pdbResNo = structures[pdbfnum].pdbResNo[r];
367 if (lpos != pdbResNo - 1)
373 molsel.append(chainCd);
380 // continuous run - and lpos >-1
383 // at the beginning, so add dash
393 * add final selection phrase
398 molsel.append(chainCd);
401 if (molsel.length() > 1)
403 selcom[pdbfnum] = molsel.toString();
404 selectioncom.append("((");
405 selectioncom.append(selcom[pdbfnum].substring(1,
406 selcom[pdbfnum].length() - 1));
407 selectioncom.append(" )& ");
408 selectioncom.append(pdbfnum + 1);
409 selectioncom.append(".1)");
410 if (pdbfnum < files.length - 1)
412 selectioncom.append("|");
417 selcom[pdbfnum] = null;
421 StringBuilder command = new StringBuilder(256);
422 // command.append("set spinFps 10;\n");
424 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
426 if (pdbfnum == refStructure || selcom[pdbfnum] == null
427 || selcom[refStructure] == null)
431 command.append("echo ");
432 command.append("\"Superposing (");
433 command.append(structures[pdbfnum].pdbId);
434 command.append(") against reference (");
435 command.append(structures[refStructure].pdbId);
436 command.append(")\";\ncompare " + nSeconds);
438 command.append(Integer.toString(1 + pdbfnum));
439 command.append(".1} {");
440 command.append(Integer.toString(1 + refStructure));
441 // conformation=1 excludes alternate locations for CA (JAL-1757)
442 command.append(".1} SUBSET {(*.CA | *.P) and conformation=1} ATOMS ");
444 // for (int s = 0; s < 2; s++)
446 // command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
448 command.append(selcom[pdbfnum]);
449 command.append(selcom[refStructure]);
450 command.append(" ROTATE TRANSLATE;\n");
452 if (selectioncom.length() > 0)
454 // TODO is performing selectioncom redundant here? is done later on
455 // System.out.println("Select regions:\n" + selectioncom.toString());
456 evalStateCommand("select *; cartoons off; backbone; select ("
457 + selectioncom.toString() + "); cartoons; ");
458 // selcom.append("; ribbons; ");
459 String cmdString = command.toString();
460 // System.out.println("Superimpose command(s):\n" + cmdString);
462 evalStateCommand(cmdString);
465 if (selectioncom.length() > 0)
466 {// finally, mark all regions that were superposed.
467 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
469 selectioncom.setLength(selectioncom.length() - 1);
471 // System.out.println("Select regions:\n" + selectioncom.toString());
472 evalStateCommand("select *; cartoons off; backbone; select ("
473 + selectioncom.toString() + "); cartoons; ");
474 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
478 public void evalStateCommand(String command)
481 if (lastCommand == null || !lastCommand.equals(command))
483 viewer.evalStringQuiet(command + "\n");
486 lastCommand = command;
490 * colour any structures associated with sequences in the given alignment
491 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
492 * if colourBySequence is enabled.
494 public void colourBySequence(AlignmentViewPanel alignmentv)
496 boolean showFeatures = alignmentv.getAlignViewport()
497 .isShowSequenceFeatures();
498 if (!colourBySequence || !isLoadingFinished())
502 if (getSsm() == null)
506 String[] files = getPdbFile();
508 SequenceRenderer sr = getSequenceRenderer(alignmentv);
510 FeatureRenderer fr = null;
513 fr = getFeatureRenderer(alignmentv);
515 AlignmentI alignment = alignmentv.getAlignment();
517 for (jalview.structure.StructureMappingcommandSet cpdbbyseq : getColourBySequenceCommands(
518 files, sr, fr, alignment))
520 for (String cbyseq : cpdbbyseq.commands)
522 executeWhenReady(cbyseq);
534 protected StructureMappingcommandSet[] getColourBySequenceCommands(
535 String[] files, SequenceRenderer sr, FeatureRenderer fr,
536 AlignmentI alignment)
538 return JmolCommands.getColourBySequenceCommand(getSsm(), files,
539 getSequence(), sr, fr, alignment);
545 protected void executeWhenReady(String command)
547 evalStateCommand(command);
550 public void createImage(String file, String type, int quality)
552 System.out.println("JMOL CREATE IMAGE");
556 public String createImage(String fileName, String type,
557 Object textOrBytes, int quality)
559 System.out.println("JMOL CREATE IMAGE");
564 public String eval(String strEval)
566 // System.out.println(strEval);
567 // "# 'eval' is implemented only for the applet.";
571 // End StructureListener
572 // //////////////////////////
575 public float[][] functionXY(String functionName, int x, int y)
581 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
583 // TODO Auto-generated method stub
587 public Color getColour(int atomIndex, int pdbResNum, String chain,
590 if (getModelNum(pdbfile) < 0)
594 // TODO: verify atomIndex is selecting correct model.
595 // return new Color(viewer.getAtomArgb(atomIndex)); Jmol 12.2.4
596 int colour = viewer.ms.at[atomIndex].atomPropertyInt(T.color);
597 return new Color(colour);
601 * returns the current featureRenderer that should be used to colour the
608 public abstract FeatureRenderer getFeatureRenderer(
609 AlignmentViewPanel alignment);
612 * instruct the Jalview binding to update the pdbentries vector if necessary
613 * prior to matching the jmol view's contents to the list of structure files
614 * Jalview knows about.
616 public abstract void refreshPdbEntries();
618 private int getModelNum(String modelFileName)
620 String[] mfn = getPdbFile();
625 for (int i = 0; i < mfn.length; i++)
627 if (mfn[i].equalsIgnoreCase(modelFileName))
636 * map between index of model filename returned from getPdbFile and the first
637 * index of models from this file in the viewer. Note - this is not trimmed -
638 * use getPdbFile to get number of unique models.
640 private int _modelFileNameMap[];
642 // ////////////////////////////////
643 // /StructureListener
645 public synchronized String[] getPdbFile()
649 return new String[0];
651 if (modelFileNames == null)
653 List<String> mset = new ArrayList<String>();
654 _modelFileNameMap = new int[viewer.ms.mc];
655 String m = viewer.ms.getModelFileName(0);
661 filePath = new File(m).getAbsolutePath();
662 } catch (AccessControlException x)
664 // usually not allowed to do this in applet
666 .println("jmolBinding: Using local file string from Jmol: "
669 if (filePath.indexOf("/file:") != -1)
671 // applet path with docroot - discard as format won't match pdbfile
675 _modelFileNameMap[0] = 0; // filename index for first model is always 0.
678 for (int i = 1; i < viewer.ms.mc; i++)
680 m = viewer.ms.getModelFileName(i);
686 filePath = new File(m).getAbsolutePath();
687 } catch (AccessControlException x)
689 // usually not allowed to do this in applet, so keep raw handle
690 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
695 * add this model unless it is read from a structure file we have
696 * already seen (example: 2MJW is an NMR structure with 10 models)
698 if (!mset.contains(filePath))
701 _modelFileNameMap[j] = i; // record the model index for the filename
705 modelFileNames = mset.toArray(new String[mset.size()]);
707 return modelFileNames;
711 * map from string to applet
714 public Map<String, Object> getRegistryInfo()
716 // TODO Auto-generated method stub
721 * returns the current sequenceRenderer that should be used to colour the
728 public abstract SequenceRenderer getSequenceRenderer(
729 AlignmentViewPanel alignment);
731 // ///////////////////////////////
732 // JmolStatusListener
734 public void handlePopupMenu(int x, int y)
736 // jmolpopup.show(x, y);
737 // jmolpopup.jpiShow(x, y);
741 * Highlight zero, one or more atoms on the structure
744 public void highlightAtoms(List<AtomSpec> atoms)
748 if (resetLastRes.length() > 0)
750 viewer.evalStringQuiet(resetLastRes.toString());
751 resetLastRes.setLength(0);
753 for (AtomSpec atom : atoms)
755 highlightAtom(atom.getAtomIndex(), atom.getPdbResNum(),
756 atom.getChain(), atom.getPdbFile());
762 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
765 if (modelFileNames == null)
770 // look up file model number for this pdbfile
772 // may need to adjust for URLencoding here - we don't worry about that yet.
773 while (mdlNum < modelFileNames.length
774 && !pdbfile.equals(modelFileNames[mdlNum]))
778 if (mdlNum == modelFileNames.length)
785 StringBuilder cmd = new StringBuilder(64);
786 cmd.append("select " + pdbResNum); // +modelNum
788 resetLastRes.append("select " + pdbResNum); // +modelNum
791 resetLastRes.append(":");
792 if (!chain.equals(" "))
795 resetLastRes.append(chain);
798 cmd.append(" /" + (mdlNum + 1));
799 resetLastRes.append("/" + (mdlNum + 1));
801 cmd.append(";wireframe 100;" + cmd.toString() + " and not hetero;");
803 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
804 + " and not hetero; spacefill 0;");
806 cmd.append("spacefill 200;select none");
808 viewer.evalStringQuiet(cmd.toString());
813 boolean debug = true;
815 private void jmolHistory(boolean enable)
817 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
820 public void loadInline(String string)
824 // viewer.loadInline(strModel, isAppend);
826 // construct fake fullPathName and fileName so we can identify the file
828 // Then, construct pass a reader for the string to Jmol.
829 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
830 // fileName, null, reader, false, null, null, 0);
831 viewer.openStringInline(string);
834 public void mouseOverStructure(int atomIndex, String strInfo)
837 int alocsep = strInfo.indexOf("^");
838 int mdlSep = strInfo.indexOf("/");
839 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
841 if (chainSeparator == -1)
843 chainSeparator = strInfo.indexOf(".");
844 if (mdlSep > -1 && mdlSep < chainSeparator)
846 chainSeparator1 = chainSeparator;
847 chainSeparator = mdlSep;
850 // handle insertion codes
853 pdbResNum = Integer.parseInt(strInfo.substring(
854 strInfo.indexOf("]") + 1, alocsep));
859 pdbResNum = Integer.parseInt(strInfo.substring(
860 strInfo.indexOf("]") + 1, chainSeparator));
864 if (strInfo.indexOf(":") > -1)
866 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
867 strInfo.indexOf("."));
874 String pdbfilename = modelFileNames[frameNo]; // default is first or current
878 if (chainSeparator1 == -1)
880 chainSeparator1 = strInfo.indexOf(".", mdlSep);
882 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
883 chainSeparator1) : strInfo.substring(mdlSep + 1);
886 // recover PDB filename for the model hovered over.
887 int _mp = _modelFileNameMap.length - 1, mnumber = new Integer(mdlId)
889 while (mnumber < _modelFileNameMap[_mp])
893 pdbfilename = modelFileNames[_mp];
894 if (pdbfilename == null)
896 pdbfilename = new File(viewer.ms.getModelFileName(mnumber))
900 } catch (Exception e)
905 if (lastMessage == null || !lastMessage.equals(strInfo))
907 getSsm().mouseOverStructure(pdbResNum, chainId, pdbfilename);
910 lastMessage = strInfo;
913 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
917 System.err.println("Ignoring additional hover info: " + data
918 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
920 mouseOverStructure(atomIndex, strInfo);
924 * { if (history != null && strStatus != null &&
925 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
929 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
932 * this implements the toggle label behaviour copied from the original
933 * structure viewer, MCView
937 System.err.println("Ignoring additional pick data string " + strData);
939 int chainSeparator = strInfo.indexOf(":");
941 if (chainSeparator == -1)
943 chainSeparator = strInfo.indexOf(".");
946 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
948 String mdlString = "";
949 if ((p = strInfo.indexOf(":")) > -1)
951 picked += strInfo.substring(p, strInfo.indexOf("."));
954 if ((p = strInfo.indexOf("/")) > -1)
956 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
958 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
962 if (!atomsPicked.contains(picked))
964 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
965 atomsPicked.addElement(picked);
969 viewer.evalString("select " + picked + ";label off");
970 atomsPicked.removeElement(picked);
973 // TODO: in application this happens
975 // if (scriptWindow != null)
977 // scriptWindow.sendConsoleMessage(strInfo);
978 // scriptWindow.sendConsoleMessage("\n");
984 public void notifyCallback(CBK type, Object[] data)
991 notifyFileLoaded((String) data[1], (String) data[2],
992 (String) data[3], (String) data[4],
993 ((Integer) data[5]).intValue());
997 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
999 // also highlight in alignment
1001 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1005 notifyScriptTermination((String) data[2],
1006 ((Integer) data[3]).intValue());
1009 sendConsoleEcho((String) data[1]);
1012 sendConsoleMessage((data == null) ? ((String) null)
1013 : (String) data[1]);
1016 // System.err.println("Ignoring error callback.");
1026 System.err.println("Unhandled callback " + type + " "
1027 + 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<String>();
1085 chainFile = new Hashtable<String, String>();
1086 boolean notifyLoaded = false;
1087 String[] modelfilenames = getPdbFile();
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("" + (1 + _modelFileNameMap[modelnum])
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, AppletFormatAdapter.PASTE);
1152 getPdbEntry(modelnum).setFile("INLINE" + pdb.getId());
1159 File fl = new File(getPdbEntry(pe).getFile());
1160 matches = fl.equals(new File(fileName));
1164 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1167 // to be tested. See mantis bug
1168 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1169 String protocol = AppletFormatAdapter.URL;
1174 protocol = AppletFormatAdapter.FILE;
1176 } catch (Exception e)
1181 // Explicitly map to the filename used by Jmol ;
1182 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1183 fileName, protocol);
1184 // pdbentry[pe].getFile(), protocol);
1190 // add an entry for every chain in the model
1191 for (int i = 0; i < pdb.getChains().size(); i++)
1193 String chid = new String(pdb.getId() + ":"
1194 + pdb.getChains().elementAt(i).id);
1195 chainFile.put(chid, fileName);
1196 chainNames.add(chid);
1198 notifyLoaded = true;
1202 if (!foundEntry && associateNewStructs)
1204 // this is a foreign pdb file that jalview doesn't know about - add
1205 // it to the dataset and try to find a home - either on a matching
1206 // sequence or as a new sequence.
1207 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1209 // parse pdb file into a chain, etc.
1210 // locate best match for pdb in associated views and add mapping to
1212 // if properly registered then
1213 notifyLoaded = true;
1218 // so finally, update the jmol bits and pieces
1219 // if (jmolpopup != null)
1221 // // potential for deadlock here:
1222 // // jmolpopup.updateComputedMenus();
1224 if (!isLoadingFromArchive())
1226 viewer.evalStringQuiet("model *; select backbone;restrict;cartoon;wireframe off;spacefill off");
1228 // register ourselves as a listener and notify the gui that it needs to
1230 getSsm().addStructureViewerListener(this);
1233 FeatureRenderer fr = getFeatureRenderer(null);
1239 loadNotifiesHandled++;
1241 setLoadingFromArchive(false);
1245 public List<String> getChainNames()
1250 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1252 notifyAtomPicked(iatom, strMeasure, null);
1255 public abstract void notifyScriptTermination(String strStatus,
1259 * display a message echoed from the jmol viewer
1263 public abstract void sendConsoleEcho(String strEcho); /*
1264 * { showConsole(true);
1266 * history.append("\n" +
1270 // /End JmolStatusListener
1271 // /////////////////////////////
1275 * status message - usually the response received after a script
1278 public abstract void sendConsoleMessage(String strStatus);
1281 public void setCallbackFunction(String callbackType,
1282 String callbackFunction)
1284 System.err.println("Ignoring set-callback request to associate "
1285 + callbackType + " with function " + callbackFunction);
1289 public void setJalviewColourScheme(ColourSchemeI cs)
1291 colourBySequence = false;
1299 StringBuilder command = new StringBuilder(128);
1300 command.append("select *;color white;");
1301 List<String> residueSet = ResidueProperties.getResidues(isNucleotide(),
1303 for (String res : residueSet)
1305 Color col = cs.findColour(res.charAt(0));
1306 command.append("select " + res + ";color[" + col.getRed() + ","
1307 + col.getGreen() + "," + col.getBlue() + "];");
1310 evalStateCommand(command.toString());
1314 public void showHelp()
1316 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1320 * open the URL somehow
1324 public abstract void showUrl(String url, String target);
1327 * called when the binding thinks the UI needs to be refreshed after a Jmol
1328 * state change. this could be because structures were loaded, or because an
1329 * error has occured.
1331 public abstract void refreshGUI();
1334 * called to show or hide the associated console window container.
1338 public abstract void showConsole(boolean show);
1341 * @param renderPanel
1343 * - when true will initialise jmol's file IO system (should be false
1344 * in applet context)
1346 * @param documentBase
1348 * @param commandOptions
1350 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1351 String htmlName, URL documentBase, URL codeBase,
1352 String commandOptions)
1354 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1355 codeBase, commandOptions, null, null);
1360 * @param renderPanel
1362 * - when true will initialise jmol's file IO system (should be false
1363 * in applet context)
1365 * @param documentBase
1367 * @param commandOptions
1368 * @param consolePanel
1369 * - panel to contain Jmol console
1370 * @param buttonsToShow
1371 * - buttons to show on the console, in ordr
1373 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1374 String htmlName, URL documentBase, URL codeBase,
1375 String commandOptions, final Container consolePanel,
1376 String buttonsToShow)
1378 if (commandOptions == null)
1380 commandOptions = "";
1382 viewer = (Viewer) JmolViewer.allocateViewer(renderPanel,
1383 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1384 + ((Object) this).toString(), documentBase, codeBase,
1385 commandOptions, this);
1387 viewer.setJmolStatusListener(this); // extends JmolCallbackListener
1389 console = createJmolConsole(consolePanel, buttonsToShow);
1390 if (consolePanel != null)
1392 consolePanel.addComponentListener(this);
1398 protected abstract JmolAppConsoleInterface createJmolConsole(
1399 Container consolePanel, String buttonsToShow);
1401 protected org.jmol.api.JmolAppConsoleInterface console = null;
1403 public void setBackgroundColour(java.awt.Color col)
1406 viewer.evalStringQuiet("background [" + col.getRed() + ","
1407 + col.getGreen() + "," + col.getBlue() + "];");
1412 public int[] resizeInnerPanel(String data)
1414 // Jalview doesn't honour resize panel requests
1421 protected void closeConsole()
1423 if (console != null)
1427 console.setVisible(false);
1430 } catch (Exception x)
1439 * ComponentListener method
1442 public void componentMoved(ComponentEvent e)
1447 * ComponentListener method
1450 public void componentResized(ComponentEvent e)
1455 * ComponentListener method
1458 public void componentShown(ComponentEvent e)
1464 * ComponentListener method
1467 public void componentHidden(ComponentEvent e)