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 String[] files = getPdbFile();
327 StringBuffer selectioncom = new StringBuffer();
328 assert (_alignment.length == _refStructure.length && _alignment.length != _hiddenCols.length);
329 // union of all aligned positions are collected together.
330 for (int a = 0; a < _alignment.length; a++)
332 int refStructure = _refStructure[a];
333 AlignmentI alignment = _alignment[a];
334 ColumnSelection hiddenCols = _hiddenCols[a];
336 && selectioncom.length() > 0
337 && !selectioncom.substring(selectioncom.length() - 1).equals(
340 selectioncom.append("|");
342 // process this alignment
343 if (refStructure >= files.length)
345 System.err.println("Invalid reference structure value "
349 if (refStructure < -1)
353 StringBuffer command = new StringBuffer();
355 boolean matched[] = new boolean[alignment.getWidth()];
356 for (int m = 0; m < matched.length; m++)
359 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
362 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
363 String isel[] = new String[files.length];
364 // reference structure - all others are superposed in it
365 String[] targetC = new String[files.length];
366 String[] chainNames = new String[files.length];
367 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
369 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
370 // RACE CONDITION - getMapping only returns Jmol loaded filenames once
371 // Jmol callback has completed.
372 if (mapping == null || mapping.length < 1)
376 for (int s = 0; s < sequence[pdbfnum].length; s++)
378 for (int sp, m = 0; m < mapping.length; m++)
380 if (mapping[m].getSequence() == sequence[pdbfnum][s]
381 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
383 if (refStructure == -1)
385 refStructure = pdbfnum;
387 SequenceI asp = alignment.getSequenceAt(sp);
388 for (int r = 0; r < matched.length; r++)
394 matched[r] = false; // assume this is not a good site
395 if (r >= asp.getLength())
400 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
402 // no mapping to gaps in sequence
405 int t = asp.findPosition(r); // sequence position
406 int apos = mapping[m].getAtomNum(t);
407 int pos = mapping[m].getPDBResNum(t);
409 if (pos < 1 || pos == lastPos)
411 // can't align unmapped sequence
414 matched[r] = true; // this is a good ite
416 // just record this residue position
417 commonrpositions[pdbfnum][r] = pos;
419 // create model selection suffix
420 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
421 if (mapping[m].getChain() == null
422 || mapping[m].getChain().trim().length() == 0)
424 targetC[pdbfnum] = "";
428 targetC[pdbfnum] = ":" + mapping[m].getChain();
430 chainNames[pdbfnum] = mapping[m].getPdbId()
432 // move on to next pdb file
433 s = sequence[pdbfnum].length;
439 String[] selcom = new String[files.length];
441 // generate select statements to select regions to superimpose structures
443 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
445 String chainCd = targetC[pdbfnum];
448 StringBuffer molsel = new StringBuffer();
450 for (int r = 0; r < matched.length; r++)
458 if (lpos != commonrpositions[pdbfnum][r] - 1)
464 molsel.append(chainCd);
465 // molsel.append("} {");
471 // continuous run - and lpos >-1
474 // at the beginning, so add dash
480 lpos = commonrpositions[pdbfnum][r];
481 // molsel.append(lpos);
484 // add final selection phrase
488 molsel.append(chainCd);
491 selcom[pdbfnum] = molsel.toString();
492 selectioncom.append("((");
493 selectioncom.append(selcom[pdbfnum].substring(1,
494 selcom[pdbfnum].length() - 1));
495 selectioncom.append(" )& ");
496 selectioncom.append(pdbfnum + 1);
497 selectioncom.append(".1)");
498 if (pdbfnum < files.length - 1)
500 selectioncom.append("|");
504 // TODO: consider bailing if nmatched less than 4 because superposition
507 // TODO: refactor superposable position search (above) from jmol selection
508 // construction (below)
509 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
511 if (pdbfnum == refStructure)
515 command.append("echo ");
516 command.append("\"Superposing (");
517 command.append(chainNames[pdbfnum]);
518 command.append(") against reference (");
519 command.append(chainNames[refStructure]);
520 command.append(")\";\ncompare ");
522 command.append(1 + pdbfnum);
523 command.append(".1} {");
524 command.append(1 + refStructure);
525 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
527 // form the matched pair strings
529 for (int s = 0; s < 2; s++)
531 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
533 command.append(" ROTATE TRANSLATE;\n");
535 System.out.println("Select regions:\n" + selectioncom.toString());
536 evalStateCommand("select *; cartoons off; backbone; select ("
537 + selectioncom.toString() + "); cartoons; ");
538 // selcom.append("; ribbons; ");
539 System.out.println("Superimpose command(s):\n" + command.toString());
541 evalStateCommand(command.toString());
543 if (selectioncom.length() > 0)
544 {// finally, mark all regions that were superposed.
545 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
547 selectioncom.setLength(selectioncom.length() - 1);
549 System.out.println("Select regions:\n" + selectioncom.toString());
550 evalStateCommand("select *; cartoons off; backbone; select ("
551 + selectioncom.toString() + "); cartoons; ");
552 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
556 public void evalStateCommand(String command)
559 if (lastCommand == null || !lastCommand.equals(command))
561 viewer.evalStringQuiet(command + "\n");
564 lastCommand = command;
568 * colour any structures associated with sequences in the given alignment
569 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
570 * if colourBySequence is enabled.
572 public void colourBySequence(boolean showFeatures,
573 jalview.api.AlignmentViewPanel alignmentv)
575 if (!colourBySequence || !loadingFinished)
581 String[] files = getPdbFile();
583 SequenceRenderer sr = getSequenceRenderer(alignmentv);
585 FeatureRenderer fr = null;
588 fr = getFeatureRenderer(alignmentv);
590 AlignmentI alignment = alignmentv.getAlignment();
592 for (jalview.structure.StructureMappingcommandSet cpdbbyseq : JmolCommands
593 .getColourBySequenceCommand(ssm, files, sequence, sr, fr,
595 for (String cbyseq : cpdbbyseq.commands)
597 evalStateCommand(cbyseq);
601 public boolean isColourBySequence()
603 return colourBySequence;
606 public void setColourBySequence(boolean colourBySequence)
608 this.colourBySequence = colourBySequence;
611 public void createImage(String file, String type, int quality)
613 System.out.println("JMOL CREATE IMAGE");
616 public String createImage(String fileName, String type,
617 Object textOrBytes, int quality)
619 System.out.println("JMOL CREATE IMAGE");
623 public String eval(String strEval)
625 // System.out.println(strEval);
626 // "# 'eval' is implemented only for the applet.";
630 // End StructureListener
631 // //////////////////////////
633 public float[][] functionXY(String functionName, int x, int y)
638 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
640 // TODO Auto-generated method stub
644 public Color getColour(int atomIndex, int pdbResNum, String chain,
647 if (getModelNum(pdbfile) < 0)
649 // TODO: verify atomIndex is selecting correct model.
650 return new Color(viewer.getAtomArgb(atomIndex));
654 * returns the current featureRenderer that should be used to colour the
661 public abstract FeatureRenderer getFeatureRenderer(
662 AlignmentViewPanel alignment);
665 * instruct the Jalview binding to update the pdbentries vector if necessary
666 * prior to matching the jmol view's contents to the list of structure files
667 * Jalview knows about.
669 public abstract void refreshPdbEntries();
671 private int getModelNum(String modelFileName)
673 String[] mfn = getPdbFile();
678 for (int i = 0; i < mfn.length; i++)
680 if (mfn[i].equalsIgnoreCase(modelFileName))
687 * map between index of model filename returned from getPdbFile and the first
688 * index of models from this file in the viewer. Note - this is not trimmed -
689 * use getPdbFile to get number of unique models.
691 private int _modelFileNameMap[];
693 // ////////////////////////////////
694 // /StructureListener
695 public synchronized String[] getPdbFile()
699 return new String[0];
701 if (modelFileNames == null)
704 String mset[] = new String[viewer.getModelCount()];
705 _modelFileNameMap = new int[mset.length];
707 String m = viewer.getModelFileName(0);
712 mset[0] = new File(m).getAbsolutePath();
713 } catch (AccessControlException x)
715 // usually not allowed to do this in applet, so keep raw handle
717 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
720 for (int i = 1; i < mset.length; i++)
722 m = viewer.getModelFileName(i);
727 mset[j] = new File(m).getAbsolutePath();
728 } catch (AccessControlException x)
730 // usually not allowed to do this in applet, so keep raw handle
732 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
735 _modelFileNameMap[j] = i; // record the model index for the filename
736 // skip any additional models in the same file (NMR structures)
737 if ((mset[j] == null ? mset[j] != mset[j - 1]
738 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
743 modelFileNames = new String[j];
744 System.arraycopy(mset, 0, modelFileNames, 0, j);
746 return modelFileNames;
750 * map from string to applet
752 public Map getRegistryInfo()
754 // TODO Auto-generated method stub
759 * returns the current sequenceRenderer that should be used to colour the
766 public abstract SequenceRenderer getSequenceRenderer(
767 AlignmentViewPanel alignment);
769 // ///////////////////////////////
770 // JmolStatusListener
772 public void handlePopupMenu(int x, int y)
774 jmolpopup.show(x, y);
778 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
781 if (modelFileNames == null)
786 // look up file model number for this pdbfile
789 // may need to adjust for URLencoding here - we don't worry about that yet.
790 while (mdlNum < modelFileNames.length
791 && !pdbfile.equals(modelFileNames[mdlNum]))
793 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
796 if (mdlNum == modelFileNames.length)
802 // if (!pdbfile.equals(pdbentry.getFile()))
804 if (resetLastRes.length() > 0)
806 viewer.evalStringQuiet(resetLastRes.toString());
810 eval.append("select " + pdbResNum); // +modelNum
812 resetLastRes.setLength(0);
813 resetLastRes.append("select " + pdbResNum); // +modelNum
816 resetLastRes.append(":");
817 if (!chain.equals(" "))
820 resetLastRes.append(chain);
823 eval.append(" /" + (mdlNum + 1));
824 resetLastRes.append("/" + (mdlNum + 1));
826 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
828 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
829 + " and not hetero; spacefill 0;");
831 eval.append("spacefill 200;select none");
833 viewer.evalStringQuiet(eval.toString());
838 boolean debug = true;
840 private void jmolHistory(boolean enable)
842 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
845 public void loadInline(String string)
849 // viewer.loadInline(strModel, isAppend);
851 // construct fake fullPathName and fileName so we can identify the file
853 // Then, construct pass a reader for the string to Jmol.
854 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
855 // fileName, null, reader, false, null, null, 0);
856 viewer.openStringInline(string);
859 public void mouseOverStructure(int atomIndex, String strInfo)
862 int alocsep = strInfo.indexOf("^");
863 int mdlSep = strInfo.indexOf("/");
864 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
866 if (chainSeparator == -1)
868 chainSeparator = strInfo.indexOf(".");
869 if (mdlSep > -1 && mdlSep < chainSeparator)
871 chainSeparator1 = chainSeparator;
872 chainSeparator = mdlSep;
875 // handle insertion codes
878 pdbResNum = Integer.parseInt(strInfo.substring(
879 strInfo.indexOf("]") + 1, alocsep));
884 pdbResNum = Integer.parseInt(strInfo.substring(
885 strInfo.indexOf("]") + 1, chainSeparator));
889 if (strInfo.indexOf(":") > -1)
890 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
891 strInfo.indexOf("."));
897 String pdbfilename = modelFileNames[frameNo]; // default is first or current
901 if (chainSeparator1 == -1)
903 chainSeparator1 = strInfo.indexOf(".", mdlSep);
905 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
906 chainSeparator1) : strInfo.substring(mdlSep + 1);
909 // recover PDB filename for the model hovered over.
910 int _mp = _modelFileNameMap.length - 1, mnumber = new Integer(mdlId)
912 while (mnumber < _modelFileNameMap[_mp])
916 pdbfilename = modelFileNames[_mp];
917 if (pdbfilename == null)
919 pdbfilename = new File(viewer.getModelFileName(mnumber))
923 } catch (Exception e)
928 if (lastMessage == null || !lastMessage.equals(strInfo))
929 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
931 lastMessage = strInfo;
934 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
938 System.err.println("Ignoring additional hover info: " + data
939 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
941 mouseOverStructure(atomIndex, strInfo);
945 * { if (history != null && strStatus != null &&
946 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
950 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
953 * this implements the toggle label behaviour copied from the original
954 * structure viewer, MCView
958 System.err.println("Ignoring additional pick data string " + strData);
960 int chainSeparator = strInfo.indexOf(":");
962 if (chainSeparator == -1)
963 chainSeparator = strInfo.indexOf(".");
965 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
967 String mdlString = "";
968 if ((p = strInfo.indexOf(":")) > -1)
969 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
971 if ((p = strInfo.indexOf("/")) > -1)
973 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
975 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
979 if (!atomsPicked.contains(picked))
981 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
982 atomsPicked.addElement(picked);
986 viewer.evalString("select " + picked + ";label off");
987 atomsPicked.removeElement(picked);
990 // TODO: in application this happens
992 // if (scriptWindow != null)
994 // scriptWindow.sendConsoleMessage(strInfo);
995 // scriptWindow.sendConsoleMessage("\n");
1001 public void notifyCallback(EnumCallback type, Object[] data)
1008 notifyFileLoaded((String) data[1], (String) data[2],
1009 (String) data[3], (String) data[4],
1010 ((Integer) data[5]).intValue());
1014 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
1016 // also highlight in alignment
1018 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1022 notifyScriptTermination((String) data[2],
1023 ((Integer) data[3]).intValue());
1026 sendConsoleEcho((String) data[1]);
1029 sendConsoleMessage((data == null) ? ((String) null)
1030 : (String) data[1]);
1033 // System.err.println("Ignoring error callback.");
1043 System.err.println("Unhandled callback " + type + " "
1044 + data[1].toString());
1047 } catch (Exception e)
1049 System.err.println("Squashed Jmol callback handler error:");
1050 e.printStackTrace();
1055 public boolean notifyEnabled(EnumCallback callbackPick)
1057 switch (callbackPick)
1077 // incremented every time a load notification is successfully handled -
1078 // lightweight mechanism for other threads to detect when they can start
1079 // referrring to new structures.
1080 private long loadNotifiesHandled = 0;
1082 public long getLoadNotifiesHandled()
1084 return loadNotifiesHandled;
1087 public void notifyFileLoaded(String fullPathName, String fileName2,
1088 String modelName, String errorMsg, int modelParts)
1090 if (errorMsg != null)
1092 fileLoadingError = errorMsg;
1096 // TODO: deal sensibly with models loaded inLine:
1097 // modelName will be null, as will fullPathName.
1099 // the rest of this routine ignores the arguments, and simply interrogates
1100 // the Jmol view to find out what structures it contains, and adds them to
1101 // the structure selection manager.
1102 fileLoadingError = null;
1103 String[] oldmodels = modelFileNames;
1104 modelFileNames = null;
1105 chainNames = new Vector();
1106 chainFile = new Hashtable();
1107 boolean notifyLoaded = false;
1108 String[] modelfilenames = getPdbFile();
1109 // first check if we've lost any structures
1110 if (oldmodels != null && oldmodels.length > 0)
1113 for (int i = 0; i < oldmodels.length; i++)
1115 for (int n = 0; n < modelfilenames.length; n++)
1117 if (modelfilenames[n] == oldmodels[i])
1119 oldmodels[i] = null;
1123 if (oldmodels[i] != null)
1130 String[] oldmfn = new String[oldm];
1132 for (int i = 0; i < oldmodels.length; i++)
1134 if (oldmodels[i] != null)
1136 oldmfn[oldm++] = oldmodels[i];
1139 // deregister the Jmol instance for these structures - we'll add
1140 // ourselves again at the end for the current structure set.
1141 ssm.removeStructureViewerListener(this, oldmfn);
1144 refreshPdbEntries();
1145 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1147 String fileName = modelfilenames[modelnum];
1148 boolean foundEntry = false;
1149 MCview.PDBfile pdb = null;
1150 String pdbfile = null, pdbfhash = null;
1151 // model was probably loaded inline - so check the pdb file hashcode
1154 // calculate essential attributes for the pdb data imported inline.
1155 // prolly need to resolve modelnumber properly - for now just use our
1157 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1159 pdbfhash = "" + pdbfile.hashCode();
1161 if (pdbentry != null)
1163 // search pdbentries and sequences to find correct pdbentry for this
1165 for (int pe = 0; pe < pdbentry.length; pe++)
1167 boolean matches = false;
1168 if (fileName == null)
1171 // see JAL-623 - need method of matching pasted data up
1173 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
1174 AppletFormatAdapter.PASTE);
1175 pdbentry[modelnum].setFile("INLINE" + pdb.id);
1183 if (matches = (fl = new File(pdbentry[pe].getFile()))
1184 .equals(new File(fileName)))
1187 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1190 // to be tested. See mantis bug
1191 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1192 String protocol = AppletFormatAdapter.URL;
1197 protocol = AppletFormatAdapter.FILE;
1199 } catch (Exception e)
1204 // Explicitly map to the filename used by Jmol ;
1205 pdb = ssm.setMapping(sequence[pe], chains[pe], fileName,
1207 // pdbentry[pe].getFile(), protocol);
1213 // add an entry for every chain in the model
1214 for (int i = 0; i < pdb.chains.size(); i++)
1216 String chid = new String(pdb.id + ":"
1217 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
1218 chainFile.put(chid, fileName);
1219 chainNames.addElement(chid);
1221 notifyLoaded = true;
1225 if (!foundEntry && associateNewStructs)
1227 // this is a foreign pdb file that jalview doesn't know about - add
1228 // it to the dataset and try to find a home - either on a matching
1229 // sequence or as a new sequence.
1230 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1232 // parse pdb file into a chain, etc.
1233 // locate best match for pdb in associated views and add mapping to
1235 // if properly registered then
1236 notifyLoaded = true;
1241 // so finally, update the jmol bits and pieces
1242 if (jmolpopup != null)
1244 // potential for deadlock here:
1245 // jmolpopup.updateComputedMenus();
1247 if (!isLoadingFromArchive())
1249 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1251 // register ourselves as a listener and notify the gui that it needs to
1253 ssm.addStructureViewerListener(this);
1256 FeatureRenderer fr = getFeatureRenderer(null);
1262 loadNotifiesHandled++;
1264 setLoadingFromArchive(false);
1267 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1269 notifyAtomPicked(iatom, strMeasure, null);
1272 public abstract void notifyScriptTermination(String strStatus,
1276 * display a message echoed from the jmol viewer
1280 public abstract void sendConsoleEcho(String strEcho); /*
1281 * { showConsole(true);
1283 * history.append("\n" +
1287 // /End JmolStatusListener
1288 // /////////////////////////////
1292 * status message - usually the response received after a script
1295 public abstract void sendConsoleMessage(String strStatus);
1297 public void setCallbackFunction(String callbackType,
1298 String callbackFunction)
1300 System.err.println("Ignoring set-callback request to associate "
1301 + callbackType + " with function " + callbackFunction);
1305 public void setJalviewColourScheme(ColourSchemeI cs)
1307 colourBySequence = false;
1316 // TODO: Switch between nucleotide or aa selection expressions
1317 Enumeration en = ResidueProperties.aa3Hash.keys();
1318 StringBuffer command = new StringBuffer("select *;color white;");
1319 while (en.hasMoreElements())
1321 res = en.nextElement().toString();
1322 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
1326 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
1328 command.append("select " + res + ";color[" + col.getRed() + ","
1329 + col.getGreen() + "," + col.getBlue() + "];");
1332 evalStateCommand(command.toString());
1336 public void showHelp()
1338 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1342 * open the URL somehow
1346 public abstract void showUrl(String url, String target);
1349 * called when the binding thinks the UI needs to be refreshed after a Jmol
1350 * state change. this could be because structures were loaded, or because an
1351 * error has occured.
1353 public abstract void refreshGUI();
1356 * called to show or hide the associated console window container.
1360 public abstract void showConsole(boolean show);
1363 * @param renderPanel
1365 * - when true will initialise jmol's file IO system (should be false
1366 * in applet context)
1368 * @param documentBase
1370 * @param commandOptions
1372 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1373 String htmlName, URL documentBase, URL codeBase,
1374 String commandOptions)
1376 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1377 codeBase, commandOptions, null, null);
1382 * @param renderPanel
1384 * - when true will initialise jmol's file IO system (should be false
1385 * in applet context)
1387 * @param documentBase
1389 * @param commandOptions
1390 * @param consolePanel
1391 * - panel to contain Jmol console
1392 * @param buttonsToShow
1393 * - buttons to show on the console, in ordr
1395 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1396 String htmlName, URL documentBase, URL codeBase,
1397 String commandOptions, final Container consolePanel,
1398 String buttonsToShow)
1400 if (commandOptions == null)
1402 commandOptions = "";
1404 viewer = JmolViewer.allocateViewer(renderPanel,
1405 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1406 + ((Object) this).toString(), documentBase, codeBase,
1407 commandOptions, this);
1409 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
1410 if (consolePanel != null)
1412 consolePanel.addComponentListener(this);
1418 protected abstract JmolAppConsoleInterface createJmolConsole(
1419 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
1421 protected org.jmol.api.JmolAppConsoleInterface console = null;
1423 public void componentResized(ComponentEvent e)
1428 public void componentMoved(ComponentEvent e)
1433 public void componentShown(ComponentEvent e)
1438 public void componentHidden(ComponentEvent e)
1443 public void setLoadingFromArchive(boolean loadingFromArchive)
1445 this.loadingFromArchive = loadingFromArchive;
1450 * @return true if Jmol is still restoring state or loading is still going on (see setFinsihedLoadingFromArchive)
1452 public boolean isLoadingFromArchive()
1454 return loadingFromArchive && !loadingFinished;
1458 * modify flag which controls if sequence colouring events are honoured by the binding.
1459 * Should be true for normal operation
1460 * @param finishedLoading
1462 public void setFinishedLoadingFromArchive(boolean finishedLoading)
1464 loadingFinished = finishedLoading;
1467 public void setBackgroundColour(java.awt.Color col)
1470 viewer.evalStringQuiet("background [" + col.getRed() + ","
1471 + col.getGreen() + "," + col.getBlue() + "];");
1476 * add structures and any known sequence associations
1478 * @returns the pdb entries added to the current set.
1480 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
1481 SequenceI[][] seq, String[][] chns)
1484 Vector v = new Vector();
1485 Vector rtn = new Vector();
1486 for (int i = 0; i < pdbentry.length; i++)
1488 v.addElement(pdbentry[i]);
1490 for (int i = 0; i < pdbe.length; i++)
1492 int r = v.indexOf(pdbe[i]);
1493 if (r == -1 || r >= pdbentry.length)
1495 rtn.addElement(new int[]
1497 v.addElement(pdbe[i]);
1501 // just make sure the sequence/chain entries are all up to date
1502 addSequenceAndChain(r, seq[i], chns[i]);
1505 pdbe = new PDBEntry[v.size()];
1510 // expand the tied seuqence[] and string[] arrays
1511 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
1512 String[][] sch = new String[pdbentry.length][];
1513 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
1514 System.arraycopy(chains, 0, sch, 0, this.chains.length);
1517 pdbe = new PDBEntry[rtn.size()];
1518 for (int r = 0; r < pdbe.length; r++)
1520 int[] stri = ((int[]) rtn.elementAt(r));
1521 // record the pdb file as a new addition
1522 pdbe[r] = pdbentry[stri[0]];
1523 // and add the new sequence/chain entries
1524 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
1534 public void addSequence(int pe, SequenceI[] seq)
1536 // add sequences to the pe'th pdbentry's seuqence set.
1537 addSequenceAndChain(pe, seq, null);
1540 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
1542 if (pe < 0 || pe >= pdbentry.length)
1545 "Implementation error - no corresponding pdbentry (for index "
1546 + pe + ") to add sequences mappings to");
1548 final String nullChain = "TheNullChain";
1549 Vector s = new Vector();
1550 Vector c = new Vector();
1553 chains = new String[pdbentry.length][];
1555 if (sequence[pe] != null)
1557 for (int i = 0; i < sequence[pe].length; i++)
1559 s.addElement(sequence[pe][i]);
1560 if (chains[pe] != null)
1562 if (i < chains[pe].length)
1564 c.addElement(chains[pe][i]);
1568 c.addElement(nullChain);
1573 if (tchain != null && tchain.length > 0)
1575 c.addElement(nullChain);
1580 for (int i = 0; i < seq.length; i++)
1582 if (!s.contains(seq[i]))
1584 s.addElement(seq[i]);
1585 if (tchain != null && i < tchain.length)
1587 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
1591 SequenceI[] tmp = new SequenceI[s.size()];
1596 String[] tch = new String[c.size()];
1598 for (int i = 0; i < tch.length; i++)
1600 if (tch[i] == nullChain)
1616 * @return text report of alignment between pdbfile and any associated
1617 * alignment sequences
1619 public String printMapping(String pdbfile)
1621 return ssm.printMapping(pdbfile);
1625 public void resizeInnerPanel(String data)
1627 // Jalview doesn't honour resize panel requests