2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3 * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
18 package jalview.ext.jmol;
20 import jalview.api.AlignmentViewPanel;
21 import jalview.api.FeatureRenderer;
22 import jalview.api.SequenceRenderer;
23 import jalview.api.SequenceStructureBinding;
24 import jalview.api.StructureSelectionManagerProvider;
25 import jalview.datamodel.AlignmentI;
26 import jalview.datamodel.ColumnSelection;
27 import jalview.datamodel.PDBEntry;
28 import jalview.datamodel.SequenceI;
29 import jalview.io.AppletFormatAdapter;
30 import jalview.schemes.ColourSchemeI;
31 import jalview.schemes.ResidueProperties;
32 import jalview.structure.StructureListener;
33 import jalview.structure.StructureMapping;
34 import jalview.structure.StructureSelectionManager;
36 import java.awt.Color;
37 import java.awt.Container;
38 import java.awt.event.ComponentEvent;
39 import java.awt.event.ComponentListener;
42 import java.security.AccessControlException;
43 import java.util.Enumeration;
44 import java.util.Hashtable;
46 import java.util.Vector;
48 import org.jmol.adapter.smarter.SmarterJmolAdapter;
49 import org.jmol.api.JmolAppConsoleInterface;
50 import org.jmol.api.JmolSelectionListener;
51 import org.jmol.api.JmolStatusListener;
52 import org.jmol.api.JmolViewer;
53 import org.jmol.constant.EnumCallback;
54 import org.jmol.popup.JmolPopup;
56 public abstract class JalviewJmolBinding implements StructureListener,
57 JmolStatusListener, SequenceStructureBinding,
58 JmolSelectionListener, ComponentListener,
59 StructureSelectionManagerProvider
63 * set if Jmol state is being restored from some source - instructs binding
64 * not to apply default display style when structure set is updated for first
67 private boolean loadingFromArchive = false;
70 * second flag to indicate if the jmol viewer should ignore sequence colouring
71 * events from the structure manager because the GUI is still setting up
73 private boolean loadingFinished = true;
76 * state flag used to check if the Jmol viewer's paint method can be called
78 private boolean finishedInit = false;
80 public boolean isFinishedInit()
85 public void setFinishedInit(boolean finishedInit)
87 this.finishedInit = finishedInit;
90 boolean allChainsSelected = false;
93 * when true, try to search the associated datamodel for sequences that are
94 * associated with any unknown structures in the Jmol view.
96 private boolean associateNewStructs = false;
98 Vector atomsPicked = new Vector();
100 public Vector chainNames;
105 * array of target chains for seuqences - tied to pdbentry and sequence[]
107 protected String[][] chains;
109 boolean colourBySequence = true;
111 StringBuffer eval = new StringBuffer();
113 public String fileLoadingError;
116 * the default or current model displayed if the model cannot be identified
117 * from the selection message
121 protected JmolPopup jmolpopup;
127 boolean loadedInline;
130 * current set of model filenames loaded in the Jmol instance
132 String[] modelFileNames = null;
134 public PDBEntry[] pdbentry;
137 * datasource protocol for access to PDBEntrylatest
139 String protocol = null;
141 StringBuffer resetLastRes = new StringBuffer();
144 * sequences mapped to each pdbentry
146 public SequenceI[][] sequence;
148 public StructureSelectionManager ssm;
150 public JmolViewer viewer;
152 public JalviewJmolBinding(StructureSelectionManager ssm,
153 PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
157 this.sequence = sequenceIs;
158 this.chains = chains;
159 this.pdbentry = pdbentry;
160 this.protocol = protocol;
163 this.chains = new String[pdbentry.length][];
166 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
167 * "jalviewJmol", ap.av.applet .getDocumentBase(),
168 * ap.av.applet.getCodeBase(), "", this);
170 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
174 public JalviewJmolBinding(StructureSelectionManager ssm,
179 viewer.setJmolStatusListener(this);
180 viewer.addSelectionListener(this);
184 * construct a title string for the viewer window based on the data jalview
189 public String getViewerTitle()
191 if (sequence == null || pdbentry == null || sequence.length < 1
192 || pdbentry.length < 1 || sequence[0].length < 1)
194 return ("Jalview Jmol Window");
196 // TODO: give a more informative title when multiple structures are
198 StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
199 + pdbentry[0].getId());
201 if (pdbentry[0].getProperty() != null)
203 if (pdbentry[0].getProperty().get("method") != null)
205 title.append(" Method: ");
206 title.append(pdbentry[0].getProperty().get("method"));
208 if (pdbentry[0].getProperty().get("chains") != null)
210 title.append(" Chain:");
211 title.append(pdbentry[0].getProperty().get("chains"));
214 return title.toString();
218 * prepare the view for a given set of models/chains. chainList contains
219 * strings of the form 'pdbfilename:Chaincode'
222 * list of chains to make visible
224 public void centerViewer(Vector chainList)
226 StringBuffer cmd = new StringBuffer();
229 for (int i = 0, iSize = chainList.size(); i < iSize; i++)
232 lbl = (String) chainList.elementAt(i);
236 mlength = lbl.indexOf(":", p);
237 } while (p < mlength && mlength < (lbl.length() - 2));
238 // TODO: lookup each pdb id and recover proper model number for it.
239 cmd.append(":" + lbl.substring(mlength + 1) + " /"
240 + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");
242 if (cmd.length() > 0)
243 cmd.setLength(cmd.length() - 4);
244 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
247 public void closeViewer()
249 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
250 // remove listeners for all structures in viewer
251 ssm.removeStructureViewerListener(this, this.getPdbFile());
252 // and shut down jmol
253 viewer.evalStringQuiet("zap");
254 viewer.setJmolStatusListener(null);
257 releaseUIResources();
261 * called by JalviewJmolbinding after closeViewer is called - release any
262 * resources and references so they can be garbage collected.
264 protected abstract void releaseUIResources();
266 public void colourByChain()
268 colourBySequence = false;
269 // TODO: colour by chain should colour each chain distinctly across all
271 // TODO: http://issues.jalview.org/browse/JAL-628
272 evalStateCommand("select *;color chain");
275 public void colourByCharge()
277 colourBySequence = false;
278 evalStateCommand("select *;color white;select ASP,GLU;color red;"
279 + "select LYS,ARG;color blue;select CYS;color yellow");
283 * superpose the structures associated with sequences in the alignment
284 * according to their corresponding positions.
286 public void superposeStructures(AlignmentI alignment)
288 superposeStructures(alignment, -1, null);
292 * superpose the structures associated with sequences in the alignment
293 * according to their corresponding positions. ded)
295 * @param refStructure
296 * - select which pdb file to use as reference (default is -1 - the
297 * first structure in the alignment)
299 public void superposeStructures(AlignmentI alignment, int refStructure)
301 superposeStructures(alignment, refStructure, null);
305 * superpose the structures associated with sequences in the alignment
306 * according to their corresponding positions. ded)
308 * @param refStructure
309 * - select which pdb file to use as reference (default is -1 - the
310 * first structure in the alignment)
314 public void superposeStructures(AlignmentI alignment, int refStructure,
315 ColumnSelection hiddenCols)
317 superposeStructures(new AlignmentI[]
318 { alignment }, new int[]
319 { refStructure }, new ColumnSelection[]
323 public void superposeStructures(AlignmentI[] _alignment,
324 int[] _refStructure, ColumnSelection[] _hiddenCols)
326 assert (_alignment.length == _refStructure.length && _alignment.length != _hiddenCols.length);
328 String[] files = getPdbFile();
329 StringBuffer selectioncom = new StringBuffer();
330 // union of all aligned positions are collected together.
331 for (int a = 0; a < _alignment.length; a++)
333 int refStructure = _refStructure[a];
334 AlignmentI alignment = _alignment[a];
335 ColumnSelection hiddenCols = _hiddenCols[a];
337 && selectioncom.length() > 0
338 && !selectioncom.substring(selectioncom.length() - 1).equals(
341 selectioncom.append("|");
343 // process this alignment
344 if (refStructure >= files.length)
346 System.err.println("Invalid reference structure value "
350 if (refStructure < -1)
354 StringBuffer command = new StringBuffer();
356 boolean matched[] = new boolean[alignment.getWidth()];
357 for (int m = 0; m < matched.length; m++)
360 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
363 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
364 String isel[] = new String[files.length];
365 // reference structure - all others are superposed in it
366 String[] targetC = new String[files.length];
367 String[] chainNames = new String[files.length];
368 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
370 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
371 // RACE CONDITION - getMapping only returns Jmol loaded filenames once
372 // Jmol callback has completed.
373 if (mapping == null || mapping.length < 1)
377 for (int s = 0; s < sequence[pdbfnum].length; s++)
379 for (int sp, m = 0; m < mapping.length; m++)
381 if (mapping[m].getSequence() == sequence[pdbfnum][s]
382 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
384 if (refStructure == -1)
386 refStructure = pdbfnum;
388 SequenceI asp = alignment.getSequenceAt(sp);
389 for (int r = 0; r < matched.length; r++)
395 matched[r] = false; // assume this is not a good site
396 if (r >= asp.getLength())
401 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
403 // no mapping to gaps in sequence
406 int t = asp.findPosition(r); // sequence position
407 int apos = mapping[m].getAtomNum(t);
408 int pos = mapping[m].getPDBResNum(t);
410 if (pos < 1 || pos == lastPos)
412 // can't align unmapped sequence
415 matched[r] = true; // this is a good ite
417 // just record this residue position
418 commonrpositions[pdbfnum][r] = pos;
420 // create model selection suffix
421 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
422 if (mapping[m].getChain() == null
423 || mapping[m].getChain().trim().length() == 0)
425 targetC[pdbfnum] = "";
429 targetC[pdbfnum] = ":" + mapping[m].getChain();
431 chainNames[pdbfnum] = mapping[m].getPdbId()
433 // move on to next pdb file
434 s = sequence[pdbfnum].length;
440 String[] selcom = new String[files.length];
442 // generate select statements to select regions to superimpose structures
444 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
446 String chainCd = targetC[pdbfnum];
449 StringBuffer molsel = new StringBuffer();
451 for (int r = 0; r < matched.length; r++)
459 if (lpos != commonrpositions[pdbfnum][r] - 1)
465 molsel.append(chainCd);
466 // molsel.append("} {");
472 // continuous run - and lpos >-1
475 // at the beginning, so add dash
481 lpos = commonrpositions[pdbfnum][r];
482 // molsel.append(lpos);
485 // add final selection phrase
489 molsel.append(chainCd);
492 selcom[pdbfnum] = molsel.toString();
493 selectioncom.append("((");
494 selectioncom.append(selcom[pdbfnum].substring(1,
495 selcom[pdbfnum].length() - 1));
496 selectioncom.append(" )& ");
497 selectioncom.append(pdbfnum + 1);
498 selectioncom.append(".1)");
499 if (pdbfnum < files.length - 1)
501 selectioncom.append("|");
505 // TODO: consider bailing if nmatched less than 4 because superposition
508 // TODO: refactor superposable position search (above) from jmol selection
509 // construction (below)
510 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
512 if (pdbfnum == refStructure)
516 command.append("echo ");
517 command.append("\"Superposing (");
518 command.append(chainNames[pdbfnum]);
519 command.append(") against reference (");
520 command.append(chainNames[refStructure]);
521 command.append(")\";\ncompare ");
523 command.append(1 + pdbfnum);
524 command.append(".1} {");
525 command.append(1 + refStructure);
526 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
528 // form the matched pair strings
530 for (int s = 0; s < 2; s++)
532 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
534 command.append(" ROTATE TRANSLATE;\n");
536 System.out.println("Select regions:\n" + selectioncom.toString());
537 evalStateCommand("select *; cartoons off; backbone; select ("
538 + selectioncom.toString() + "); cartoons; ");
539 // selcom.append("; ribbons; ");
540 System.out.println("Superimpose command(s):\n" + command.toString());
542 evalStateCommand(command.toString());
544 if (selectioncom.length() > 0)
545 {// finally, mark all regions that were superposed.
546 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
548 selectioncom.setLength(selectioncom.length() - 1);
550 System.out.println("Select regions:\n" + selectioncom.toString());
551 evalStateCommand("select *; cartoons off; backbone; select ("
552 + selectioncom.toString() + "); cartoons; ");
553 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
557 public void evalStateCommand(String command)
560 if (lastCommand == null || !lastCommand.equals(command))
562 viewer.evalStringQuiet(command + "\n");
565 lastCommand = command;
569 * colour any structures associated with sequences in the given alignment
570 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
571 * if colourBySequence is enabled.
573 public void colourBySequence(boolean showFeatures,
574 jalview.api.AlignmentViewPanel alignmentv)
576 if (!colourBySequence || !loadingFinished)
582 String[] files = getPdbFile();
584 SequenceRenderer sr = getSequenceRenderer(alignmentv);
586 FeatureRenderer fr = null;
589 fr = getFeatureRenderer(alignmentv);
591 AlignmentI alignment = alignmentv.getAlignment();
593 for (jalview.structure.StructureMappingcommandSet cpdbbyseq : JmolCommands
594 .getColourBySequenceCommand(ssm, files, sequence, sr, fr,
596 for (String cbyseq : cpdbbyseq.commands)
598 evalStateCommand(cbyseq);
602 public boolean isColourBySequence()
604 return colourBySequence;
607 public void setColourBySequence(boolean colourBySequence)
609 this.colourBySequence = colourBySequence;
612 public void createImage(String file, String type, int quality)
614 System.out.println("JMOL CREATE IMAGE");
617 public String createImage(String fileName, String type,
618 Object textOrBytes, int quality)
620 System.out.println("JMOL CREATE IMAGE");
624 public String eval(String strEval)
626 // System.out.println(strEval);
627 // "# 'eval' is implemented only for the applet.";
631 // End StructureListener
632 // //////////////////////////
634 public float[][] functionXY(String functionName, int x, int y)
639 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
641 // TODO Auto-generated method stub
645 public Color getColour(int atomIndex, int pdbResNum, String chain,
648 if (getModelNum(pdbfile) < 0)
650 // TODO: verify atomIndex is selecting correct model.
651 return new Color(viewer.getAtomArgb(atomIndex));
655 * returns the current featureRenderer that should be used to colour the
662 public abstract FeatureRenderer getFeatureRenderer(
663 AlignmentViewPanel alignment);
666 * instruct the Jalview binding to update the pdbentries vector if necessary
667 * prior to matching the jmol view's contents to the list of structure files
668 * Jalview knows about.
670 public abstract void refreshPdbEntries();
672 private int getModelNum(String modelFileName)
674 String[] mfn = getPdbFile();
679 for (int i = 0; i < mfn.length; i++)
681 if (mfn[i].equalsIgnoreCase(modelFileName))
688 * map between index of model filename returned from getPdbFile and the first
689 * index of models from this file in the viewer. Note - this is not trimmed -
690 * use getPdbFile to get number of unique models.
692 private int _modelFileNameMap[];
694 // ////////////////////////////////
695 // /StructureListener
696 public synchronized String[] getPdbFile()
700 return new String[0];
702 if (modelFileNames == null)
705 String mset[] = new String[viewer.getModelCount()];
706 _modelFileNameMap = new int[mset.length];
708 String m = viewer.getModelFileName(0);
713 mset[0] = new File(m).getAbsolutePath();
714 } catch (AccessControlException x)
716 // usually not allowed to do this in applet, so keep raw handle
718 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
721 for (int i = 1; i < mset.length; i++)
723 m = viewer.getModelFileName(i);
728 mset[j] = new File(m).getAbsolutePath();
729 } catch (AccessControlException x)
731 // usually not allowed to do this in applet, so keep raw handle
733 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
736 _modelFileNameMap[j] = i; // record the model index for the filename
737 // skip any additional models in the same file (NMR structures)
738 if ((mset[j] == null ? mset[j] != mset[j - 1]
739 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
744 modelFileNames = new String[j];
745 System.arraycopy(mset, 0, modelFileNames, 0, j);
747 return modelFileNames;
751 * map from string to applet
753 public Map getRegistryInfo()
755 // TODO Auto-generated method stub
760 * returns the current sequenceRenderer that should be used to colour the
767 public abstract SequenceRenderer getSequenceRenderer(
768 AlignmentViewPanel alignment);
770 // ///////////////////////////////
771 // JmolStatusListener
773 public void handlePopupMenu(int x, int y)
775 jmolpopup.show(x, y);
779 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
782 if (modelFileNames == null)
787 // look up file model number for this pdbfile
790 // may need to adjust for URLencoding here - we don't worry about that yet.
791 while (mdlNum < modelFileNames.length
792 && !pdbfile.equals(modelFileNames[mdlNum]))
794 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
797 if (mdlNum == modelFileNames.length)
803 // if (!pdbfile.equals(pdbentry.getFile()))
805 if (resetLastRes.length() > 0)
807 viewer.evalStringQuiet(resetLastRes.toString());
811 eval.append("select " + pdbResNum); // +modelNum
813 resetLastRes.setLength(0);
814 resetLastRes.append("select " + pdbResNum); // +modelNum
817 resetLastRes.append(":");
818 if (!chain.equals(" "))
821 resetLastRes.append(chain);
824 eval.append(" /" + (mdlNum + 1));
825 resetLastRes.append("/" + (mdlNum + 1));
827 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
829 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
830 + " and not hetero; spacefill 0;");
832 eval.append("spacefill 200;select none");
834 viewer.evalStringQuiet(eval.toString());
839 boolean debug = true;
841 private void jmolHistory(boolean enable)
843 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
846 public void loadInline(String string)
850 // viewer.loadInline(strModel, isAppend);
852 // construct fake fullPathName and fileName so we can identify the file
854 // Then, construct pass a reader for the string to Jmol.
855 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
856 // fileName, null, reader, false, null, null, 0);
857 viewer.openStringInline(string);
860 public void mouseOverStructure(int atomIndex, String strInfo)
863 int alocsep = strInfo.indexOf("^");
864 int mdlSep = strInfo.indexOf("/");
865 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
867 if (chainSeparator == -1)
869 chainSeparator = strInfo.indexOf(".");
870 if (mdlSep > -1 && mdlSep < chainSeparator)
872 chainSeparator1 = chainSeparator;
873 chainSeparator = mdlSep;
876 // handle insertion codes
879 pdbResNum = Integer.parseInt(strInfo.substring(
880 strInfo.indexOf("]") + 1, alocsep));
885 pdbResNum = Integer.parseInt(strInfo.substring(
886 strInfo.indexOf("]") + 1, chainSeparator));
890 if (strInfo.indexOf(":") > -1)
891 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
892 strInfo.indexOf("."));
898 String pdbfilename = modelFileNames[frameNo]; // default is first or current
902 if (chainSeparator1 == -1)
904 chainSeparator1 = strInfo.indexOf(".", mdlSep);
906 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
907 chainSeparator1) : strInfo.substring(mdlSep + 1);
910 // recover PDB filename for the model hovered over.
911 int _mp = _modelFileNameMap.length - 1, mnumber = new Integer(mdlId)
913 while (mnumber < _modelFileNameMap[_mp])
917 pdbfilename = modelFileNames[_mp];
918 if (pdbfilename == null)
920 pdbfilename = new File(viewer.getModelFileName(mnumber))
924 } catch (Exception e)
929 if (lastMessage == null || !lastMessage.equals(strInfo))
930 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
932 lastMessage = strInfo;
935 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
939 System.err.println("Ignoring additional hover info: " + data
940 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
942 mouseOverStructure(atomIndex, strInfo);
946 * { if (history != null && strStatus != null &&
947 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
951 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
954 * this implements the toggle label behaviour copied from the original
955 * structure viewer, MCView
959 System.err.println("Ignoring additional pick data string " + strData);
961 int chainSeparator = strInfo.indexOf(":");
963 if (chainSeparator == -1)
964 chainSeparator = strInfo.indexOf(".");
966 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
968 String mdlString = "";
969 if ((p = strInfo.indexOf(":")) > -1)
970 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
972 if ((p = strInfo.indexOf("/")) > -1)
974 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
976 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
980 if (!atomsPicked.contains(picked))
982 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
983 atomsPicked.addElement(picked);
987 viewer.evalString("select " + picked + ";label off");
988 atomsPicked.removeElement(picked);
991 // TODO: in application this happens
993 // if (scriptWindow != null)
995 // scriptWindow.sendConsoleMessage(strInfo);
996 // scriptWindow.sendConsoleMessage("\n");
1002 public void notifyCallback(EnumCallback type, Object[] data)
1009 notifyFileLoaded((String) data[1], (String) data[2],
1010 (String) data[3], (String) data[4],
1011 ((Integer) data[5]).intValue());
1015 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
1017 // also highlight in alignment
1019 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1023 notifyScriptTermination((String) data[2],
1024 ((Integer) data[3]).intValue());
1027 sendConsoleEcho((String) data[1]);
1030 sendConsoleMessage((data == null) ? ((String) null)
1031 : (String) data[1]);
1034 // System.err.println("Ignoring error callback.");
1044 System.err.println("Unhandled callback " + type + " "
1045 + data[1].toString());
1048 } catch (Exception e)
1050 System.err.println("Squashed Jmol callback handler error:");
1051 e.printStackTrace();
1056 public boolean notifyEnabled(EnumCallback callbackPick)
1058 switch (callbackPick)
1078 // incremented every time a load notification is successfully handled -
1079 // lightweight mechanism for other threads to detect when they can start
1080 // referrring to new structures.
1081 private long loadNotifiesHandled = 0;
1083 public long getLoadNotifiesHandled()
1085 return loadNotifiesHandled;
1088 public void notifyFileLoaded(String fullPathName, String fileName2,
1089 String modelName, String errorMsg, int modelParts)
1091 if (errorMsg != null)
1093 fileLoadingError = errorMsg;
1097 // TODO: deal sensibly with models loaded inLine:
1098 // modelName will be null, as will fullPathName.
1100 // the rest of this routine ignores the arguments, and simply interrogates
1101 // the Jmol view to find out what structures it contains, and adds them to
1102 // the structure selection manager.
1103 fileLoadingError = null;
1104 String[] oldmodels = modelFileNames;
1105 modelFileNames = null;
1106 chainNames = new Vector();
1107 chainFile = new Hashtable();
1108 boolean notifyLoaded = false;
1109 String[] modelfilenames = getPdbFile();
1110 // first check if we've lost any structures
1111 if (oldmodels != null && oldmodels.length > 0)
1114 for (int i = 0; i < oldmodels.length; i++)
1116 for (int n = 0; n < modelfilenames.length; n++)
1118 if (modelfilenames[n] == oldmodels[i])
1120 oldmodels[i] = null;
1124 if (oldmodels[i] != null)
1131 String[] oldmfn = new String[oldm];
1133 for (int i = 0; i < oldmodels.length; i++)
1135 if (oldmodels[i] != null)
1137 oldmfn[oldm++] = oldmodels[i];
1140 // deregister the Jmol instance for these structures - we'll add
1141 // ourselves again at the end for the current structure set.
1142 ssm.removeStructureViewerListener(this, oldmfn);
1145 refreshPdbEntries();
1146 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1148 String fileName = modelfilenames[modelnum];
1149 boolean foundEntry = false;
1150 MCview.PDBfile pdb = null;
1151 String pdbfile = null, pdbfhash = null;
1152 // model was probably loaded inline - so check the pdb file hashcode
1155 // calculate essential attributes for the pdb data imported inline.
1156 // prolly need to resolve modelnumber properly - for now just use our
1158 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1160 pdbfhash = "" + pdbfile.hashCode();
1162 if (pdbentry != null)
1164 // search pdbentries and sequences to find correct pdbentry for this
1166 for (int pe = 0; pe < pdbentry.length; pe++)
1168 boolean matches = false;
1169 if (fileName == null)
1172 // see JAL-623 - need method of matching pasted data up
1174 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
1175 AppletFormatAdapter.PASTE);
1176 pdbentry[modelnum].setFile("INLINE" + pdb.id);
1184 if (matches = (fl = new File(pdbentry[pe].getFile()))
1185 .equals(new File(fileName)))
1188 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1191 // to be tested. See mantis bug
1192 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1193 String protocol = AppletFormatAdapter.URL;
1198 protocol = AppletFormatAdapter.FILE;
1200 } catch (Exception e)
1205 // Explicitly map to the filename used by Jmol ;
1206 pdb = ssm.setMapping(sequence[pe], chains[pe], fileName,
1208 // pdbentry[pe].getFile(), protocol);
1214 // add an entry for every chain in the model
1215 for (int i = 0; i < pdb.chains.size(); i++)
1217 String chid = new String(pdb.id + ":"
1218 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
1219 chainFile.put(chid, fileName);
1220 chainNames.addElement(chid);
1222 notifyLoaded = true;
1226 if (!foundEntry && associateNewStructs)
1228 // this is a foreign pdb file that jalview doesn't know about - add
1229 // it to the dataset and try to find a home - either on a matching
1230 // sequence or as a new sequence.
1231 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1233 // parse pdb file into a chain, etc.
1234 // locate best match for pdb in associated views and add mapping to
1236 // if properly registered then
1237 notifyLoaded = true;
1242 // so finally, update the jmol bits and pieces
1243 if (jmolpopup != null)
1245 // potential for deadlock here:
1246 // jmolpopup.updateComputedMenus();
1248 if (!isLoadingFromArchive())
1250 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1252 // register ourselves as a listener and notify the gui that it needs to
1254 ssm.addStructureViewerListener(this);
1257 FeatureRenderer fr = getFeatureRenderer(null);
1263 loadNotifiesHandled++;
1265 setLoadingFromArchive(false);
1268 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1270 notifyAtomPicked(iatom, strMeasure, null);
1273 public abstract void notifyScriptTermination(String strStatus,
1277 * display a message echoed from the jmol viewer
1281 public abstract void sendConsoleEcho(String strEcho); /*
1282 * { showConsole(true);
1284 * history.append("\n" +
1288 // /End JmolStatusListener
1289 // /////////////////////////////
1293 * status message - usually the response received after a script
1296 public abstract void sendConsoleMessage(String strStatus);
1298 public void setCallbackFunction(String callbackType,
1299 String callbackFunction)
1301 System.err.println("Ignoring set-callback request to associate "
1302 + callbackType + " with function " + callbackFunction);
1306 public void setJalviewColourScheme(ColourSchemeI cs)
1308 colourBySequence = false;
1317 // TODO: Switch between nucleotide or aa selection expressions
1318 Enumeration en = ResidueProperties.aa3Hash.keys();
1319 StringBuffer command = new StringBuffer("select *;color white;");
1320 while (en.hasMoreElements())
1322 res = en.nextElement().toString();
1323 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
1327 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
1329 command.append("select " + res + ";color[" + col.getRed() + ","
1330 + col.getGreen() + "," + col.getBlue() + "];");
1333 evalStateCommand(command.toString());
1337 public void showHelp()
1339 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1343 * open the URL somehow
1347 public abstract void showUrl(String url, String target);
1350 * called when the binding thinks the UI needs to be refreshed after a Jmol
1351 * state change. this could be because structures were loaded, or because an
1352 * error has occured.
1354 public abstract void refreshGUI();
1357 * called to show or hide the associated console window container.
1361 public abstract void showConsole(boolean show);
1364 * @param renderPanel
1366 * - when true will initialise jmol's file IO system (should be false
1367 * in applet context)
1369 * @param documentBase
1371 * @param commandOptions
1373 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1374 String htmlName, URL documentBase, URL codeBase,
1375 String commandOptions)
1377 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1378 codeBase, commandOptions, null, null);
1383 * @param renderPanel
1385 * - when true will initialise jmol's file IO system (should be false
1386 * in applet context)
1388 * @param documentBase
1390 * @param commandOptions
1391 * @param consolePanel
1392 * - panel to contain Jmol console
1393 * @param buttonsToShow
1394 * - buttons to show on the console, in ordr
1396 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1397 String htmlName, URL documentBase, URL codeBase,
1398 String commandOptions, final Container consolePanel,
1399 String buttonsToShow)
1401 if (commandOptions == null)
1403 commandOptions = "";
1405 viewer = JmolViewer.allocateViewer(renderPanel,
1406 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1407 + ((Object) this).toString(), documentBase, codeBase,
1408 commandOptions, this);
1410 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
1411 if (consolePanel != null)
1413 consolePanel.addComponentListener(this);
1419 protected abstract JmolAppConsoleInterface createJmolConsole(
1420 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
1422 protected org.jmol.api.JmolAppConsoleInterface console = null;
1424 public void componentResized(ComponentEvent e)
1429 public void componentMoved(ComponentEvent e)
1434 public void componentShown(ComponentEvent e)
1439 public void componentHidden(ComponentEvent e)
1444 public void setLoadingFromArchive(boolean loadingFromArchive)
1446 this.loadingFromArchive = loadingFromArchive;
1451 * @return true if Jmol is still restoring state or loading is still going on (see setFinsihedLoadingFromArchive)
1453 public boolean isLoadingFromArchive()
1455 return loadingFromArchive && !loadingFinished;
1459 * modify flag which controls if sequence colouring events are honoured by the binding.
1460 * Should be true for normal operation
1461 * @param finishedLoading
1463 public void setFinishedLoadingFromArchive(boolean finishedLoading)
1465 loadingFinished = finishedLoading;
1468 public void setBackgroundColour(java.awt.Color col)
1471 viewer.evalStringQuiet("background [" + col.getRed() + ","
1472 + col.getGreen() + "," + col.getBlue() + "];");
1477 * add structures and any known sequence associations
1479 * @returns the pdb entries added to the current set.
1481 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
1482 SequenceI[][] seq, String[][] chns)
1485 Vector v = new Vector();
1486 Vector rtn = new Vector();
1487 for (int i = 0; i < pdbentry.length; i++)
1489 v.addElement(pdbentry[i]);
1491 for (int i = 0; i < pdbe.length; i++)
1493 int r = v.indexOf(pdbe[i]);
1494 if (r == -1 || r >= pdbentry.length)
1496 rtn.addElement(new int[]
1498 v.addElement(pdbe[i]);
1502 // just make sure the sequence/chain entries are all up to date
1503 addSequenceAndChain(r, seq[i], chns[i]);
1506 pdbe = new PDBEntry[v.size()];
1511 // expand the tied seuqence[] and string[] arrays
1512 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
1513 String[][] sch = new String[pdbentry.length][];
1514 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
1515 System.arraycopy(chains, 0, sch, 0, this.chains.length);
1518 pdbe = new PDBEntry[rtn.size()];
1519 for (int r = 0; r < pdbe.length; r++)
1521 int[] stri = ((int[]) rtn.elementAt(r));
1522 // record the pdb file as a new addition
1523 pdbe[r] = pdbentry[stri[0]];
1524 // and add the new sequence/chain entries
1525 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
1535 public void addSequence(int pe, SequenceI[] seq)
1537 // add sequences to the pe'th pdbentry's seuqence set.
1538 addSequenceAndChain(pe, seq, null);
1541 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
1543 if (pe < 0 || pe >= pdbentry.length)
1546 "Implementation error - no corresponding pdbentry (for index "
1547 + pe + ") to add sequences mappings to");
1549 final String nullChain = "TheNullChain";
1550 Vector s = new Vector();
1551 Vector c = new Vector();
1554 chains = new String[pdbentry.length][];
1556 if (sequence[pe] != null)
1558 for (int i = 0; i < sequence[pe].length; i++)
1560 s.addElement(sequence[pe][i]);
1561 if (chains[pe] != null)
1563 if (i < chains[pe].length)
1565 c.addElement(chains[pe][i]);
1569 c.addElement(nullChain);
1574 if (tchain != null && tchain.length > 0)
1576 c.addElement(nullChain);
1581 for (int i = 0; i < seq.length; i++)
1583 if (!s.contains(seq[i]))
1585 s.addElement(seq[i]);
1586 if (tchain != null && i < tchain.length)
1588 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
1592 SequenceI[] tmp = new SequenceI[s.size()];
1597 String[] tch = new String[c.size()];
1599 for (int i = 0; i < tch.length; i++)
1601 if (tch[i] == nullChain)
1617 * @return text report of alignment between pdbfile and any associated
1618 * alignment sequences
1620 public String printMapping(String pdbfile)
1622 return ssm.printMapping(pdbfile);
1626 public void resizeInnerPanel(String data)
1628 // Jalview doesn't honour resize panel requests