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 // check to see if we are still waiting for Jmol files
330 long starttime=System.currentTimeMillis();
331 boolean waiting=true;
334 for (String file:files)
337 // HACK - in Jalview 2.8 this call may not be threadsafe so we catch
338 // every possible exception
339 StructureMapping[] sm = ssm.getMapping(file);
340 if (sm == null || sm.length == 0)
344 } catch (Exception x)
352 // we wait around for a reasonable time before we give up
353 } while (waiting && System.currentTimeMillis()<(10000+1000*files.length+starttime));
356 System.err.println("RUNTIME PROBLEM: Jmol seems to be taking a long time to process all the structures.");
359 StringBuffer selectioncom = new StringBuffer();
362 // union of all aligned positions are collected together.
363 for (int a = 0; a < _alignment.length; a++)
365 int refStructure = _refStructure[a];
366 AlignmentI alignment = _alignment[a];
367 ColumnSelection hiddenCols = _hiddenCols[a];
369 && selectioncom.length() > 0
370 && !selectioncom.substring(selectioncom.length() - 1).equals(
373 selectioncom.append("|");
375 // process this alignment
376 if (refStructure >= files.length)
378 System.err.println("Invalid reference structure value "
382 if (refStructure < -1)
386 StringBuffer command = new StringBuffer();
388 boolean matched[] = new boolean[alignment.getWidth()];
389 for (int m = 0; m < matched.length; m++)
392 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
395 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
396 String isel[] = new String[files.length];
397 // reference structure - all others are superposed in it
398 String[] targetC = new String[files.length];
399 String[] chainNames = new String[files.length];
400 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
402 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
403 // RACE CONDITION - getMapping only returns Jmol loaded filenames once
404 // Jmol callback has completed.
405 if (mapping == null || mapping.length < 1)
409 for (int s = 0; s < sequence[pdbfnum].length; s++)
411 for (int sp, m = 0; m < mapping.length; m++)
413 if (mapping[m].getSequence() == sequence[pdbfnum][s]
414 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
416 if (refStructure == -1)
418 refStructure = pdbfnum;
420 SequenceI asp = alignment.getSequenceAt(sp);
421 for (int r = 0; r < matched.length; r++)
427 matched[r] = false; // assume this is not a good site
428 if (r >= asp.getLength())
433 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
435 // no mapping to gaps in sequence
438 int t = asp.findPosition(r); // sequence position
439 int apos = mapping[m].getAtomNum(t);
440 int pos = mapping[m].getPDBResNum(t);
442 if (pos < 1 || pos == lastPos)
444 // can't align unmapped sequence
447 matched[r] = true; // this is a good ite
449 // just record this residue position
450 commonrpositions[pdbfnum][r] = pos;
452 // create model selection suffix
453 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
454 if (mapping[m].getChain() == null
455 || mapping[m].getChain().trim().length() == 0)
457 targetC[pdbfnum] = "";
461 targetC[pdbfnum] = ":" + mapping[m].getChain();
463 chainNames[pdbfnum] = mapping[m].getPdbId()
465 // move on to next pdb file
466 s = sequence[pdbfnum].length;
472 String[] selcom = new String[files.length];
474 // generate select statements to select regions to superimpose structures
476 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
478 String chainCd = targetC[pdbfnum];
481 StringBuffer molsel = new StringBuffer();
483 for (int r = 0; r < matched.length; r++)
491 if (lpos != commonrpositions[pdbfnum][r] - 1)
497 molsel.append(chainCd);
498 // molsel.append("} {");
504 // continuous run - and lpos >-1
507 // at the beginning, so add dash
513 lpos = commonrpositions[pdbfnum][r];
514 // molsel.append(lpos);
517 // add final selection phrase
521 molsel.append(chainCd);
524 selcom[pdbfnum] = molsel.toString();
525 selectioncom.append("((");
526 selectioncom.append(selcom[pdbfnum].substring(1,
527 selcom[pdbfnum].length() - 1));
528 selectioncom.append(" )& ");
529 selectioncom.append(pdbfnum + 1);
530 selectioncom.append(".1)");
531 if (pdbfnum < files.length - 1)
533 selectioncom.append("|");
537 // TODO: consider bailing if nmatched less than 4 because superposition
540 // TODO: refactor superposable position search (above) from jmol selection
541 // construction (below)
542 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
544 if (pdbfnum == refStructure)
548 command.append("echo ");
549 command.append("\"Superposing (");
550 command.append(chainNames[pdbfnum]);
551 command.append(") against reference (");
552 command.append(chainNames[refStructure]);
553 command.append(")\";\ncompare ");
555 command.append(1 + pdbfnum);
556 command.append(".1} {");
557 command.append(1 + refStructure);
558 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
560 // form the matched pair strings
562 for (int s = 0; s < 2; s++)
564 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
566 command.append(" ROTATE TRANSLATE;\n");
568 System.out.println("Select regions:\n" + selectioncom.toString());
569 evalStateCommand("select *; cartoons off; backbone; select ("
570 + selectioncom.toString() + "); cartoons; ");
571 // selcom.append("; ribbons; ");
572 System.out.println("Superimpose command(s):\n" + command.toString());
574 evalStateCommand(command.toString());
576 if (selectioncom.length() > 0)
577 {// finally, mark all regions that were superposed.
578 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
580 selectioncom.setLength(selectioncom.length() - 1);
582 System.out.println("Select regions:\n" + selectioncom.toString());
583 evalStateCommand("select *; cartoons off; backbone; select ("
584 + selectioncom.toString() + "); cartoons; ");
585 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
589 public void evalStateCommand(String command)
592 if (lastCommand == null || !lastCommand.equals(command))
594 viewer.evalStringQuiet(command + "\n");
597 lastCommand = command;
601 * colour any structures associated with sequences in the given alignment
602 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
603 * if colourBySequence is enabled.
605 public void colourBySequence(boolean showFeatures,
606 jalview.api.AlignmentViewPanel alignmentv)
608 if (!colourBySequence || !loadingFinished)
614 String[] files = getPdbFile();
616 SequenceRenderer sr = getSequenceRenderer(alignmentv);
618 FeatureRenderer fr = null;
621 fr = getFeatureRenderer(alignmentv);
623 AlignmentI alignment = alignmentv.getAlignment();
625 for (jalview.structure.StructureMappingcommandSet cpdbbyseq : JmolCommands
626 .getColourBySequenceCommand(ssm, files, sequence, sr, fr,
628 for (String cbyseq : cpdbbyseq.commands)
630 evalStateCommand(cbyseq);
634 public boolean isColourBySequence()
636 return colourBySequence;
639 public void setColourBySequence(boolean colourBySequence)
641 this.colourBySequence = colourBySequence;
644 public void createImage(String file, String type, int quality)
646 System.out.println("JMOL CREATE IMAGE");
649 public String createImage(String fileName, String type,
650 Object textOrBytes, int quality)
652 System.out.println("JMOL CREATE IMAGE");
656 public String eval(String strEval)
658 // System.out.println(strEval);
659 // "# 'eval' is implemented only for the applet.";
663 // End StructureListener
664 // //////////////////////////
666 public float[][] functionXY(String functionName, int x, int y)
671 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
673 // TODO Auto-generated method stub
677 public Color getColour(int atomIndex, int pdbResNum, String chain,
680 if (getModelNum(pdbfile) < 0)
682 // TODO: verify atomIndex is selecting correct model.
683 return new Color(viewer.getAtomArgb(atomIndex));
687 * returns the current featureRenderer that should be used to colour the
694 public abstract FeatureRenderer getFeatureRenderer(
695 AlignmentViewPanel alignment);
698 * instruct the Jalview binding to update the pdbentries vector if necessary
699 * prior to matching the jmol view's contents to the list of structure files
700 * Jalview knows about.
702 public abstract void refreshPdbEntries();
704 private int getModelNum(String modelFileName)
706 String[] mfn = getPdbFile();
711 for (int i = 0; i < mfn.length; i++)
713 if (mfn[i].equalsIgnoreCase(modelFileName))
720 * map between index of model filename returned from getPdbFile and the first
721 * index of models from this file in the viewer. Note - this is not trimmed -
722 * use getPdbFile to get number of unique models.
724 private int _modelFileNameMap[];
726 // ////////////////////////////////
727 // /StructureListener
728 public synchronized String[] getPdbFile()
732 return new String[0];
734 if (modelFileNames == null)
737 String mset[] = new String[viewer.getModelCount()];
738 _modelFileNameMap = new int[mset.length];
740 String m = viewer.getModelFileName(0);
745 mset[0] = new File(m).getAbsolutePath();
746 } catch (AccessControlException x)
748 // usually not allowed to do this in applet, so keep raw handle
750 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
753 for (int i = 1; i < mset.length; i++)
755 m = viewer.getModelFileName(i);
760 mset[j] = new File(m).getAbsolutePath();
761 } catch (AccessControlException x)
763 // usually not allowed to do this in applet, so keep raw handle
765 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
768 _modelFileNameMap[j] = i; // record the model index for the filename
769 // skip any additional models in the same file (NMR structures)
770 if ((mset[j] == null ? mset[j] != mset[j - 1]
771 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
776 modelFileNames = new String[j];
777 System.arraycopy(mset, 0, modelFileNames, 0, j);
779 return modelFileNames;
783 * map from string to applet
785 public Map getRegistryInfo()
787 // TODO Auto-generated method stub
792 * returns the current sequenceRenderer that should be used to colour the
799 public abstract SequenceRenderer getSequenceRenderer(
800 AlignmentViewPanel alignment);
802 // ///////////////////////////////
803 // JmolStatusListener
805 public void handlePopupMenu(int x, int y)
807 jmolpopup.show(x, y);
811 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
814 if (modelFileNames == null)
819 // look up file model number for this pdbfile
822 // may need to adjust for URLencoding here - we don't worry about that yet.
823 while (mdlNum < modelFileNames.length
824 && !pdbfile.equals(modelFileNames[mdlNum]))
826 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
829 if (mdlNum == modelFileNames.length)
835 // if (!pdbfile.equals(pdbentry.getFile()))
837 if (resetLastRes.length() > 0)
839 viewer.evalStringQuiet(resetLastRes.toString());
843 eval.append("select " + pdbResNum); // +modelNum
845 resetLastRes.setLength(0);
846 resetLastRes.append("select " + pdbResNum); // +modelNum
849 resetLastRes.append(":");
850 if (!chain.equals(" "))
853 resetLastRes.append(chain);
856 eval.append(" /" + (mdlNum + 1));
857 resetLastRes.append("/" + (mdlNum + 1));
859 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
861 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
862 + " and not hetero; spacefill 0;");
864 eval.append("spacefill 200;select none");
866 viewer.evalStringQuiet(eval.toString());
871 boolean debug = true;
873 private void jmolHistory(boolean enable)
875 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
878 public void loadInline(String string)
882 // viewer.loadInline(strModel, isAppend);
884 // construct fake fullPathName and fileName so we can identify the file
886 // Then, construct pass a reader for the string to Jmol.
887 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
888 // fileName, null, reader, false, null, null, 0);
889 viewer.openStringInline(string);
892 public void mouseOverStructure(int atomIndex, String strInfo)
895 int alocsep = strInfo.indexOf("^");
896 int mdlSep = strInfo.indexOf("/");
897 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
899 if (chainSeparator == -1)
901 chainSeparator = strInfo.indexOf(".");
902 if (mdlSep > -1 && mdlSep < chainSeparator)
904 chainSeparator1 = chainSeparator;
905 chainSeparator = mdlSep;
908 // handle insertion codes
911 pdbResNum = Integer.parseInt(strInfo.substring(
912 strInfo.indexOf("]") + 1, alocsep));
917 pdbResNum = Integer.parseInt(strInfo.substring(
918 strInfo.indexOf("]") + 1, chainSeparator));
922 if (strInfo.indexOf(":") > -1)
923 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
924 strInfo.indexOf("."));
930 String pdbfilename = modelFileNames[frameNo]; // default is first or current
934 if (chainSeparator1 == -1)
936 chainSeparator1 = strInfo.indexOf(".", mdlSep);
938 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
939 chainSeparator1) : strInfo.substring(mdlSep + 1);
942 // recover PDB filename for the model hovered over.
943 int _mp = _modelFileNameMap.length - 1, mnumber = new Integer(mdlId)
945 while (mnumber < _modelFileNameMap[_mp])
949 pdbfilename = modelFileNames[_mp];
950 if (pdbfilename == null)
952 pdbfilename = new File(viewer.getModelFileName(mnumber))
956 } catch (Exception e)
961 if (lastMessage == null || !lastMessage.equals(strInfo))
962 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
964 lastMessage = strInfo;
967 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
971 System.err.println("Ignoring additional hover info: " + data
972 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
974 mouseOverStructure(atomIndex, strInfo);
978 * { if (history != null && strStatus != null &&
979 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
983 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
986 * this implements the toggle label behaviour copied from the original
987 * structure viewer, MCView
991 System.err.println("Ignoring additional pick data string " + strData);
993 int chainSeparator = strInfo.indexOf(":");
995 if (chainSeparator == -1)
996 chainSeparator = strInfo.indexOf(".");
998 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
1000 String mdlString = "";
1001 if ((p = strInfo.indexOf(":")) > -1)
1002 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
1004 if ((p = strInfo.indexOf("/")) > -1)
1006 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
1008 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
1012 if (!atomsPicked.contains(picked))
1014 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
1015 atomsPicked.addElement(picked);
1019 viewer.evalString("select " + picked + ";label off");
1020 atomsPicked.removeElement(picked);
1023 // TODO: in application this happens
1025 // if (scriptWindow != null)
1027 // scriptWindow.sendConsoleMessage(strInfo);
1028 // scriptWindow.sendConsoleMessage("\n");
1034 public void notifyCallback(EnumCallback type, Object[] data)
1041 notifyFileLoaded((String) data[1], (String) data[2],
1042 (String) data[3], (String) data[4],
1043 ((Integer) data[5]).intValue());
1047 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
1049 // also highlight in alignment
1051 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1055 notifyScriptTermination((String) data[2],
1056 ((Integer) data[3]).intValue());
1059 sendConsoleEcho((String) data[1]);
1062 sendConsoleMessage((data == null) ? ((String) null)
1063 : (String) data[1]);
1066 // System.err.println("Ignoring error callback.");
1076 System.err.println("Unhandled callback " + type + " "
1077 + data[1].toString());
1080 } catch (Exception e)
1082 System.err.println("Squashed Jmol callback handler error:");
1083 e.printStackTrace();
1088 public boolean notifyEnabled(EnumCallback callbackPick)
1090 switch (callbackPick)
1110 // incremented every time a load notification is successfully handled -
1111 // lightweight mechanism for other threads to detect when they can start
1112 // referrring to new structures.
1113 private long loadNotifiesHandled = 0;
1115 public long getLoadNotifiesHandled()
1117 return loadNotifiesHandled;
1120 public void notifyFileLoaded(String fullPathName, String fileName2,
1121 String modelName, String errorMsg, int modelParts)
1123 if (errorMsg != null)
1125 fileLoadingError = errorMsg;
1129 // TODO: deal sensibly with models loaded inLine:
1130 // modelName will be null, as will fullPathName.
1132 // the rest of this routine ignores the arguments, and simply interrogates
1133 // the Jmol view to find out what structures it contains, and adds them to
1134 // the structure selection manager.
1135 fileLoadingError = null;
1136 String[] oldmodels = modelFileNames;
1137 modelFileNames = null;
1138 chainNames = new Vector();
1139 chainFile = new Hashtable();
1140 boolean notifyLoaded = false;
1141 String[] modelfilenames = getPdbFile();
1142 // first check if we've lost any structures
1143 if (oldmodels != null && oldmodels.length > 0)
1146 for (int i = 0; i < oldmodels.length; i++)
1148 for (int n = 0; n < modelfilenames.length; n++)
1150 if (modelfilenames[n] == oldmodels[i])
1152 oldmodels[i] = null;
1156 if (oldmodels[i] != null)
1163 String[] oldmfn = new String[oldm];
1165 for (int i = 0; i < oldmodels.length; i++)
1167 if (oldmodels[i] != null)
1169 oldmfn[oldm++] = oldmodels[i];
1172 // deregister the Jmol instance for these structures - we'll add
1173 // ourselves again at the end for the current structure set.
1174 ssm.removeStructureViewerListener(this, oldmfn);
1177 refreshPdbEntries();
1178 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1180 String fileName = modelfilenames[modelnum];
1181 boolean foundEntry = false;
1182 MCview.PDBfile pdb = null;
1183 String pdbfile = null, pdbfhash = null;
1184 // model was probably loaded inline - so check the pdb file hashcode
1187 // calculate essential attributes for the pdb data imported inline.
1188 // prolly need to resolve modelnumber properly - for now just use our
1190 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1192 pdbfhash = "" + pdbfile.hashCode();
1194 if (pdbentry != null)
1196 // search pdbentries and sequences to find correct pdbentry for this
1198 for (int pe = 0; pe < pdbentry.length; pe++)
1200 boolean matches = false;
1201 if (fileName == null)
1204 // see JAL-623 - need method of matching pasted data up
1206 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
1207 AppletFormatAdapter.PASTE);
1208 pdbentry[modelnum].setFile("INLINE" + pdb.id);
1216 if (matches = (fl = new File(pdbentry[pe].getFile()))
1217 .equals(new File(fileName)))
1220 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1223 // to be tested. See mantis bug
1224 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1225 String protocol = AppletFormatAdapter.URL;
1230 protocol = AppletFormatAdapter.FILE;
1232 } catch (Exception e)
1237 // Explicitly map to the filename used by Jmol ;
1238 pdb = ssm.setMapping(sequence[pe], chains[pe], fileName,
1240 // pdbentry[pe].getFile(), protocol);
1246 // add an entry for every chain in the model
1247 for (int i = 0; i < pdb.chains.size(); i++)
1249 String chid = new String(pdb.id + ":"
1250 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
1251 chainFile.put(chid, fileName);
1252 chainNames.addElement(chid);
1254 notifyLoaded = true;
1258 if (!foundEntry && associateNewStructs)
1260 // this is a foreign pdb file that jalview doesn't know about - add
1261 // it to the dataset and try to find a home - either on a matching
1262 // sequence or as a new sequence.
1263 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1265 // parse pdb file into a chain, etc.
1266 // locate best match for pdb in associated views and add mapping to
1268 // if properly registered then
1269 notifyLoaded = true;
1274 // so finally, update the jmol bits and pieces
1275 if (jmolpopup != null)
1277 // potential for deadlock here:
1278 // jmolpopup.updateComputedMenus();
1280 if (!isLoadingFromArchive())
1282 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1284 // register ourselves as a listener and notify the gui that it needs to
1286 ssm.addStructureViewerListener(this);
1289 FeatureRenderer fr = getFeatureRenderer(null);
1295 loadNotifiesHandled++;
1297 setLoadingFromArchive(false);
1300 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1302 notifyAtomPicked(iatom, strMeasure, null);
1305 public abstract void notifyScriptTermination(String strStatus,
1309 * display a message echoed from the jmol viewer
1313 public abstract void sendConsoleEcho(String strEcho); /*
1314 * { showConsole(true);
1316 * history.append("\n" +
1320 // /End JmolStatusListener
1321 // /////////////////////////////
1325 * status message - usually the response received after a script
1328 public abstract void sendConsoleMessage(String strStatus);
1330 public void setCallbackFunction(String callbackType,
1331 String callbackFunction)
1333 System.err.println("Ignoring set-callback request to associate "
1334 + callbackType + " with function " + callbackFunction);
1338 public void setJalviewColourScheme(ColourSchemeI cs)
1340 colourBySequence = false;
1349 // TODO: Switch between nucleotide or aa selection expressions
1350 Enumeration en = ResidueProperties.aa3Hash.keys();
1351 StringBuffer command = new StringBuffer("select *;color white;");
1352 while (en.hasMoreElements())
1354 res = en.nextElement().toString();
1355 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
1359 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
1361 command.append("select " + res + ";color[" + col.getRed() + ","
1362 + col.getGreen() + "," + col.getBlue() + "];");
1365 evalStateCommand(command.toString());
1369 public void showHelp()
1371 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1375 * open the URL somehow
1379 public abstract void showUrl(String url, String target);
1382 * called when the binding thinks the UI needs to be refreshed after a Jmol
1383 * state change. this could be because structures were loaded, or because an
1384 * error has occured.
1386 public abstract void refreshGUI();
1389 * called to show or hide the associated console window container.
1393 public abstract void showConsole(boolean show);
1396 * @param renderPanel
1398 * - when true will initialise jmol's file IO system (should be false
1399 * in applet context)
1401 * @param documentBase
1403 * @param commandOptions
1405 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1406 String htmlName, URL documentBase, URL codeBase,
1407 String commandOptions)
1409 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1410 codeBase, commandOptions, null, null);
1415 * @param renderPanel
1417 * - when true will initialise jmol's file IO system (should be false
1418 * in applet context)
1420 * @param documentBase
1422 * @param commandOptions
1423 * @param consolePanel
1424 * - panel to contain Jmol console
1425 * @param buttonsToShow
1426 * - buttons to show on the console, in ordr
1428 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1429 String htmlName, URL documentBase, URL codeBase,
1430 String commandOptions, final Container consolePanel,
1431 String buttonsToShow)
1433 if (commandOptions == null)
1435 commandOptions = "";
1437 viewer = JmolViewer.allocateViewer(renderPanel,
1438 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1439 + ((Object) this).toString(), documentBase, codeBase,
1440 commandOptions, this);
1442 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
1443 if (consolePanel != null)
1445 consolePanel.addComponentListener(this);
1451 protected abstract JmolAppConsoleInterface createJmolConsole(
1452 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
1454 protected org.jmol.api.JmolAppConsoleInterface console = null;
1456 public void componentResized(ComponentEvent e)
1461 public void componentMoved(ComponentEvent e)
1466 public void componentShown(ComponentEvent e)
1471 public void componentHidden(ComponentEvent e)
1476 public void setLoadingFromArchive(boolean loadingFromArchive)
1478 this.loadingFromArchive = loadingFromArchive;
1483 * @return true if Jmol is still restoring state or loading is still going on (see setFinsihedLoadingFromArchive)
1485 public boolean isLoadingFromArchive()
1487 return loadingFromArchive && !loadingFinished;
1491 * modify flag which controls if sequence colouring events are honoured by the binding.
1492 * Should be true for normal operation
1493 * @param finishedLoading
1495 public void setFinishedLoadingFromArchive(boolean finishedLoading)
1497 loadingFinished = finishedLoading;
1500 public void setBackgroundColour(java.awt.Color col)
1503 viewer.evalStringQuiet("background [" + col.getRed() + ","
1504 + col.getGreen() + "," + col.getBlue() + "];");
1509 * add structures and any known sequence associations
1511 * @returns the pdb entries added to the current set.
1513 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
1514 SequenceI[][] seq, String[][] chns)
1517 Vector v = new Vector();
1518 Vector rtn = new Vector();
1519 for (int i = 0; i < pdbentry.length; i++)
1521 v.addElement(pdbentry[i]);
1523 for (int i = 0; i < pdbe.length; i++)
1525 int r = v.indexOf(pdbe[i]);
1526 if (r == -1 || r >= pdbentry.length)
1528 rtn.addElement(new int[]
1530 v.addElement(pdbe[i]);
1534 // just make sure the sequence/chain entries are all up to date
1535 addSequenceAndChain(r, seq[i], chns[i]);
1538 pdbe = new PDBEntry[v.size()];
1543 // expand the tied seuqence[] and string[] arrays
1544 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
1545 String[][] sch = new String[pdbentry.length][];
1546 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
1547 System.arraycopy(chains, 0, sch, 0, this.chains.length);
1550 pdbe = new PDBEntry[rtn.size()];
1551 for (int r = 0; r < pdbe.length; r++)
1553 int[] stri = ((int[]) rtn.elementAt(r));
1554 // record the pdb file as a new addition
1555 pdbe[r] = pdbentry[stri[0]];
1556 // and add the new sequence/chain entries
1557 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
1567 public void addSequence(int pe, SequenceI[] seq)
1569 // add sequences to the pe'th pdbentry's seuqence set.
1570 addSequenceAndChain(pe, seq, null);
1573 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
1575 if (pe < 0 || pe >= pdbentry.length)
1578 "Implementation error - no corresponding pdbentry (for index "
1579 + pe + ") to add sequences mappings to");
1581 final String nullChain = "TheNullChain";
1582 Vector s = new Vector();
1583 Vector c = new Vector();
1586 chains = new String[pdbentry.length][];
1588 if (sequence[pe] != null)
1590 for (int i = 0; i < sequence[pe].length; i++)
1592 s.addElement(sequence[pe][i]);
1593 if (chains[pe] != null)
1595 if (i < chains[pe].length)
1597 c.addElement(chains[pe][i]);
1601 c.addElement(nullChain);
1606 if (tchain != null && tchain.length > 0)
1608 c.addElement(nullChain);
1613 for (int i = 0; i < seq.length; i++)
1615 if (!s.contains(seq[i]))
1617 s.addElement(seq[i]);
1618 if (tchain != null && i < tchain.length)
1620 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
1624 SequenceI[] tmp = new SequenceI[s.size()];
1629 String[] tch = new String[c.size()];
1631 for (int i = 0; i < tch.length; i++)
1633 if (tch[i] == nullChain)
1649 * @return text report of alignment between pdbfile and any associated
1650 * alignment sequences
1652 public String printMapping(String pdbfile)
1654 return ssm.printMapping(pdbfile);
1658 public void resizeInnerPanel(String data)
1660 // Jalview doesn't honour resize panel requests