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)
407 throw new Error("Implementation error - Jmol seems to be still working on getting its data - report at http://issues.jalview.org/browse/JAL-1016");
410 for (int s = 0; s < sequence[pdbfnum].length; s++)
412 for (int sp, m = 0; m < mapping.length; m++)
414 if (mapping[m].getSequence() == sequence[pdbfnum][s]
415 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
417 if (refStructure == -1)
419 refStructure = pdbfnum;
421 SequenceI asp = alignment.getSequenceAt(sp);
422 for (int r = 0; r < matched.length; r++)
428 matched[r] = false; // assume this is not a good site
429 if (r >= asp.getLength())
434 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
436 // no mapping to gaps in sequence
439 int t = asp.findPosition(r); // sequence position
440 int apos = mapping[m].getAtomNum(t);
441 int pos = mapping[m].getPDBResNum(t);
443 if (pos < 1 || pos == lastPos)
445 // can't align unmapped sequence
448 matched[r] = true; // this is a good ite
450 // just record this residue position
451 commonrpositions[pdbfnum][r] = pos;
453 // create model selection suffix
454 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
455 if (mapping[m].getChain() == null
456 || mapping[m].getChain().trim().length() == 0)
458 targetC[pdbfnum] = "";
462 targetC[pdbfnum] = ":" + mapping[m].getChain();
464 chainNames[pdbfnum] = mapping[m].getPdbId()
466 // move on to next pdb file
467 s = sequence[pdbfnum].length;
474 // TODO: consider bailing if nmatched less than 4 because superposition
477 // TODO: refactor superposable position search (above) from jmol selection
478 // construction (below)
480 String[] selcom = new String[files.length];
482 // generate select statements to select regions to superimpose structures
484 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
486 String chainCd = targetC[pdbfnum];
489 StringBuffer molsel = new StringBuffer();
491 for (int r = 0; r < matched.length; r++)
499 if (lpos != commonrpositions[pdbfnum][r] - 1)
505 molsel.append(chainCd);
506 // molsel.append("} {");
512 // continuous run - and lpos >-1
515 // at the beginning, so add dash
521 lpos = commonrpositions[pdbfnum][r];
522 // molsel.append(lpos);
525 // add final selection phrase
529 molsel.append(chainCd);
532 selcom[pdbfnum] = molsel.toString();
533 selectioncom.append("((");
534 selectioncom.append(selcom[pdbfnum].substring(1,
535 selcom[pdbfnum].length() - 1));
536 selectioncom.append(" )& ");
537 selectioncom.append(pdbfnum + 1);
538 selectioncom.append(".1)");
539 if (pdbfnum < files.length - 1)
541 selectioncom.append("|");
545 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
547 if (pdbfnum == refStructure)
551 command.append("echo ");
552 command.append("\"Superposing (");
553 command.append(chainNames[pdbfnum]);
554 command.append(") against reference (");
555 command.append(chainNames[refStructure]);
556 command.append(")\";\ncompare ");
558 command.append(1 + pdbfnum);
559 command.append(".1} {");
560 command.append(1 + refStructure);
561 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
563 // form the matched pair strings
565 for (int s = 0; s < 2; s++)
567 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
569 command.append(" ROTATE TRANSLATE;\n");
571 System.out.println("Select regions:\n" + selectioncom.toString());
572 evalStateCommand("select *; cartoons off; backbone; select ("
573 + selectioncom.toString() + "); cartoons; ");
574 // selcom.append("; ribbons; ");
575 System.out.println("Superimpose command(s):\n" + command.toString());
577 evalStateCommand(command.toString());
579 if (selectioncom.length() > 0)
580 {// finally, mark all regions that were superposed.
581 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
583 selectioncom.setLength(selectioncom.length() - 1);
585 System.out.println("Select regions:\n" + selectioncom.toString());
586 evalStateCommand("select *; cartoons off; backbone; select ("
587 + selectioncom.toString() + "); cartoons; ");
588 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
592 public void evalStateCommand(String command)
595 if (lastCommand == null || !lastCommand.equals(command))
597 viewer.evalStringQuiet(command + "\n");
600 lastCommand = command;
604 * colour any structures associated with sequences in the given alignment
605 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
606 * if colourBySequence is enabled.
608 public void colourBySequence(boolean showFeatures,
609 jalview.api.AlignmentViewPanel alignmentv)
611 if (!colourBySequence || !loadingFinished)
617 String[] files = getPdbFile();
619 SequenceRenderer sr = getSequenceRenderer(alignmentv);
621 FeatureRenderer fr = null;
624 fr = getFeatureRenderer(alignmentv);
626 AlignmentI alignment = alignmentv.getAlignment();
628 for (jalview.structure.StructureMappingcommandSet cpdbbyseq : JmolCommands
629 .getColourBySequenceCommand(ssm, files, sequence, sr, fr,
631 for (String cbyseq : cpdbbyseq.commands)
633 evalStateCommand(cbyseq);
637 public boolean isColourBySequence()
639 return colourBySequence;
642 public void setColourBySequence(boolean colourBySequence)
644 this.colourBySequence = colourBySequence;
647 public void createImage(String file, String type, int quality)
649 System.out.println("JMOL CREATE IMAGE");
652 public String createImage(String fileName, String type,
653 Object textOrBytes, int quality)
655 System.out.println("JMOL CREATE IMAGE");
659 public String eval(String strEval)
661 // System.out.println(strEval);
662 // "# 'eval' is implemented only for the applet.";
666 // End StructureListener
667 // //////////////////////////
669 public float[][] functionXY(String functionName, int x, int y)
674 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
676 // TODO Auto-generated method stub
680 public Color getColour(int atomIndex, int pdbResNum, String chain,
683 if (getModelNum(pdbfile) < 0)
685 // TODO: verify atomIndex is selecting correct model.
686 return new Color(viewer.getAtomArgb(atomIndex));
690 * returns the current featureRenderer that should be used to colour the
697 public abstract FeatureRenderer getFeatureRenderer(
698 AlignmentViewPanel alignment);
701 * instruct the Jalview binding to update the pdbentries vector if necessary
702 * prior to matching the jmol view's contents to the list of structure files
703 * Jalview knows about.
705 public abstract void refreshPdbEntries();
707 private int getModelNum(String modelFileName)
709 String[] mfn = getPdbFile();
714 for (int i = 0; i < mfn.length; i++)
716 if (mfn[i].equalsIgnoreCase(modelFileName))
723 * map between index of model filename returned from getPdbFile and the first
724 * index of models from this file in the viewer. Note - this is not trimmed -
725 * use getPdbFile to get number of unique models.
727 private int _modelFileNameMap[];
729 // ////////////////////////////////
730 // /StructureListener
731 public synchronized String[] getPdbFile()
735 return new String[0];
737 if (modelFileNames == null)
740 String mset[] = new String[viewer.getModelCount()];
741 _modelFileNameMap = new int[mset.length];
743 String m = viewer.getModelFileName(0);
748 mset[0] = new File(m).getAbsolutePath();
749 } catch (AccessControlException x)
751 // usually not allowed to do this in applet, so keep raw handle
753 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
756 for (int i = 1; i < mset.length; i++)
758 m = viewer.getModelFileName(i);
763 mset[j] = new File(m).getAbsolutePath();
764 } catch (AccessControlException x)
766 // usually not allowed to do this in applet, so keep raw handle
768 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
771 _modelFileNameMap[j] = i; // record the model index for the filename
772 // skip any additional models in the same file (NMR structures)
773 if ((mset[j] == null ? mset[j] != mset[j - 1]
774 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
779 modelFileNames = new String[j];
780 System.arraycopy(mset, 0, modelFileNames, 0, j);
782 return modelFileNames;
786 * map from string to applet
788 public Map getRegistryInfo()
790 // TODO Auto-generated method stub
795 * returns the current sequenceRenderer that should be used to colour the
802 public abstract SequenceRenderer getSequenceRenderer(
803 AlignmentViewPanel alignment);
805 // ///////////////////////////////
806 // JmolStatusListener
808 public void handlePopupMenu(int x, int y)
810 jmolpopup.show(x, y);
814 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
817 if (modelFileNames == null)
822 // look up file model number for this pdbfile
825 // may need to adjust for URLencoding here - we don't worry about that yet.
826 while (mdlNum < modelFileNames.length
827 && !pdbfile.equals(modelFileNames[mdlNum]))
829 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
832 if (mdlNum == modelFileNames.length)
838 // if (!pdbfile.equals(pdbentry.getFile()))
840 if (resetLastRes.length() > 0)
842 viewer.evalStringQuiet(resetLastRes.toString());
846 eval.append("select " + pdbResNum); // +modelNum
848 resetLastRes.setLength(0);
849 resetLastRes.append("select " + pdbResNum); // +modelNum
852 resetLastRes.append(":");
853 if (!chain.equals(" "))
856 resetLastRes.append(chain);
859 eval.append(" /" + (mdlNum + 1));
860 resetLastRes.append("/" + (mdlNum + 1));
862 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
864 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
865 + " and not hetero; spacefill 0;");
867 eval.append("spacefill 200;select none");
869 viewer.evalStringQuiet(eval.toString());
874 boolean debug = true;
876 private void jmolHistory(boolean enable)
878 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
881 public void loadInline(String string)
885 // viewer.loadInline(strModel, isAppend);
887 // construct fake fullPathName and fileName so we can identify the file
889 // Then, construct pass a reader for the string to Jmol.
890 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
891 // fileName, null, reader, false, null, null, 0);
892 viewer.openStringInline(string);
895 public void mouseOverStructure(int atomIndex, String strInfo)
898 int alocsep = strInfo.indexOf("^");
899 int mdlSep = strInfo.indexOf("/");
900 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
902 if (chainSeparator == -1)
904 chainSeparator = strInfo.indexOf(".");
905 if (mdlSep > -1 && mdlSep < chainSeparator)
907 chainSeparator1 = chainSeparator;
908 chainSeparator = mdlSep;
911 // handle insertion codes
914 pdbResNum = Integer.parseInt(strInfo.substring(
915 strInfo.indexOf("]") + 1, alocsep));
920 pdbResNum = Integer.parseInt(strInfo.substring(
921 strInfo.indexOf("]") + 1, chainSeparator));
925 if (strInfo.indexOf(":") > -1)
926 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
927 strInfo.indexOf("."));
933 String pdbfilename = modelFileNames[frameNo]; // default is first or current
937 if (chainSeparator1 == -1)
939 chainSeparator1 = strInfo.indexOf(".", mdlSep);
941 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
942 chainSeparator1) : strInfo.substring(mdlSep + 1);
945 // recover PDB filename for the model hovered over.
946 int _mp = _modelFileNameMap.length - 1, mnumber = new Integer(mdlId)
948 while (mnumber < _modelFileNameMap[_mp])
952 pdbfilename = modelFileNames[_mp];
953 if (pdbfilename == null)
955 pdbfilename = new File(viewer.getModelFileName(mnumber))
959 } catch (Exception e)
964 if (lastMessage == null || !lastMessage.equals(strInfo))
965 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
967 lastMessage = strInfo;
970 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
974 System.err.println("Ignoring additional hover info: " + data
975 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
977 mouseOverStructure(atomIndex, strInfo);
981 * { if (history != null && strStatus != null &&
982 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
986 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
989 * this implements the toggle label behaviour copied from the original
990 * structure viewer, MCView
994 System.err.println("Ignoring additional pick data string " + strData);
996 int chainSeparator = strInfo.indexOf(":");
998 if (chainSeparator == -1)
999 chainSeparator = strInfo.indexOf(".");
1001 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
1003 String mdlString = "";
1004 if ((p = strInfo.indexOf(":")) > -1)
1005 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
1007 if ((p = strInfo.indexOf("/")) > -1)
1009 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
1011 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
1015 if (!atomsPicked.contains(picked))
1017 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
1018 atomsPicked.addElement(picked);
1022 viewer.evalString("select " + picked + ";label off");
1023 atomsPicked.removeElement(picked);
1026 // TODO: in application this happens
1028 // if (scriptWindow != null)
1030 // scriptWindow.sendConsoleMessage(strInfo);
1031 // scriptWindow.sendConsoleMessage("\n");
1037 public void notifyCallback(EnumCallback type, Object[] data)
1044 notifyFileLoaded((String) data[1], (String) data[2],
1045 (String) data[3], (String) data[4],
1046 ((Integer) data[5]).intValue());
1050 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
1052 // also highlight in alignment
1054 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1058 notifyScriptTermination((String) data[2],
1059 ((Integer) data[3]).intValue());
1062 sendConsoleEcho((String) data[1]);
1065 sendConsoleMessage((data == null) ? ((String) null)
1066 : (String) data[1]);
1069 // System.err.println("Ignoring error callback.");
1079 System.err.println("Unhandled callback " + type + " "
1080 + data[1].toString());
1083 } catch (Exception e)
1085 System.err.println("Squashed Jmol callback handler error:");
1086 e.printStackTrace();
1091 public boolean notifyEnabled(EnumCallback callbackPick)
1093 switch (callbackPick)
1113 // incremented every time a load notification is successfully handled -
1114 // lightweight mechanism for other threads to detect when they can start
1115 // referrring to new structures.
1116 private long loadNotifiesHandled = 0;
1118 public long getLoadNotifiesHandled()
1120 return loadNotifiesHandled;
1123 public void notifyFileLoaded(String fullPathName, String fileName2,
1124 String modelName, String errorMsg, int modelParts)
1126 if (errorMsg != null)
1128 fileLoadingError = errorMsg;
1132 // TODO: deal sensibly with models loaded inLine:
1133 // modelName will be null, as will fullPathName.
1135 // the rest of this routine ignores the arguments, and simply interrogates
1136 // the Jmol view to find out what structures it contains, and adds them to
1137 // the structure selection manager.
1138 fileLoadingError = null;
1139 String[] oldmodels = modelFileNames;
1140 modelFileNames = null;
1141 chainNames = new Vector();
1142 chainFile = new Hashtable();
1143 boolean notifyLoaded = false;
1144 String[] modelfilenames = getPdbFile();
1145 // first check if we've lost any structures
1146 if (oldmodels != null && oldmodels.length > 0)
1149 for (int i = 0; i < oldmodels.length; i++)
1151 for (int n = 0; n < modelfilenames.length; n++)
1153 if (modelfilenames[n] == oldmodels[i])
1155 oldmodels[i] = null;
1159 if (oldmodels[i] != null)
1166 String[] oldmfn = new String[oldm];
1168 for (int i = 0; i < oldmodels.length; i++)
1170 if (oldmodels[i] != null)
1172 oldmfn[oldm++] = oldmodels[i];
1175 // deregister the Jmol instance for these structures - we'll add
1176 // ourselves again at the end for the current structure set.
1177 ssm.removeStructureViewerListener(this, oldmfn);
1180 refreshPdbEntries();
1181 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1183 String fileName = modelfilenames[modelnum];
1184 boolean foundEntry = false;
1185 MCview.PDBfile pdb = null;
1186 String pdbfile = null, pdbfhash = null;
1187 // model was probably loaded inline - so check the pdb file hashcode
1190 // calculate essential attributes for the pdb data imported inline.
1191 // prolly need to resolve modelnumber properly - for now just use our
1193 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1195 pdbfhash = "" + pdbfile.hashCode();
1197 if (pdbentry != null)
1199 // search pdbentries and sequences to find correct pdbentry for this
1201 for (int pe = 0; pe < pdbentry.length; pe++)
1203 boolean matches = false;
1204 if (fileName == null)
1207 // see JAL-623 - need method of matching pasted data up
1209 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
1210 AppletFormatAdapter.PASTE);
1211 pdbentry[modelnum].setFile("INLINE" + pdb.id);
1219 if (matches = (fl = new File(pdbentry[pe].getFile()))
1220 .equals(new File(fileName)))
1223 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1226 // to be tested. See mantis bug
1227 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1228 String protocol = AppletFormatAdapter.URL;
1233 protocol = AppletFormatAdapter.FILE;
1235 } catch (Exception e)
1240 // Explicitly map to the filename used by Jmol ;
1241 pdb = ssm.setMapping(sequence[pe], chains[pe], fileName,
1243 // pdbentry[pe].getFile(), protocol);
1249 // add an entry for every chain in the model
1250 for (int i = 0; i < pdb.chains.size(); i++)
1252 String chid = new String(pdb.id + ":"
1253 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
1254 chainFile.put(chid, fileName);
1255 chainNames.addElement(chid);
1257 notifyLoaded = true;
1261 if (!foundEntry && associateNewStructs)
1263 // this is a foreign pdb file that jalview doesn't know about - add
1264 // it to the dataset and try to find a home - either on a matching
1265 // sequence or as a new sequence.
1266 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1268 // parse pdb file into a chain, etc.
1269 // locate best match for pdb in associated views and add mapping to
1271 // if properly registered then
1272 notifyLoaded = true;
1277 // so finally, update the jmol bits and pieces
1278 if (jmolpopup != null)
1280 // potential for deadlock here:
1281 // jmolpopup.updateComputedMenus();
1283 if (!isLoadingFromArchive())
1285 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1287 // register ourselves as a listener and notify the gui that it needs to
1289 ssm.addStructureViewerListener(this);
1292 FeatureRenderer fr = getFeatureRenderer(null);
1298 loadNotifiesHandled++;
1300 setLoadingFromArchive(false);
1303 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1305 notifyAtomPicked(iatom, strMeasure, null);
1308 public abstract void notifyScriptTermination(String strStatus,
1312 * display a message echoed from the jmol viewer
1316 public abstract void sendConsoleEcho(String strEcho); /*
1317 * { showConsole(true);
1319 * history.append("\n" +
1323 // /End JmolStatusListener
1324 // /////////////////////////////
1328 * status message - usually the response received after a script
1331 public abstract void sendConsoleMessage(String strStatus);
1333 public void setCallbackFunction(String callbackType,
1334 String callbackFunction)
1336 System.err.println("Ignoring set-callback request to associate "
1337 + callbackType + " with function " + callbackFunction);
1341 public void setJalviewColourScheme(ColourSchemeI cs)
1343 colourBySequence = false;
1352 // TODO: Switch between nucleotide or aa selection expressions
1353 Enumeration en = ResidueProperties.aa3Hash.keys();
1354 StringBuffer command = new StringBuffer("select *;color white;");
1355 while (en.hasMoreElements())
1357 res = en.nextElement().toString();
1358 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
1362 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
1364 command.append("select " + res + ";color[" + col.getRed() + ","
1365 + col.getGreen() + "," + col.getBlue() + "];");
1368 evalStateCommand(command.toString());
1372 public void showHelp()
1374 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1378 * open the URL somehow
1382 public abstract void showUrl(String url, String target);
1385 * called when the binding thinks the UI needs to be refreshed after a Jmol
1386 * state change. this could be because structures were loaded, or because an
1387 * error has occured.
1389 public abstract void refreshGUI();
1392 * called to show or hide the associated console window container.
1396 public abstract void showConsole(boolean show);
1399 * @param renderPanel
1401 * - when true will initialise jmol's file IO system (should be false
1402 * in applet context)
1404 * @param documentBase
1406 * @param commandOptions
1408 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1409 String htmlName, URL documentBase, URL codeBase,
1410 String commandOptions)
1412 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1413 codeBase, commandOptions, null, null);
1418 * @param renderPanel
1420 * - when true will initialise jmol's file IO system (should be false
1421 * in applet context)
1423 * @param documentBase
1425 * @param commandOptions
1426 * @param consolePanel
1427 * - panel to contain Jmol console
1428 * @param buttonsToShow
1429 * - buttons to show on the console, in ordr
1431 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1432 String htmlName, URL documentBase, URL codeBase,
1433 String commandOptions, final Container consolePanel,
1434 String buttonsToShow)
1436 if (commandOptions == null)
1438 commandOptions = "";
1440 viewer = JmolViewer.allocateViewer(renderPanel,
1441 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1442 + ((Object) this).toString(), documentBase, codeBase,
1443 commandOptions, this);
1445 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
1446 if (consolePanel != null)
1448 consolePanel.addComponentListener(this);
1454 protected abstract JmolAppConsoleInterface createJmolConsole(
1455 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
1457 protected org.jmol.api.JmolAppConsoleInterface console = null;
1459 public void componentResized(ComponentEvent e)
1464 public void componentMoved(ComponentEvent e)
1469 public void componentShown(ComponentEvent e)
1474 public void componentHidden(ComponentEvent e)
1479 public void setLoadingFromArchive(boolean loadingFromArchive)
1481 this.loadingFromArchive = loadingFromArchive;
1486 * @return true if Jmol is still restoring state or loading is still going on (see setFinsihedLoadingFromArchive)
1488 public boolean isLoadingFromArchive()
1490 return loadingFromArchive && !loadingFinished;
1494 * modify flag which controls if sequence colouring events are honoured by the binding.
1495 * Should be true for normal operation
1496 * @param finishedLoading
1498 public void setFinishedLoadingFromArchive(boolean finishedLoading)
1500 loadingFinished = finishedLoading;
1503 public void setBackgroundColour(java.awt.Color col)
1506 viewer.evalStringQuiet("background [" + col.getRed() + ","
1507 + col.getGreen() + "," + col.getBlue() + "];");
1512 * add structures and any known sequence associations
1514 * @returns the pdb entries added to the current set.
1516 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
1517 SequenceI[][] seq, String[][] chns)
1520 Vector v = new Vector();
1521 Vector rtn = new Vector();
1522 for (int i = 0; i < pdbentry.length; i++)
1524 v.addElement(pdbentry[i]);
1526 for (int i = 0; i < pdbe.length; i++)
1528 int r = v.indexOf(pdbe[i]);
1529 if (r == -1 || r >= pdbentry.length)
1531 rtn.addElement(new int[]
1533 v.addElement(pdbe[i]);
1537 // just make sure the sequence/chain entries are all up to date
1538 addSequenceAndChain(r, seq[i], chns[i]);
1541 pdbe = new PDBEntry[v.size()];
1546 // expand the tied seuqence[] and string[] arrays
1547 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
1548 String[][] sch = new String[pdbentry.length][];
1549 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
1550 System.arraycopy(chains, 0, sch, 0, this.chains.length);
1553 pdbe = new PDBEntry[rtn.size()];
1554 for (int r = 0; r < pdbe.length; r++)
1556 int[] stri = ((int[]) rtn.elementAt(r));
1557 // record the pdb file as a new addition
1558 pdbe[r] = pdbentry[stri[0]];
1559 // and add the new sequence/chain entries
1560 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
1570 public void addSequence(int pe, SequenceI[] seq)
1572 // add sequences to the pe'th pdbentry's seuqence set.
1573 addSequenceAndChain(pe, seq, null);
1576 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
1578 if (pe < 0 || pe >= pdbentry.length)
1581 "Implementation error - no corresponding pdbentry (for index "
1582 + pe + ") to add sequences mappings to");
1584 final String nullChain = "TheNullChain";
1585 Vector s = new Vector();
1586 Vector c = new Vector();
1589 chains = new String[pdbentry.length][];
1591 if (sequence[pe] != null)
1593 for (int i = 0; i < sequence[pe].length; i++)
1595 s.addElement(sequence[pe][i]);
1596 if (chains[pe] != null)
1598 if (i < chains[pe].length)
1600 c.addElement(chains[pe][i]);
1604 c.addElement(nullChain);
1609 if (tchain != null && tchain.length > 0)
1611 c.addElement(nullChain);
1616 for (int i = 0; i < seq.length; i++)
1618 if (!s.contains(seq[i]))
1620 s.addElement(seq[i]);
1621 if (tchain != null && i < tchain.length)
1623 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
1627 SequenceI[] tmp = new SequenceI[s.size()];
1632 String[] tch = new String[c.size()];
1634 for (int i = 0; i < tch.length; i++)
1636 if (tch[i] == nullChain)
1652 * @return text report of alignment between pdbfile and any associated
1653 * alignment sequences
1655 public String printMapping(String pdbfile)
1657 return ssm.printMapping(pdbfile);
1661 public void resizeInnerPanel(String data)
1663 // Jalview doesn't honour resize panel requests