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 java.awt.Color;
24 import java.awt.Container;
25 import java.awt.event.ComponentEvent;
26 import java.awt.event.ComponentListener;
29 import java.util.ArrayList;
30 import java.util.BitSet;
31 import java.util.Hashtable;
32 import java.util.List;
34 import java.util.StringTokenizer;
35 import java.util.Vector;
37 import javax.swing.SwingUtilities;
39 import org.jmol.adapter.smarter.SmarterJmolAdapter;
40 import org.jmol.api.JmolAppConsoleInterface;
41 import org.jmol.api.JmolSelectionListener;
42 import org.jmol.api.JmolStatusListener;
43 import org.jmol.api.JmolViewer;
44 import org.jmol.c.CBK;
45 import org.jmol.script.T;
46 import org.jmol.viewer.Viewer;
48 import jalview.api.AlignmentViewPanel;
49 import jalview.api.FeatureRenderer;
50 import jalview.api.FeatureSettingsModelI;
51 import jalview.api.SequenceRenderer;
52 import jalview.datamodel.AlignmentI;
53 import jalview.datamodel.HiddenColumns;
54 import jalview.datamodel.PDBEntry;
55 import jalview.datamodel.SequenceI;
56 import jalview.gui.AppJmol;
57 import jalview.gui.IProgressIndicator;
58 import jalview.io.DataSourceType;
59 import jalview.io.StructureFile;
60 import jalview.schemes.ColourSchemeI;
61 import jalview.schemes.ResidueProperties;
62 import jalview.structure.AtomSpec;
63 import jalview.structure.StructureMappingcommandSet;
64 import jalview.structure.StructureSelectionManager;
65 import jalview.structures.models.AAStructureBindingModel;
66 import jalview.util.MessageManager;
67 import jalview.ws.dbsources.Pdb;
69 public abstract class JalviewJmolBinding extends AAStructureBindingModel
70 implements JmolStatusListener, JmolSelectionListener,
73 private String lastMessage;
75 boolean allChainsSelected = false;
78 * when true, try to search the associated datamodel for sequences that are
79 * associated with any unknown structures in the Jmol view.
81 private boolean associateNewStructs = false;
83 Vector<String> atomsPicked = new Vector<>();
85 private List<String> chainNames;
87 Hashtable<String, String> chainFile;
90 * the default or current model displayed if the model cannot be identified
91 * from the selection message
95 // protected JmolGenericPopup jmolpopup; // not used - remove?
101 StringBuffer resetLastRes = new StringBuffer();
103 public Viewer viewer;
105 public JalviewJmolBinding(StructureSelectionManager ssm,
106 PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
107 DataSourceType protocol)
109 super(ssm, pdbentry, sequenceIs, protocol);
111 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
112 * "jalviewJmol", ap.av.applet .getDocumentBase(),
113 * ap.av.applet.getCodeBase(), "", this);
115 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
119 public JalviewJmolBinding(StructureSelectionManager ssm,
120 SequenceI[][] seqs, Viewer theViewer)
125 viewer.setJmolStatusListener(this);
126 viewer.addSelectionListener(this);
130 * construct a title string for the viewer window based on the data jalview
135 public String getViewerTitle()
137 return getViewerTitle("Jmol", true);
141 * prepare the view for a given set of models/chains. chainList contains
142 * strings of the form 'pdbfilename:Chaincode'
145 * list of chains to make visible
147 public void centerViewer(Vector<String> chainList)
149 StringBuilder cmd = new StringBuilder(128);
151 for (String lbl : chainList)
157 mlength = lbl.indexOf(":", p);
158 } while (p < mlength && mlength < (lbl.length() - 2));
159 // TODO: lookup each pdb id and recover proper model number for it.
160 cmd.append(":" + lbl.substring(mlength + 1) + " /"
161 + (1 + getModelNum(chainFile.get(lbl))) + " or ");
163 if (cmd.length() > 0)
165 cmd.setLength(cmd.length() - 4);
167 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
170 public void closeViewer()
172 // remove listeners for all structures in viewer
173 getSsm().removeStructureViewerListener(this, this.getStructureFiles());
177 releaseUIResources();
181 public void colourByChain()
183 colourBySequence = false;
184 // TODO: colour by chain should colour each chain distinctly across all
186 // TODO: http://issues.jalview.org/browse/JAL-628
187 evalStateCommand("select *;color chain");
191 public void colourByCharge()
193 colourBySequence = false;
194 evalStateCommand("select *;color white;select ASP,GLU;color red;"
195 + "select LYS,ARG;color blue;select CYS;color yellow");
199 * superpose the structures associated with sequences in the alignment
200 * according to their corresponding positions.
202 public void superposeStructures(AlignmentI alignment)
204 superposeStructures(alignment, -1, null);
208 * superpose the structures associated with sequences in the alignment
209 * according to their corresponding positions. ded)
211 * @param refStructure
212 * - select which pdb file to use as reference (default is -1 - the
213 * first structure in the alignment)
215 public void superposeStructures(AlignmentI alignment, int refStructure)
217 superposeStructures(alignment, refStructure, null);
221 * superpose the structures associated with sequences in the alignment
222 * according to their corresponding positions. ded)
224 * @param refStructure
225 * - select which pdb file to use as reference (default is -1 - the
226 * first structure in the alignment)
230 public void superposeStructures(AlignmentI alignment, int refStructure,
231 HiddenColumns hiddenCols)
233 superposeStructures(new AlignmentI[] { alignment },
235 { refStructure }, new HiddenColumns[] { hiddenCols });
242 public String superposeStructures(AlignmentI[] _alignment,
243 int[] _refStructure, HiddenColumns[] _hiddenCols)
245 while (viewer.isScriptExecuting())
250 } catch (InterruptedException i)
256 * get the distinct structure files modelled
257 * (a file with multiple chains may map to multiple sequences)
259 String[] files = getStructureFiles();
260 if (!waitForFileLoad(files))
265 StringBuilder selectioncom = new StringBuilder(256);
266 // In principle - nSeconds specifies the speed of animation for each
267 // superposition - but is seems to behave weirdly, so we don't specify it.
268 String nSeconds = " ";
269 if (files.length > 10)
271 nSeconds = " 0.005 ";
275 nSeconds = " " + (2.0 / files.length) + " ";
276 // if (nSeconds).substring(0,5)+" ";
279 // see JAL-1345 - should really automatically turn off the animation for
280 // large numbers of structures, but Jmol doesn't seem to allow that.
282 // union of all aligned positions are collected together.
283 for (int a = 0; a < _alignment.length; a++)
285 int refStructure = _refStructure[a];
286 AlignmentI alignment = _alignment[a];
287 HiddenColumns hiddenCols = _hiddenCols[a];
288 if (a > 0 && selectioncom.length() > 0 && !selectioncom
289 .substring(selectioncom.length() - 1).equals("|"))
291 selectioncom.append("|");
293 // process this alignment
294 if (refStructure >= files.length)
297 "Invalid reference structure value " + refStructure);
302 * 'matched' bit j will be set for visible alignment columns j where
303 * all sequences have a residue with a mapping to the PDB structure
305 BitSet matched = new BitSet();
306 for (int m = 0; m < alignment.getWidth(); m++)
308 if (hiddenCols == null || hiddenCols.isVisible(m))
314 SuperposeData[] structures = new SuperposeData[files.length];
315 for (int f = 0; f < files.length; f++)
317 structures[f] = new SuperposeData(alignment.getWidth());
321 * Calculate the superposable alignment columns ('matched'), and the
322 * corresponding structure residue positions (structures.pdbResNo)
324 int candidateRefStructure = findSuperposableResidues(alignment,
325 matched, structures);
326 if (refStructure < 0)
329 * If no reference structure was specified, pick the first one that has
330 * a mapping in the alignment
332 refStructure = candidateRefStructure;
335 String[] selcom = new String[files.length];
336 int nmatched = matched.cardinality();
339 return (MessageManager.formatMessage("label.insufficient_residues",
344 * generate select statements to select regions to superimpose structures
347 // TODO extract method to construct selection statements
348 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
350 String chainCd = ":" + structures[pdbfnum].chain;
353 StringBuilder molsel = new StringBuilder();
356 int nextColumnMatch = matched.nextSetBit(0);
357 while (nextColumnMatch != -1)
359 int pdbResNo = structures[pdbfnum].pdbResNo[nextColumnMatch];
360 if (lpos != pdbResNo - 1)
366 molsel.append(chainCd);
373 // continuous run - and lpos >-1
376 // at the beginning, so add dash
383 nextColumnMatch = matched.nextSetBit(nextColumnMatch + 1);
386 * add final selection phrase
391 molsel.append(chainCd);
394 if (molsel.length() > 1)
396 selcom[pdbfnum] = molsel.toString();
397 selectioncom.append("((");
398 selectioncom.append(selcom[pdbfnum].substring(1,
399 selcom[pdbfnum].length() - 1));
400 selectioncom.append(" )& ");
401 selectioncom.append(pdbfnum + 1);
402 selectioncom.append(".1)");
403 if (pdbfnum < files.length - 1)
405 selectioncom.append("|");
410 selcom[pdbfnum] = null;
414 StringBuilder command = new StringBuilder(256);
415 // command.append("set spinFps 10;\n");
417 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
419 if (pdbfnum == refStructure || selcom[pdbfnum] == null
420 || selcom[refStructure] == null)
424 command.append("echo ");
425 command.append("\"Superposing (");
426 command.append(structures[pdbfnum].pdbId);
427 command.append(") against reference (");
428 command.append(structures[refStructure].pdbId);
429 command.append(")\";\ncompare " + nSeconds);
431 command.append(Integer.toString(1 + pdbfnum));
432 command.append(".1} {");
433 command.append(Integer.toString(1 + refStructure));
434 // conformation=1 excludes alternate locations for CA (JAL-1757)
436 ".1} SUBSET {(*.CA | *.P) and conformation=1} ATOMS ");
438 // for (int s = 0; s < 2; s++)
440 // command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
442 command.append(selcom[pdbfnum]);
443 command.append(selcom[refStructure]);
444 command.append(" ROTATE TRANSLATE;\n");
446 if (selectioncom.length() > 0)
448 // TODO is performing selectioncom redundant here? is done later on
449 // System.out.println("Select regions:\n" + selectioncom.toString());
450 evalStateCommand("select *; cartoons off; backbone; select ("
451 + selectioncom.toString() + "); cartoons; ");
452 // selcom.append("; ribbons; ");
453 String cmdString = command.toString();
454 // System.out.println("Superimpose command(s):\n" + cmdString);
456 evalStateCommand(cmdString);
459 if (selectioncom.length() > 0)
460 {// finally, mark all regions that were superposed.
461 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
463 selectioncom.setLength(selectioncom.length() - 1);
465 // System.out.println("Select regions:\n" + selectioncom.toString());
466 evalStateCommand("select *; cartoons off; backbone; select ("
467 + selectioncom.toString() + "); cartoons; ");
468 // evalStateCommand("select *; backbone; select "+selcom.toString()+";
469 // cartoons; center "+selcom.toString());
475 public void evalStateCommand(String command)
478 if (lastCommand == null || !lastCommand.equals(command))
480 viewer.evalStringQuiet(command + "\n");
483 lastCommand = command;
486 Thread colourby = null;
489 * Sends a set of colour commands to the structure viewer
491 * @param colourBySequenceCommands
494 protected void colourBySequence(
495 final StructureMappingcommandSet[] colourBySequenceCommands)
497 if (colourby != null)
499 colourby.interrupt();
502 colourby = new Thread(new Runnable()
507 for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands)
509 for (String cbyseq : cpdbbyseq.commands)
511 executeWhenReady(cbyseq);
526 protected StructureMappingcommandSet[] getColourBySequenceCommands(
527 String[] files, SequenceRenderer sr, AlignmentViewPanel viewPanel)
529 return JmolCommands.getColourBySequenceCommand(getSsm(), files,
530 getSequence(), sr, viewPanel);
536 protected void executeWhenReady(String command)
538 evalStateCommand(command);
541 public void createImage(String file, String type, int quality)
543 System.out.println("JMOL CREATE IMAGE");
547 public String createImage(String fileName, String type,
548 Object textOrBytes, int quality)
550 System.out.println("JMOL CREATE IMAGE");
555 public String eval(String strEval)
557 // System.out.println(strEval);
558 // "# 'eval' is implemented only for the applet.";
562 // End StructureListener
563 // //////////////////////////
566 public float[][] functionXY(String functionName, int x, int y)
572 public float[][][] functionXYZ(String functionName, int nx, int ny,
575 // TODO Auto-generated method stub
579 public Color getColour(int atomIndex, int pdbResNum, String chain,
582 if (getModelNum(pdbfile) < 0)
586 // TODO: verify atomIndex is selecting correct model.
587 // return new Color(viewer.getAtomArgb(atomIndex)); Jmol 12.2.4
588 int colour = viewer.ms.at[atomIndex].atomPropertyInt(T.color);
589 return new Color(colour);
593 * instruct the Jalview binding to update the pdbentries vector if necessary
594 * prior to matching the jmol view's contents to the list of structure files
595 * Jalview knows about.
597 public abstract void refreshPdbEntries();
599 private int getModelNum(String modelFileName)
601 String[] mfn = getStructureFiles();
606 for (int i = 0; i < mfn.length; i++)
608 if (mfn[i].equalsIgnoreCase(modelFileName))
617 * map between index of model filename returned from getPdbFile and the first
618 * index of models from this file in the viewer. Note - this is not trimmed -
619 * use getPdbFile to get number of unique models.
621 private int _modelFileNameMap[];
624 public synchronized String[] getStructureFiles()
626 List<String> mset = new ArrayList<>();
629 return new String[0];
632 if (modelFileNames == null)
634 int modelCount = viewer.ms.mc;
635 String filePath = null;
636 for (int i = 0; i < modelCount; ++i)
638 filePath = viewer.ms.getModelFileName(i);
639 if (!mset.contains(filePath))
644 modelFileNames = mset.toArray(new String[mset.size()]);
647 return modelFileNames;
651 * map from string to applet
654 public Map<String, Object> getRegistryInfo()
656 // TODO Auto-generated method stub
660 // ///////////////////////////////
661 // JmolStatusListener
663 public void handlePopupMenu(int x, int y)
665 // jmolpopup.show(x, y);
666 // jmolpopup.jpiShow(x, y);
670 * Highlight zero, one or more atoms on the structure
673 public void highlightAtoms(List<AtomSpec> atoms)
677 if (resetLastRes.length() > 0)
679 viewer.evalStringQuiet(resetLastRes.toString());
680 resetLastRes.setLength(0);
682 for (AtomSpec atom : atoms)
684 highlightAtom(atom.getAtomIndex(), atom.getPdbResNum(),
685 atom.getChain(), atom.getPdbFile());
691 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
694 if (modelFileNames == null)
699 // look up file model number for this pdbfile
701 // may need to adjust for URLencoding here - we don't worry about that yet.
702 while (mdlNum < modelFileNames.length
703 && !pdbfile.equals(modelFileNames[mdlNum]))
707 if (mdlNum == modelFileNames.length)
714 StringBuilder cmd = new StringBuilder(64);
715 cmd.append("select " + pdbResNum); // +modelNum
717 resetLastRes.append("select " + pdbResNum); // +modelNum
720 resetLastRes.append(":");
721 if (!chain.equals(" "))
724 resetLastRes.append(chain);
727 cmd.append(" /" + (mdlNum + 1));
728 resetLastRes.append("/" + (mdlNum + 1));
730 cmd.append(";wireframe 100;" + cmd.toString() + " and not hetero;");
732 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
733 + " and not hetero; spacefill 0;");
735 cmd.append("spacefill 200;select none");
737 viewer.evalStringQuiet(cmd.toString());
742 boolean debug = true;
744 private void jmolHistory(boolean enable)
746 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
749 public void loadInline(String string)
753 // viewer.loadInline(strModel, isAppend);
755 // construct fake fullPathName and fileName so we can identify the file
757 // Then, construct pass a reader for the string to Jmol.
758 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
759 // fileName, null, reader, false, null, null, 0);
760 viewer.openStringInline(string);
763 protected void mouseOverStructure(int atomIndex, final String strInfo)
766 int alocsep = strInfo.indexOf("^");
767 int mdlSep = strInfo.indexOf("/");
768 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
770 if (chainSeparator == -1)
772 chainSeparator = strInfo.indexOf(".");
773 if (mdlSep > -1 && mdlSep < chainSeparator)
775 chainSeparator1 = chainSeparator;
776 chainSeparator = mdlSep;
779 // handle insertion codes
782 pdbResNum = Integer.parseInt(
783 strInfo.substring(strInfo.indexOf("]") + 1, alocsep));
788 pdbResNum = Integer.parseInt(
789 strInfo.substring(strInfo.indexOf("]") + 1, chainSeparator));
793 if (strInfo.indexOf(":") > -1)
795 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
796 strInfo.indexOf("."));
803 String pdbfilename = modelFileNames[frameNo]; // default is first or current
807 if (chainSeparator1 == -1)
809 chainSeparator1 = strInfo.indexOf(".", mdlSep);
811 String mdlId = (chainSeparator1 > -1)
812 ? strInfo.substring(mdlSep + 1, chainSeparator1)
813 : strInfo.substring(mdlSep + 1);
816 // recover PDB filename for the model hovered over.
817 int mnumber = Integer.valueOf(mdlId).intValue() - 1;
818 if (_modelFileNameMap != null)
820 int _mp = _modelFileNameMap.length - 1;
822 while (mnumber < _modelFileNameMap[_mp])
826 pdbfilename = modelFileNames[_mp];
830 if (mnumber >= 0 && mnumber < modelFileNames.length)
832 pdbfilename = modelFileNames[mnumber];
835 if (pdbfilename == null)
837 pdbfilename = new File(viewer.ms.getModelFileName(mnumber))
841 } catch (Exception e)
847 * highlight position on alignment(s); if some text is returned,
848 * show this as a second line on the structure hover tooltip
850 String label = getSsm().mouseOverStructure(pdbResNum, chainId,
854 // change comma to pipe separator (newline token for Jmol)
855 label = label.replace(',', '|');
856 StringTokenizer toks = new StringTokenizer(strInfo, " ");
857 StringBuilder sb = new StringBuilder();
858 sb.append("select ").append(String.valueOf(pdbResNum)).append(":")
859 .append(chainId).append("/1");
860 sb.append(";set hoverLabel \"").append(toks.nextToken()).append(" ")
861 .append(toks.nextToken());
862 sb.append("|").append(label).append("\"");
863 evalStateCommand(sb.toString());
867 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
869 if (strInfo.equals(lastMessage))
873 lastMessage = strInfo;
876 System.err.println("Ignoring additional hover info: " + data
877 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
879 mouseOverStructure(atomIndex, strInfo);
883 * { if (history != null && strStatus != null &&
884 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
888 public void notifyAtomPicked(int atomIndex, String strInfo,
892 * this implements the toggle label behaviour copied from the original
893 * structure viewer, MCView
897 System.err.println("Ignoring additional pick data string " + strData);
899 int chainSeparator = strInfo.indexOf(":");
901 if (chainSeparator == -1)
903 chainSeparator = strInfo.indexOf(".");
906 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
908 String mdlString = "";
909 if ((p = strInfo.indexOf(":")) > -1)
911 picked += strInfo.substring(p, strInfo.indexOf("."));
914 if ((p = strInfo.indexOf("/")) > -1)
916 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
918 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
922 if (!atomsPicked.contains(picked))
924 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
925 atomsPicked.addElement(picked);
929 viewer.evalString("select " + picked + ";label off");
930 atomsPicked.removeElement(picked);
933 // TODO: in application this happens
935 // if (scriptWindow != null)
937 // scriptWindow.sendConsoleMessage(strInfo);
938 // scriptWindow.sendConsoleMessage("\n");
944 public void notifyCallback(CBK type, Object[] data)
947 * ensure processed in AWT thread to avoid risk of deadlocks
949 SwingUtilities.invokeLater(new Runnable()
955 processCallback(type, data);
961 * Processes one callback notification from Jmol
966 protected void processCallback(CBK type, Object[] data)
973 notifyFileLoaded((String) data[1], (String) data[2],
974 (String) data[3], (String) data[4],
975 ((Integer) data[5]).intValue());
979 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
981 // also highlight in alignment
982 // deliberate fall through
984 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
988 notifyScriptTermination((String) data[2],
989 ((Integer) data[3]).intValue());
992 sendConsoleEcho((String) data[1]);
996 (data == null) ? ((String) null) : (String) data[1]);
999 // System.err.println("Ignoring error callback.");
1010 "Unhandled callback " + type + " " + data[1].toString());
1013 } catch (Exception e)
1015 System.err.println("Squashed Jmol callback handler error:");
1016 e.printStackTrace();
1021 public boolean notifyEnabled(CBK callbackPick)
1023 switch (callbackPick)
1039 // incremented every time a load notification is successfully handled -
1040 // lightweight mechanism for other threads to detect when they can start
1041 // referrring to new structures.
1042 private long loadNotifiesHandled = 0;
1044 public long getLoadNotifiesHandled()
1046 return loadNotifiesHandled;
1049 public void notifyFileLoaded(String fullPathName, String fileName2,
1050 String modelName, String errorMsg, int modelParts)
1052 if (errorMsg != null)
1054 fileLoadingError = errorMsg;
1058 // TODO: deal sensibly with models loaded inLine:
1059 // modelName will be null, as will fullPathName.
1061 // the rest of this routine ignores the arguments, and simply interrogates
1062 // the Jmol view to find out what structures it contains, and adds them to
1063 // the structure selection manager.
1064 fileLoadingError = null;
1065 String[] oldmodels = modelFileNames;
1066 modelFileNames = null;
1067 chainNames = new ArrayList<>();
1068 chainFile = new Hashtable<>();
1069 boolean notifyLoaded = false;
1070 String[] modelfilenames = getStructureFiles();
1071 // first check if we've lost any structures
1072 if (oldmodels != null && oldmodels.length > 0)
1075 for (int i = 0; i < oldmodels.length; i++)
1077 for (int n = 0; n < modelfilenames.length; n++)
1079 if (modelfilenames[n] == oldmodels[i])
1081 oldmodels[i] = null;
1085 if (oldmodels[i] != null)
1092 String[] oldmfn = new String[oldm];
1094 for (int i = 0; i < oldmodels.length; i++)
1096 if (oldmodels[i] != null)
1098 oldmfn[oldm++] = oldmodels[i];
1101 // deregister the Jmol instance for these structures - we'll add
1102 // ourselves again at the end for the current structure set.
1103 getSsm().removeStructureViewerListener(this, oldmfn);
1106 refreshPdbEntries();
1107 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1109 String fileName = modelfilenames[modelnum];
1110 boolean foundEntry = false;
1111 StructureFile pdb = null;
1112 String pdbfile = null;
1113 // model was probably loaded inline - so check the pdb file hashcode
1116 // calculate essential attributes for the pdb data imported inline.
1117 // prolly need to resolve modelnumber properly - for now just use our
1119 pdbfile = viewer.getData(
1120 "" + (1 + _modelFileNameMap[modelnum]) + ".0", "PDB");
1122 // search pdbentries and sequences to find correct pdbentry for this
1124 for (int pe = 0; pe < getPdbCount(); pe++)
1126 boolean matches = false;
1127 addSequence(pe, getSequence()[pe]);
1128 if (fileName == null)
1131 // see JAL-623 - need method of matching pasted data up
1133 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1134 pdbfile, DataSourceType.PASTE, getIProgressIndicator());
1135 getPdbEntry(modelnum).setFile("INLINE" + pdb.getId());
1142 File fl = new File(getPdbEntry(pe).getFile());
1143 matches = fl.equals(new File(fileName));
1147 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1150 // to be tested. See mantis bug
1151 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1152 DataSourceType protocol = DataSourceType.URL;
1157 protocol = DataSourceType.FILE;
1159 } catch (Exception e)
1164 // Explicitly map to the filename used by Jmol ;
1165 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1166 fileName, protocol, getIProgressIndicator());
1167 // pdbentry[pe].getFile(), protocol);
1173 // add an entry for every chain in the model
1174 for (int i = 0; i < pdb.getChains().size(); i++)
1176 String chid = new String(
1177 pdb.getId() + ":" + pdb.getChains().elementAt(i).id);
1178 chainFile.put(chid, fileName);
1179 chainNames.add(chid);
1181 notifyLoaded = true;
1185 if (!foundEntry && associateNewStructs)
1187 // this is a foreign pdb file that jalview doesn't know about - add
1188 // it to the dataset and try to find a home - either on a matching
1189 // sequence or as a new sequence.
1190 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1192 // parse pdb file into a chain, etc.
1193 // locate best match for pdb in associated views and add mapping to
1195 // if properly registered then
1196 notifyLoaded = true;
1201 // so finally, update the jmol bits and pieces
1202 // if (jmolpopup != null)
1204 // // potential for deadlock here:
1205 // // jmolpopup.updateComputedMenus();
1207 if (!isLoadingFromArchive())
1209 viewer.evalStringQuiet(
1210 "model *; select backbone;restrict;cartoon;wireframe off;spacefill off");
1212 // register ourselves as a listener and notify the gui that it needs to
1214 getSsm().addStructureViewerListener(this);
1217 FeatureRenderer fr = getFeatureRenderer(null);
1220 FeatureSettingsModelI colours = new Pdb().getFeatureColourScheme();
1221 ((AppJmol) getViewer()).getAlignmentPanel().av
1222 .applyFeaturesStyle(colours);
1225 loadNotifiesHandled++;
1227 setLoadingFromArchive(false);
1231 public List<String> getChainNames()
1236 protected IProgressIndicator getIProgressIndicator()
1241 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1243 notifyAtomPicked(iatom, strMeasure, null);
1246 public abstract void notifyScriptTermination(String strStatus,
1250 * display a message echoed from the jmol viewer
1254 public abstract void sendConsoleEcho(String strEcho); /*
1255 * { showConsole(true);
1257 * history.append("\n" +
1261 // /End JmolStatusListener
1262 // /////////////////////////////
1266 * status message - usually the response received after a script
1269 public abstract void sendConsoleMessage(String strStatus);
1272 public void setCallbackFunction(String callbackType,
1273 String callbackFunction)
1275 System.err.println("Ignoring set-callback request to associate "
1276 + callbackType + " with function " + callbackFunction);
1281 public void setJalviewColourScheme(ColourSchemeI cs)
1283 colourBySequence = false;
1291 StringBuilder command = new StringBuilder(128);
1292 command.append("select *;color white;");
1293 List<String> residueSet = ResidueProperties.getResidues(isNucleotide(),
1295 for (String resName : residueSet)
1297 char res = resName.length() == 3
1298 ? ResidueProperties.getSingleCharacterCode(resName)
1299 : resName.charAt(0);
1300 Color col = cs.findColour(res, 0, null, null, 0f);
1301 command.append("select " + resName + ";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),
1379 htmlName + ((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;
1399 public void setBackgroundColour(java.awt.Color col)
1402 viewer.evalStringQuiet("background [" + col.getRed() + ","
1403 + col.getGreen() + "," + col.getBlue() + "];");
1408 public int[] resizeInnerPanel(String data)
1410 // Jalview doesn't honour resize panel requests
1417 protected void closeConsole()
1419 if (console != null)
1423 console.setVisible(false);
1426 } catch (Exception x)
1435 * ComponentListener method
1438 public void componentMoved(ComponentEvent e)
1443 * ComponentListener method
1446 public void componentResized(ComponentEvent e)
1451 * ComponentListener method
1454 public void componentShown(ComponentEvent e)
1460 * ComponentListener method
1463 public void componentHidden(ComponentEvent e)