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;
473 // TODO: consider bailing if nmatched less than 4 because superposition
476 // TODO: refactor superposable position search (above) from jmol selection
477 // construction (below)
479 String[] selcom = new String[files.length];
481 // generate select statements to select regions to superimpose structures
483 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
485 String chainCd = targetC[pdbfnum];
488 StringBuffer molsel = new StringBuffer();
490 for (int r = 0; r < matched.length; r++)
498 if (lpos != commonrpositions[pdbfnum][r] - 1)
504 molsel.append(chainCd);
505 // molsel.append("} {");
511 // continuous run - and lpos >-1
514 // at the beginning, so add dash
520 lpos = commonrpositions[pdbfnum][r];
521 // molsel.append(lpos);
524 // add final selection phrase
528 molsel.append(chainCd);
531 selcom[pdbfnum] = molsel.toString();
532 selectioncom.append("((");
533 selectioncom.append(selcom[pdbfnum].substring(1,
534 selcom[pdbfnum].length() - 1));
535 selectioncom.append(" )& ");
536 selectioncom.append(pdbfnum + 1);
537 selectioncom.append(".1)");
538 if (pdbfnum < files.length - 1)
540 selectioncom.append("|");
544 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
546 if (pdbfnum == refStructure)
550 command.append("echo ");
551 command.append("\"Superposing (");
552 command.append(chainNames[pdbfnum]);
553 command.append(") against reference (");
554 command.append(chainNames[refStructure]);
555 command.append(")\";\ncompare ");
557 command.append(1 + pdbfnum);
558 command.append(".1} {");
559 command.append(1 + refStructure);
560 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
562 // form the matched pair strings
564 for (int s = 0; s < 2; s++)
566 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
568 command.append(" ROTATE TRANSLATE;\n");
570 System.out.println("Select regions:\n" + selectioncom.toString());
571 evalStateCommand("select *; cartoons off; backbone; select ("
572 + selectioncom.toString() + "); cartoons; ");
573 // selcom.append("; ribbons; ");
574 System.out.println("Superimpose command(s):\n" + command.toString());
576 evalStateCommand(command.toString());
578 if (selectioncom.length() > 0)
579 {// finally, mark all regions that were superposed.
580 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
582 selectioncom.setLength(selectioncom.length() - 1);
584 System.out.println("Select regions:\n" + selectioncom.toString());
585 evalStateCommand("select *; cartoons off; backbone; select ("
586 + selectioncom.toString() + "); cartoons; ");
587 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
591 public void evalStateCommand(String command)
594 if (lastCommand == null || !lastCommand.equals(command))
596 viewer.evalStringQuiet(command + "\n");
599 lastCommand = command;
603 * colour any structures associated with sequences in the given alignment
604 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
605 * if colourBySequence is enabled.
607 public void colourBySequence(boolean showFeatures,
608 jalview.api.AlignmentViewPanel alignmentv)
610 if (!colourBySequence || !loadingFinished)
616 String[] files = getPdbFile();
618 SequenceRenderer sr = getSequenceRenderer(alignmentv);
620 FeatureRenderer fr = null;
623 fr = getFeatureRenderer(alignmentv);
625 AlignmentI alignment = alignmentv.getAlignment();
627 for (jalview.structure.StructureMappingcommandSet cpdbbyseq : JmolCommands
628 .getColourBySequenceCommand(ssm, files, sequence, sr, fr,
630 for (String cbyseq : cpdbbyseq.commands)
632 evalStateCommand(cbyseq);
636 public boolean isColourBySequence()
638 return colourBySequence;
641 public void setColourBySequence(boolean colourBySequence)
643 this.colourBySequence = colourBySequence;
646 public void createImage(String file, String type, int quality)
648 System.out.println("JMOL CREATE IMAGE");
651 public String createImage(String fileName, String type,
652 Object textOrBytes, int quality)
654 System.out.println("JMOL CREATE IMAGE");
658 public String eval(String strEval)
660 // System.out.println(strEval);
661 // "# 'eval' is implemented only for the applet.";
665 // End StructureListener
666 // //////////////////////////
668 public float[][] functionXY(String functionName, int x, int y)
673 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
675 // TODO Auto-generated method stub
679 public Color getColour(int atomIndex, int pdbResNum, String chain,
682 if (getModelNum(pdbfile) < 0)
684 // TODO: verify atomIndex is selecting correct model.
685 return new Color(viewer.getAtomArgb(atomIndex));
689 * returns the current featureRenderer that should be used to colour the
696 public abstract FeatureRenderer getFeatureRenderer(
697 AlignmentViewPanel alignment);
700 * instruct the Jalview binding to update the pdbentries vector if necessary
701 * prior to matching the jmol view's contents to the list of structure files
702 * Jalview knows about.
704 public abstract void refreshPdbEntries();
706 private int getModelNum(String modelFileName)
708 String[] mfn = getPdbFile();
713 for (int i = 0; i < mfn.length; i++)
715 if (mfn[i].equalsIgnoreCase(modelFileName))
722 * map between index of model filename returned from getPdbFile and the first
723 * index of models from this file in the viewer. Note - this is not trimmed -
724 * use getPdbFile to get number of unique models.
726 private int _modelFileNameMap[];
728 // ////////////////////////////////
729 // /StructureListener
730 public synchronized String[] getPdbFile()
734 return new String[0];
736 if (modelFileNames == null)
739 String mset[] = new String[viewer.getModelCount()];
740 _modelFileNameMap = new int[mset.length];
742 String m = viewer.getModelFileName(0);
747 mset[0] = new File(m).getAbsolutePath();
748 } catch (AccessControlException x)
750 // usually not allowed to do this in applet, so keep raw handle
752 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
755 for (int i = 1; i < mset.length; i++)
757 m = viewer.getModelFileName(i);
762 mset[j] = new File(m).getAbsolutePath();
763 } catch (AccessControlException x)
765 // usually not allowed to do this in applet, so keep raw handle
767 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
770 _modelFileNameMap[j] = i; // record the model index for the filename
771 // skip any additional models in the same file (NMR structures)
772 if ((mset[j] == null ? mset[j] != mset[j - 1]
773 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
778 modelFileNames = new String[j];
779 System.arraycopy(mset, 0, modelFileNames, 0, j);
781 return modelFileNames;
785 * map from string to applet
787 public Map getRegistryInfo()
789 // TODO Auto-generated method stub
794 * returns the current sequenceRenderer that should be used to colour the
801 public abstract SequenceRenderer getSequenceRenderer(
802 AlignmentViewPanel alignment);
804 // ///////////////////////////////
805 // JmolStatusListener
807 public void handlePopupMenu(int x, int y)
809 jmolpopup.show(x, y);
813 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
816 if (modelFileNames == null)
821 // look up file model number for this pdbfile
824 // may need to adjust for URLencoding here - we don't worry about that yet.
825 while (mdlNum < modelFileNames.length
826 && !pdbfile.equals(modelFileNames[mdlNum]))
828 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
831 if (mdlNum == modelFileNames.length)
837 // if (!pdbfile.equals(pdbentry.getFile()))
839 if (resetLastRes.length() > 0)
841 viewer.evalStringQuiet(resetLastRes.toString());
845 eval.append("select " + pdbResNum); // +modelNum
847 resetLastRes.setLength(0);
848 resetLastRes.append("select " + pdbResNum); // +modelNum
851 resetLastRes.append(":");
852 if (!chain.equals(" "))
855 resetLastRes.append(chain);
858 eval.append(" /" + (mdlNum + 1));
859 resetLastRes.append("/" + (mdlNum + 1));
861 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
863 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
864 + " and not hetero; spacefill 0;");
866 eval.append("spacefill 200;select none");
868 viewer.evalStringQuiet(eval.toString());
873 boolean debug = true;
875 private void jmolHistory(boolean enable)
877 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
880 public void loadInline(String string)
884 // viewer.loadInline(strModel, isAppend);
886 // construct fake fullPathName and fileName so we can identify the file
888 // Then, construct pass a reader for the string to Jmol.
889 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
890 // fileName, null, reader, false, null, null, 0);
891 viewer.openStringInline(string);
894 public void mouseOverStructure(int atomIndex, String strInfo)
897 int alocsep = strInfo.indexOf("^");
898 int mdlSep = strInfo.indexOf("/");
899 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
901 if (chainSeparator == -1)
903 chainSeparator = strInfo.indexOf(".");
904 if (mdlSep > -1 && mdlSep < chainSeparator)
906 chainSeparator1 = chainSeparator;
907 chainSeparator = mdlSep;
910 // handle insertion codes
913 pdbResNum = Integer.parseInt(strInfo.substring(
914 strInfo.indexOf("]") + 1, alocsep));
919 pdbResNum = Integer.parseInt(strInfo.substring(
920 strInfo.indexOf("]") + 1, chainSeparator));
924 if (strInfo.indexOf(":") > -1)
925 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
926 strInfo.indexOf("."));
932 String pdbfilename = modelFileNames[frameNo]; // default is first or current
936 if (chainSeparator1 == -1)
938 chainSeparator1 = strInfo.indexOf(".", mdlSep);
940 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
941 chainSeparator1) : strInfo.substring(mdlSep + 1);
944 // recover PDB filename for the model hovered over.
945 int _mp = _modelFileNameMap.length - 1, mnumber = new Integer(mdlId)
947 while (mnumber < _modelFileNameMap[_mp])
951 pdbfilename = modelFileNames[_mp];
952 if (pdbfilename == null)
954 pdbfilename = new File(viewer.getModelFileName(mnumber))
958 } catch (Exception e)
963 if (lastMessage == null || !lastMessage.equals(strInfo))
964 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
966 lastMessage = strInfo;
969 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
973 System.err.println("Ignoring additional hover info: " + data
974 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
976 mouseOverStructure(atomIndex, strInfo);
980 * { if (history != null && strStatus != null &&
981 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
985 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
988 * this implements the toggle label behaviour copied from the original
989 * structure viewer, MCView
993 System.err.println("Ignoring additional pick data string " + strData);
995 int chainSeparator = strInfo.indexOf(":");
997 if (chainSeparator == -1)
998 chainSeparator = strInfo.indexOf(".");
1000 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
1002 String mdlString = "";
1003 if ((p = strInfo.indexOf(":")) > -1)
1004 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
1006 if ((p = strInfo.indexOf("/")) > -1)
1008 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
1010 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
1014 if (!atomsPicked.contains(picked))
1016 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
1017 atomsPicked.addElement(picked);
1021 viewer.evalString("select " + picked + ";label off");
1022 atomsPicked.removeElement(picked);
1025 // TODO: in application this happens
1027 // if (scriptWindow != null)
1029 // scriptWindow.sendConsoleMessage(strInfo);
1030 // scriptWindow.sendConsoleMessage("\n");
1036 public void notifyCallback(EnumCallback type, Object[] data)
1043 notifyFileLoaded((String) data[1], (String) data[2],
1044 (String) data[3], (String) data[4],
1045 ((Integer) data[5]).intValue());
1049 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
1051 // also highlight in alignment
1053 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1057 notifyScriptTermination((String) data[2],
1058 ((Integer) data[3]).intValue());
1061 sendConsoleEcho((String) data[1]);
1064 sendConsoleMessage((data == null) ? ((String) null)
1065 : (String) data[1]);
1068 // System.err.println("Ignoring error callback.");
1078 System.err.println("Unhandled callback " + type + " "
1079 + data[1].toString());
1082 } catch (Exception e)
1084 System.err.println("Squashed Jmol callback handler error:");
1085 e.printStackTrace();
1090 public boolean notifyEnabled(EnumCallback callbackPick)
1092 switch (callbackPick)
1112 // incremented every time a load notification is successfully handled -
1113 // lightweight mechanism for other threads to detect when they can start
1114 // referrring to new structures.
1115 private long loadNotifiesHandled = 0;
1117 public long getLoadNotifiesHandled()
1119 return loadNotifiesHandled;
1122 public void notifyFileLoaded(String fullPathName, String fileName2,
1123 String modelName, String errorMsg, int modelParts)
1125 if (errorMsg != null)
1127 fileLoadingError = errorMsg;
1131 // TODO: deal sensibly with models loaded inLine:
1132 // modelName will be null, as will fullPathName.
1134 // the rest of this routine ignores the arguments, and simply interrogates
1135 // the Jmol view to find out what structures it contains, and adds them to
1136 // the structure selection manager.
1137 fileLoadingError = null;
1138 String[] oldmodels = modelFileNames;
1139 modelFileNames = null;
1140 chainNames = new Vector();
1141 chainFile = new Hashtable();
1142 boolean notifyLoaded = false;
1143 String[] modelfilenames = getPdbFile();
1144 // first check if we've lost any structures
1145 if (oldmodels != null && oldmodels.length > 0)
1148 for (int i = 0; i < oldmodels.length; i++)
1150 for (int n = 0; n < modelfilenames.length; n++)
1152 if (modelfilenames[n] == oldmodels[i])
1154 oldmodels[i] = null;
1158 if (oldmodels[i] != null)
1165 String[] oldmfn = new String[oldm];
1167 for (int i = 0; i < oldmodels.length; i++)
1169 if (oldmodels[i] != null)
1171 oldmfn[oldm++] = oldmodels[i];
1174 // deregister the Jmol instance for these structures - we'll add
1175 // ourselves again at the end for the current structure set.
1176 ssm.removeStructureViewerListener(this, oldmfn);
1179 refreshPdbEntries();
1180 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1182 String fileName = modelfilenames[modelnum];
1183 boolean foundEntry = false;
1184 MCview.PDBfile pdb = null;
1185 String pdbfile = null, pdbfhash = null;
1186 // model was probably loaded inline - so check the pdb file hashcode
1189 // calculate essential attributes for the pdb data imported inline.
1190 // prolly need to resolve modelnumber properly - for now just use our
1192 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1194 pdbfhash = "" + pdbfile.hashCode();
1196 if (pdbentry != null)
1198 // search pdbentries and sequences to find correct pdbentry for this
1200 for (int pe = 0; pe < pdbentry.length; pe++)
1202 boolean matches = false;
1203 if (fileName == null)
1206 // see JAL-623 - need method of matching pasted data up
1208 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
1209 AppletFormatAdapter.PASTE);
1210 pdbentry[modelnum].setFile("INLINE" + pdb.id);
1218 if (matches = (fl = new File(pdbentry[pe].getFile()))
1219 .equals(new File(fileName)))
1222 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1225 // to be tested. See mantis bug
1226 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1227 String protocol = AppletFormatAdapter.URL;
1232 protocol = AppletFormatAdapter.FILE;
1234 } catch (Exception e)
1239 // Explicitly map to the filename used by Jmol ;
1240 pdb = ssm.setMapping(sequence[pe], chains[pe], fileName,
1242 // pdbentry[pe].getFile(), protocol);
1248 // add an entry for every chain in the model
1249 for (int i = 0; i < pdb.chains.size(); i++)
1251 String chid = new String(pdb.id + ":"
1252 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
1253 chainFile.put(chid, fileName);
1254 chainNames.addElement(chid);
1256 notifyLoaded = true;
1260 if (!foundEntry && associateNewStructs)
1262 // this is a foreign pdb file that jalview doesn't know about - add
1263 // it to the dataset and try to find a home - either on a matching
1264 // sequence or as a new sequence.
1265 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1267 // parse pdb file into a chain, etc.
1268 // locate best match for pdb in associated views and add mapping to
1270 // if properly registered then
1271 notifyLoaded = true;
1276 // so finally, update the jmol bits and pieces
1277 if (jmolpopup != null)
1279 // potential for deadlock here:
1280 // jmolpopup.updateComputedMenus();
1282 if (!isLoadingFromArchive())
1284 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1286 // register ourselves as a listener and notify the gui that it needs to
1288 ssm.addStructureViewerListener(this);
1291 FeatureRenderer fr = getFeatureRenderer(null);
1297 loadNotifiesHandled++;
1299 setLoadingFromArchive(false);
1302 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1304 notifyAtomPicked(iatom, strMeasure, null);
1307 public abstract void notifyScriptTermination(String strStatus,
1311 * display a message echoed from the jmol viewer
1315 public abstract void sendConsoleEcho(String strEcho); /*
1316 * { showConsole(true);
1318 * history.append("\n" +
1322 // /End JmolStatusListener
1323 // /////////////////////////////
1327 * status message - usually the response received after a script
1330 public abstract void sendConsoleMessage(String strStatus);
1332 public void setCallbackFunction(String callbackType,
1333 String callbackFunction)
1335 System.err.println("Ignoring set-callback request to associate "
1336 + callbackType + " with function " + callbackFunction);
1340 public void setJalviewColourScheme(ColourSchemeI cs)
1342 colourBySequence = false;
1351 // TODO: Switch between nucleotide or aa selection expressions
1352 Enumeration en = ResidueProperties.aa3Hash.keys();
1353 StringBuffer command = new StringBuffer("select *;color white;");
1354 while (en.hasMoreElements())
1356 res = en.nextElement().toString();
1357 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
1361 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
1363 command.append("select " + res + ";color[" + col.getRed() + ","
1364 + col.getGreen() + "," + col.getBlue() + "];");
1367 evalStateCommand(command.toString());
1371 public void showHelp()
1373 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1377 * open the URL somehow
1381 public abstract void showUrl(String url, String target);
1384 * called when the binding thinks the UI needs to be refreshed after a Jmol
1385 * state change. this could be because structures were loaded, or because an
1386 * error has occured.
1388 public abstract void refreshGUI();
1391 * called to show or hide the associated console window container.
1395 public abstract void showConsole(boolean show);
1398 * @param renderPanel
1400 * - when true will initialise jmol's file IO system (should be false
1401 * in applet context)
1403 * @param documentBase
1405 * @param commandOptions
1407 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1408 String htmlName, URL documentBase, URL codeBase,
1409 String commandOptions)
1411 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1412 codeBase, commandOptions, null, null);
1417 * @param renderPanel
1419 * - when true will initialise jmol's file IO system (should be false
1420 * in applet context)
1422 * @param documentBase
1424 * @param commandOptions
1425 * @param consolePanel
1426 * - panel to contain Jmol console
1427 * @param buttonsToShow
1428 * - buttons to show on the console, in ordr
1430 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1431 String htmlName, URL documentBase, URL codeBase,
1432 String commandOptions, final Container consolePanel,
1433 String buttonsToShow)
1435 if (commandOptions == null)
1437 commandOptions = "";
1439 viewer = JmolViewer.allocateViewer(renderPanel,
1440 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1441 + ((Object) this).toString(), documentBase, codeBase,
1442 commandOptions, this);
1444 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
1445 if (consolePanel != null)
1447 consolePanel.addComponentListener(this);
1453 protected abstract JmolAppConsoleInterface createJmolConsole(
1454 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
1456 protected org.jmol.api.JmolAppConsoleInterface console = null;
1458 public void componentResized(ComponentEvent e)
1463 public void componentMoved(ComponentEvent e)
1468 public void componentShown(ComponentEvent e)
1473 public void componentHidden(ComponentEvent e)
1478 public void setLoadingFromArchive(boolean loadingFromArchive)
1480 this.loadingFromArchive = loadingFromArchive;
1485 * @return true if Jmol is still restoring state or loading is still going on (see setFinsihedLoadingFromArchive)
1487 public boolean isLoadingFromArchive()
1489 return loadingFromArchive && !loadingFinished;
1493 * modify flag which controls if sequence colouring events are honoured by the binding.
1494 * Should be true for normal operation
1495 * @param finishedLoading
1497 public void setFinishedLoadingFromArchive(boolean finishedLoading)
1499 loadingFinished = finishedLoading;
1502 public void setBackgroundColour(java.awt.Color col)
1505 viewer.evalStringQuiet("background [" + col.getRed() + ","
1506 + col.getGreen() + "," + col.getBlue() + "];");
1511 * add structures and any known sequence associations
1513 * @returns the pdb entries added to the current set.
1515 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
1516 SequenceI[][] seq, String[][] chns)
1519 Vector v = new Vector();
1520 Vector rtn = new Vector();
1521 for (int i = 0; i < pdbentry.length; i++)
1523 v.addElement(pdbentry[i]);
1525 for (int i = 0; i < pdbe.length; i++)
1527 int r = v.indexOf(pdbe[i]);
1528 if (r == -1 || r >= pdbentry.length)
1530 rtn.addElement(new int[]
1532 v.addElement(pdbe[i]);
1536 // just make sure the sequence/chain entries are all up to date
1537 addSequenceAndChain(r, seq[i], chns[i]);
1540 pdbe = new PDBEntry[v.size()];
1545 // expand the tied seuqence[] and string[] arrays
1546 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
1547 String[][] sch = new String[pdbentry.length][];
1548 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
1549 System.arraycopy(chains, 0, sch, 0, this.chains.length);
1552 pdbe = new PDBEntry[rtn.size()];
1553 for (int r = 0; r < pdbe.length; r++)
1555 int[] stri = ((int[]) rtn.elementAt(r));
1556 // record the pdb file as a new addition
1557 pdbe[r] = pdbentry[stri[0]];
1558 // and add the new sequence/chain entries
1559 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
1569 public void addSequence(int pe, SequenceI[] seq)
1571 // add sequences to the pe'th pdbentry's seuqence set.
1572 addSequenceAndChain(pe, seq, null);
1575 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
1577 if (pe < 0 || pe >= pdbentry.length)
1580 "Implementation error - no corresponding pdbentry (for index "
1581 + pe + ") to add sequences mappings to");
1583 final String nullChain = "TheNullChain";
1584 Vector s = new Vector();
1585 Vector c = new Vector();
1588 chains = new String[pdbentry.length][];
1590 if (sequence[pe] != null)
1592 for (int i = 0; i < sequence[pe].length; i++)
1594 s.addElement(sequence[pe][i]);
1595 if (chains[pe] != null)
1597 if (i < chains[pe].length)
1599 c.addElement(chains[pe][i]);
1603 c.addElement(nullChain);
1608 if (tchain != null && tchain.length > 0)
1610 c.addElement(nullChain);
1615 for (int i = 0; i < seq.length; i++)
1617 if (!s.contains(seq[i]))
1619 s.addElement(seq[i]);
1620 if (tchain != null && i < tchain.length)
1622 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
1626 SequenceI[] tmp = new SequenceI[s.size()];
1631 String[] tch = new String[c.size()];
1633 for (int i = 0; i < tch.length; i++)
1635 if (tch[i] == nullChain)
1651 * @return text report of alignment between pdbfile and any associated
1652 * alignment sequences
1654 public String printMapping(String pdbfile)
1656 return ssm.printMapping(pdbfile);
1660 public void resizeInnerPanel(String data)
1662 // Jalview doesn't honour resize panel requests