2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.1)
3 * Copyright (C) 2014 The Jalview Authors
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/>.
17 * The Jalview Authors are detailed in the 'AUTHORS' file.
19 package jalview.ext.jmol;
21 import jalview.api.AlignmentViewPanel;
22 import jalview.api.FeatureRenderer;
23 import jalview.api.SequenceRenderer;
24 import jalview.api.SequenceStructureBinding;
25 import jalview.api.StructureSelectionManagerProvider;
26 import jalview.datamodel.AlignmentI;
27 import jalview.datamodel.ColumnSelection;
28 import jalview.datamodel.PDBEntry;
29 import jalview.datamodel.SequenceI;
30 import jalview.io.AppletFormatAdapter;
31 import jalview.schemes.ColourSchemeI;
32 import jalview.schemes.ResidueProperties;
33 import jalview.structure.StructureListener;
34 import jalview.structure.StructureMapping;
35 import jalview.structure.StructureSelectionManager;
37 import java.awt.Color;
38 import java.awt.Container;
39 import java.awt.event.ComponentEvent;
40 import java.awt.event.ComponentListener;
43 import java.security.AccessControlException;
44 import java.util.Enumeration;
45 import java.util.Hashtable;
47 import java.util.Vector;
49 import org.jmol.adapter.smarter.SmarterJmolAdapter;
50 import org.jmol.api.JmolAppConsoleInterface;
51 import org.jmol.api.JmolSelectionListener;
52 import org.jmol.api.JmolStatusListener;
53 import org.jmol.api.JmolViewer;
54 import org.jmol.constant.EnumCallback;
55 import org.jmol.popup.JmolPopup;
57 public abstract class JalviewJmolBinding implements StructureListener,
58 JmolStatusListener, SequenceStructureBinding,
59 JmolSelectionListener, ComponentListener,
60 StructureSelectionManagerProvider
64 * set if Jmol state is being restored from some source - instructs binding
65 * not to apply default display style when structure set is updated for first
68 private boolean loadingFromArchive = false;
71 * second flag to indicate if the jmol viewer should ignore sequence colouring
72 * events from the structure manager because the GUI is still setting up
74 private boolean loadingFinished = true;
77 * state flag used to check if the Jmol viewer's paint method can be called
79 private boolean finishedInit = false;
81 public boolean isFinishedInit()
86 public void setFinishedInit(boolean finishedInit)
88 this.finishedInit = finishedInit;
91 boolean allChainsSelected = false;
94 * when true, try to search the associated datamodel for sequences that are
95 * associated with any unknown structures in the Jmol view.
97 private boolean associateNewStructs = false;
99 Vector atomsPicked = new Vector();
101 public Vector chainNames;
106 * array of target chains for seuqences - tied to pdbentry and sequence[]
108 protected String[][] chains;
110 boolean colourBySequence = true;
112 StringBuffer eval = new StringBuffer();
114 public String fileLoadingError;
117 * the default or current model displayed if the model cannot be identified
118 * from the selection message
122 protected JmolPopup jmolpopup;
128 boolean loadedInline;
131 * current set of model filenames loaded in the Jmol instance
133 String[] modelFileNames = null;
135 public PDBEntry[] pdbentry;
138 * datasource protocol for access to PDBEntrylatest
140 String protocol = null;
142 StringBuffer resetLastRes = new StringBuffer();
145 * sequences mapped to each pdbentry
147 public SequenceI[][] sequence;
149 public StructureSelectionManager ssm;
151 public JmolViewer viewer;
153 public JalviewJmolBinding(StructureSelectionManager ssm,
154 PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
158 this.sequence = sequenceIs;
159 this.chains = chains;
160 this.pdbentry = pdbentry;
161 this.protocol = protocol;
164 this.chains = new String[pdbentry.length][];
167 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
168 * "jalviewJmol", ap.av.applet .getDocumentBase(),
169 * ap.av.applet.getCodeBase(), "", this);
171 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
175 public JalviewJmolBinding(StructureSelectionManager ssm,
180 viewer.setJmolStatusListener(this);
181 viewer.addSelectionListener(this);
185 * construct a title string for the viewer window based on the data jalview
190 public String getViewerTitle()
192 if (sequence == null || pdbentry == null || sequence.length < 1
193 || pdbentry.length < 1 || sequence[0].length < 1)
195 return ("Jalview Jmol Window");
197 // TODO: give a more informative title when multiple structures are
199 StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
200 + pdbentry[0].getId());
202 if (pdbentry[0].getProperty() != null)
204 if (pdbentry[0].getProperty().get("method") != null)
206 title.append(" Method: ");
207 title.append(pdbentry[0].getProperty().get("method"));
209 if (pdbentry[0].getProperty().get("chains") != null)
211 title.append(" Chain:");
212 title.append(pdbentry[0].getProperty().get("chains"));
215 return title.toString();
219 * prepare the view for a given set of models/chains. chainList contains
220 * strings of the form 'pdbfilename:Chaincode'
223 * list of chains to make visible
225 public void centerViewer(Vector chainList)
227 StringBuffer cmd = new StringBuffer();
230 for (int i = 0, iSize = chainList.size(); i < iSize; i++)
233 lbl = (String) chainList.elementAt(i);
237 mlength = lbl.indexOf(":", p);
238 } while (p < mlength && mlength < (lbl.length() - 2));
239 // TODO: lookup each pdb id and recover proper model number for it.
240 cmd.append(":" + lbl.substring(mlength + 1) + " /"
241 + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");
243 if (cmd.length() > 0)
244 cmd.setLength(cmd.length() - 4);
245 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
248 public void closeViewer()
250 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
251 // remove listeners for all structures in viewer
252 ssm.removeStructureViewerListener(this, this.getPdbFile());
253 // and shut down jmol
254 viewer.evalStringQuiet("zap");
255 viewer.setJmolStatusListener(null);
258 releaseUIResources();
262 * called by JalviewJmolbinding after closeViewer is called - release any
263 * resources and references so they can be garbage collected.
265 protected abstract void releaseUIResources();
267 public void colourByChain()
269 colourBySequence = false;
270 // TODO: colour by chain should colour each chain distinctly across all
272 // TODO: http://issues.jalview.org/browse/JAL-628
273 evalStateCommand("select *;color chain");
276 public void colourByCharge()
278 colourBySequence = false;
279 evalStateCommand("select *;color white;select ASP,GLU;color red;"
280 + "select LYS,ARG;color blue;select CYS;color yellow");
284 * superpose the structures associated with sequences in the alignment
285 * according to their corresponding positions.
287 public void superposeStructures(AlignmentI alignment)
289 superposeStructures(alignment, -1, null);
293 * superpose the structures associated with sequences in the alignment
294 * according to their corresponding positions. ded)
296 * @param refStructure
297 * - select which pdb file to use as reference (default is -1 - the
298 * first structure in the alignment)
300 public void superposeStructures(AlignmentI alignment, int refStructure)
302 superposeStructures(alignment, refStructure, null);
306 * superpose the structures associated with sequences in the alignment
307 * according to their corresponding positions. ded)
309 * @param refStructure
310 * - select which pdb file to use as reference (default is -1 - the
311 * first structure in the alignment)
315 public void superposeStructures(AlignmentI alignment, int refStructure,
316 ColumnSelection hiddenCols)
318 superposeStructures(new AlignmentI[]
319 { alignment }, new int[]
320 { refStructure }, new ColumnSelection[]
324 public void superposeStructures(AlignmentI[] _alignment,
325 int[] _refStructure, ColumnSelection[] _hiddenCols)
327 assert (_alignment.length == _refStructure.length && _alignment.length != _hiddenCols.length);
329 String[] files = getPdbFile();
330 // check to see if we are still waiting for Jmol files
331 long starttime=System.currentTimeMillis();
332 boolean waiting=true;
335 for (String file:files)
338 // HACK - in Jalview 2.8 this call may not be threadsafe so we catch
339 // every possible exception
340 StructureMapping[] sm = ssm.getMapping(file);
341 if (sm == null || sm.length == 0)
345 } catch (Exception x)
353 // we wait around for a reasonable time before we give up
354 } while (waiting && System.currentTimeMillis()<(10000+1000*files.length+starttime));
357 System.err.println("RUNTIME PROBLEM: Jmol seems to be taking a long time to process all the structures.");
360 StringBuffer selectioncom = new StringBuffer();
361 // In principle - nSeconds specifies the speed of animation for each
362 // superposition - but is seems to behave weirdly, so we don't specify it.
363 String nSeconds = " ";
364 if (files.length > 10)
366 nSeconds = " 0.00001 ";
370 nSeconds = " " + (2.0 / files.length) + " ";
371 // if (nSeconds).substring(0,5)+" ";
373 // see JAL-1345 - should really automatically turn off the animation for
374 // large numbers of structures, but Jmol doesn't seem to allow that.
376 // union of all aligned positions are collected together.
377 for (int a = 0; a < _alignment.length; a++)
379 int refStructure = _refStructure[a];
380 AlignmentI alignment = _alignment[a];
381 ColumnSelection hiddenCols = _hiddenCols[a];
383 && selectioncom.length() > 0
384 && !selectioncom.substring(selectioncom.length() - 1).equals(
387 selectioncom.append("|");
389 // process this alignment
390 if (refStructure >= files.length)
392 System.err.println("Invalid reference structure value "
396 if (refStructure < -1)
400 StringBuffer command = new StringBuffer();
402 boolean matched[] = new boolean[alignment.getWidth()];
403 for (int m = 0; m < matched.length; m++)
406 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
409 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
410 String isel[] = new String[files.length];
411 // reference structure - all others are superposed in it
412 String[] targetC = new String[files.length];
413 String[] chainNames = new String[files.length];
414 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
416 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
417 // RACE CONDITION - getMapping only returns Jmol loaded filenames once
418 // Jmol callback has completed.
419 if (mapping == null || mapping.length < 1)
421 throw new Error("Implementation error - Jmol seems to be still working on getting its data - report at http://issues.jalview.org/browse/JAL-1016");
424 for (int s = 0; s < sequence[pdbfnum].length; s++)
426 for (int sp, m = 0; m < mapping.length; m++)
428 if (mapping[m].getSequence() == sequence[pdbfnum][s]
429 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
431 if (refStructure == -1)
433 refStructure = pdbfnum;
435 SequenceI asp = alignment.getSequenceAt(sp);
436 for (int r = 0; r < matched.length; r++)
442 matched[r] = false; // assume this is not a good site
443 if (r >= asp.getLength())
448 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
450 // no mapping to gaps in sequence
453 int t = asp.findPosition(r); // sequence position
454 int apos = mapping[m].getAtomNum(t);
455 int pos = mapping[m].getPDBResNum(t);
457 if (pos < 1 || pos == lastPos)
459 // can't align unmapped sequence
462 matched[r] = true; // this is a good ite
464 // just record this residue position
465 commonrpositions[pdbfnum][r] = pos;
467 // create model selection suffix
468 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
469 if (mapping[m].getChain() == null
470 || mapping[m].getChain().trim().length() == 0)
472 targetC[pdbfnum] = "";
476 targetC[pdbfnum] = ":" + mapping[m].getChain();
478 chainNames[pdbfnum] = mapping[m].getPdbId()
480 // move on to next pdb file
481 s = sequence[pdbfnum].length;
488 // TODO: consider bailing if nmatched less than 4 because superposition
491 // TODO: refactor superposable position search (above) from jmol selection
492 // construction (below)
494 String[] selcom = new String[files.length];
496 // generate select statements to select regions to superimpose structures
498 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
500 String chainCd = targetC[pdbfnum];
503 StringBuffer molsel = new StringBuffer();
505 for (int r = 0; r < matched.length; r++)
513 if (lpos != commonrpositions[pdbfnum][r] - 1)
519 molsel.append(chainCd);
520 // molsel.append("} {");
526 // continuous run - and lpos >-1
529 // at the beginning, so add dash
535 lpos = commonrpositions[pdbfnum][r];
536 // molsel.append(lpos);
539 // add final selection phrase
543 molsel.append(chainCd);
546 if (molsel.length() > 1)
548 selcom[pdbfnum] = molsel.toString();
549 selectioncom.append("((");
550 selectioncom.append(selcom[pdbfnum].substring(1,
551 selcom[pdbfnum].length() - 1));
552 selectioncom.append(" )& ");
553 selectioncom.append(pdbfnum + 1);
554 selectioncom.append(".1)");
555 if (pdbfnum < files.length - 1)
557 selectioncom.append("|");
560 selcom[pdbfnum] = null;
564 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
566 if (pdbfnum == refStructure || selcom[pdbfnum]==null || selcom[refStructure]==null)
570 command.append("echo ");
571 command.append("\"Superposing (");
572 command.append(chainNames[pdbfnum]);
573 command.append(") against reference (");
574 command.append(chainNames[refStructure]);
575 command.append(")\";\ncompare "+nSeconds);
577 command.append(1 + pdbfnum);
578 command.append(".1} {");
579 command.append(1 + refStructure);
580 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
582 // form the matched pair strings
584 for (int s = 0; s < 2; s++)
586 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
588 command.append(" ROTATE TRANSLATE;\n");
590 if (selectioncom.length() > 0)
592 System.out.println("Select regions:\n" + selectioncom.toString());
593 evalStateCommand("select *; cartoons off; backbone; select ("
594 + selectioncom.toString() + "); cartoons; ");
595 // selcom.append("; ribbons; ");
597 .println("Superimpose command(s):\n" + command.toString());
599 evalStateCommand(command.toString());
602 if (selectioncom.length() > 0)
603 {// finally, mark all regions that were superposed.
604 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
606 selectioncom.setLength(selectioncom.length() - 1);
608 System.out.println("Select regions:\n" + selectioncom.toString());
609 evalStateCommand("select *; cartoons off; backbone; select ("
610 + selectioncom.toString() + "); cartoons; ");
611 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
615 public void evalStateCommand(String command)
618 if (lastCommand == null || !lastCommand.equals(command))
620 viewer.evalStringQuiet(command + "\n");
623 lastCommand = command;
627 * colour any structures associated with sequences in the given alignment
628 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
629 * if colourBySequence is enabled.
631 public void colourBySequence(boolean showFeatures,
632 jalview.api.AlignmentViewPanel alignmentv)
634 if (!colourBySequence || !loadingFinished)
640 String[] files = getPdbFile();
642 SequenceRenderer sr = getSequenceRenderer(alignmentv);
644 FeatureRenderer fr = null;
647 fr = getFeatureRenderer(alignmentv);
649 AlignmentI alignment = alignmentv.getAlignment();
651 for (jalview.structure.StructureMappingcommandSet cpdbbyseq : JmolCommands
652 .getColourBySequenceCommand(ssm, files, sequence, sr, fr,
654 for (String cbyseq : cpdbbyseq.commands)
656 evalStateCommand(cbyseq);
660 public boolean isColourBySequence()
662 return colourBySequence;
665 public void setColourBySequence(boolean colourBySequence)
667 this.colourBySequence = colourBySequence;
670 public void createImage(String file, String type, int quality)
672 System.out.println("JMOL CREATE IMAGE");
675 public String createImage(String fileName, String type,
676 Object textOrBytes, int quality)
678 System.out.println("JMOL CREATE IMAGE");
682 public String eval(String strEval)
684 // System.out.println(strEval);
685 // "# 'eval' is implemented only for the applet.";
689 // End StructureListener
690 // //////////////////////////
692 public float[][] functionXY(String functionName, int x, int y)
697 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
699 // TODO Auto-generated method stub
703 public Color getColour(int atomIndex, int pdbResNum, String chain,
706 if (getModelNum(pdbfile) < 0)
708 // TODO: verify atomIndex is selecting correct model.
709 return new Color(viewer.getAtomArgb(atomIndex));
713 * returns the current featureRenderer that should be used to colour the
720 public abstract FeatureRenderer getFeatureRenderer(
721 AlignmentViewPanel alignment);
724 * instruct the Jalview binding to update the pdbentries vector if necessary
725 * prior to matching the jmol view's contents to the list of structure files
726 * Jalview knows about.
728 public abstract void refreshPdbEntries();
730 private int getModelNum(String modelFileName)
732 String[] mfn = getPdbFile();
737 for (int i = 0; i < mfn.length; i++)
739 if (mfn[i].equalsIgnoreCase(modelFileName))
746 * map between index of model filename returned from getPdbFile and the first
747 * index of models from this file in the viewer. Note - this is not trimmed -
748 * use getPdbFile to get number of unique models.
750 private int _modelFileNameMap[];
752 // ////////////////////////////////
753 // /StructureListener
754 public synchronized String[] getPdbFile()
758 return new String[0];
760 if (modelFileNames == null)
763 String mset[] = new String[viewer.getModelCount()];
764 _modelFileNameMap = new int[mset.length];
766 String m = viewer.getModelFileName(0);
771 mset[0] = new File(m).getAbsolutePath();
772 } catch (AccessControlException x)
774 // usually not allowed to do this in applet, so keep raw handle
776 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
779 for (int i = 1; i < mset.length; i++)
781 m = viewer.getModelFileName(i);
786 mset[j] = new File(m).getAbsolutePath();
787 } catch (AccessControlException x)
789 // usually not allowed to do this in applet, so keep raw handle
791 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
794 _modelFileNameMap[j] = i; // record the model index for the filename
795 // skip any additional models in the same file (NMR structures)
796 if ((mset[j] == null ? mset[j] != mset[j - 1]
797 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
802 modelFileNames = new String[j];
803 System.arraycopy(mset, 0, modelFileNames, 0, j);
805 return modelFileNames;
809 * map from string to applet
811 public Map getRegistryInfo()
813 // TODO Auto-generated method stub
818 * returns the current sequenceRenderer that should be used to colour the
825 public abstract SequenceRenderer getSequenceRenderer(
826 AlignmentViewPanel alignment);
828 // ///////////////////////////////
829 // JmolStatusListener
831 public void handlePopupMenu(int x, int y)
833 jmolpopup.show(x, y);
837 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
840 if (modelFileNames == null)
845 // look up file model number for this pdbfile
848 // may need to adjust for URLencoding here - we don't worry about that yet.
849 while (mdlNum < modelFileNames.length
850 && !pdbfile.equals(modelFileNames[mdlNum]))
852 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
855 if (mdlNum == modelFileNames.length)
861 // if (!pdbfile.equals(pdbentry.getFile()))
863 if (resetLastRes.length() > 0)
865 viewer.evalStringQuiet(resetLastRes.toString());
869 eval.append("select " + pdbResNum); // +modelNum
871 resetLastRes.setLength(0);
872 resetLastRes.append("select " + pdbResNum); // +modelNum
875 resetLastRes.append(":");
876 if (!chain.equals(" "))
879 resetLastRes.append(chain);
882 eval.append(" /" + (mdlNum + 1));
883 resetLastRes.append("/" + (mdlNum + 1));
885 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
887 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
888 + " and not hetero; spacefill 0;");
890 eval.append("spacefill 200;select none");
892 viewer.evalStringQuiet(eval.toString());
897 boolean debug = true;
899 private void jmolHistory(boolean enable)
901 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
904 public void loadInline(String string)
908 // viewer.loadInline(strModel, isAppend);
910 // construct fake fullPathName and fileName so we can identify the file
912 // Then, construct pass a reader for the string to Jmol.
913 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
914 // fileName, null, reader, false, null, null, 0);
915 viewer.openStringInline(string);
918 public void mouseOverStructure(int atomIndex, String strInfo)
921 int alocsep = strInfo.indexOf("^");
922 int mdlSep = strInfo.indexOf("/");
923 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
925 if (chainSeparator == -1)
927 chainSeparator = strInfo.indexOf(".");
928 if (mdlSep > -1 && mdlSep < chainSeparator)
930 chainSeparator1 = chainSeparator;
931 chainSeparator = mdlSep;
934 // handle insertion codes
937 pdbResNum = Integer.parseInt(strInfo.substring(
938 strInfo.indexOf("]") + 1, alocsep));
943 pdbResNum = Integer.parseInt(strInfo.substring(
944 strInfo.indexOf("]") + 1, chainSeparator));
948 if (strInfo.indexOf(":") > -1)
949 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
950 strInfo.indexOf("."));
956 String pdbfilename = modelFileNames[frameNo]; // default is first or current
960 if (chainSeparator1 == -1)
962 chainSeparator1 = strInfo.indexOf(".", mdlSep);
964 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
965 chainSeparator1) : strInfo.substring(mdlSep + 1);
968 // recover PDB filename for the model hovered over.
969 int _mp = _modelFileNameMap.length - 1, mnumber = new Integer(mdlId)
971 while (mnumber < _modelFileNameMap[_mp])
975 pdbfilename = modelFileNames[_mp];
976 if (pdbfilename == null)
978 pdbfilename = new File(viewer.getModelFileName(mnumber))
982 } catch (Exception e)
987 if (lastMessage == null || !lastMessage.equals(strInfo))
988 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
990 lastMessage = strInfo;
993 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
997 System.err.println("Ignoring additional hover info: " + data
998 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
1000 mouseOverStructure(atomIndex, strInfo);
1004 * { if (history != null && strStatus != null &&
1005 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
1009 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
1012 * this implements the toggle label behaviour copied from the original
1013 * structure viewer, MCView
1015 if (strData != null)
1017 System.err.println("Ignoring additional pick data string " + strData);
1019 int chainSeparator = strInfo.indexOf(":");
1021 if (chainSeparator == -1)
1022 chainSeparator = strInfo.indexOf(".");
1024 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
1026 String mdlString = "";
1027 if ((p = strInfo.indexOf(":")) > -1)
1028 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
1030 if ((p = strInfo.indexOf("/")) > -1)
1032 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
1034 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
1038 if (!atomsPicked.contains(picked))
1040 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
1041 atomsPicked.addElement(picked);
1045 viewer.evalString("select " + picked + ";label off");
1046 atomsPicked.removeElement(picked);
1049 // TODO: in application this happens
1051 // if (scriptWindow != null)
1053 // scriptWindow.sendConsoleMessage(strInfo);
1054 // scriptWindow.sendConsoleMessage("\n");
1060 public void notifyCallback(EnumCallback type, Object[] data)
1067 notifyFileLoaded((String) data[1], (String) data[2],
1068 (String) data[3], (String) data[4],
1069 ((Integer) data[5]).intValue());
1073 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
1075 // also highlight in alignment
1077 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1081 notifyScriptTermination((String) data[2],
1082 ((Integer) data[3]).intValue());
1085 sendConsoleEcho((String) data[1]);
1088 sendConsoleMessage((data == null) ? ((String) null)
1089 : (String) data[1]);
1092 // System.err.println("Ignoring error callback.");
1102 System.err.println("Unhandled callback " + type + " "
1103 + data[1].toString());
1106 } catch (Exception e)
1108 System.err.println("Squashed Jmol callback handler error:");
1109 e.printStackTrace();
1114 public boolean notifyEnabled(EnumCallback callbackPick)
1116 switch (callbackPick)
1136 // incremented every time a load notification is successfully handled -
1137 // lightweight mechanism for other threads to detect when they can start
1138 // referrring to new structures.
1139 private long loadNotifiesHandled = 0;
1141 public long getLoadNotifiesHandled()
1143 return loadNotifiesHandled;
1146 public void notifyFileLoaded(String fullPathName, String fileName2,
1147 String modelName, String errorMsg, int modelParts)
1149 if (errorMsg != null)
1151 fileLoadingError = errorMsg;
1155 // TODO: deal sensibly with models loaded inLine:
1156 // modelName will be null, as will fullPathName.
1158 // the rest of this routine ignores the arguments, and simply interrogates
1159 // the Jmol view to find out what structures it contains, and adds them to
1160 // the structure selection manager.
1161 fileLoadingError = null;
1162 String[] oldmodels = modelFileNames;
1163 modelFileNames = null;
1164 chainNames = new Vector();
1165 chainFile = new Hashtable();
1166 boolean notifyLoaded = false;
1167 String[] modelfilenames = getPdbFile();
1168 // first check if we've lost any structures
1169 if (oldmodels != null && oldmodels.length > 0)
1172 for (int i = 0; i < oldmodels.length; i++)
1174 for (int n = 0; n < modelfilenames.length; n++)
1176 if (modelfilenames[n] == oldmodels[i])
1178 oldmodels[i] = null;
1182 if (oldmodels[i] != null)
1189 String[] oldmfn = new String[oldm];
1191 for (int i = 0; i < oldmodels.length; i++)
1193 if (oldmodels[i] != null)
1195 oldmfn[oldm++] = oldmodels[i];
1198 // deregister the Jmol instance for these structures - we'll add
1199 // ourselves again at the end for the current structure set.
1200 ssm.removeStructureViewerListener(this, oldmfn);
1203 refreshPdbEntries();
1204 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1206 String fileName = modelfilenames[modelnum];
1207 boolean foundEntry = false;
1208 MCview.PDBfile pdb = null;
1209 String pdbfile = null, pdbfhash = null;
1210 // model was probably loaded inline - so check the pdb file hashcode
1213 // calculate essential attributes for the pdb data imported inline.
1214 // prolly need to resolve modelnumber properly - for now just use our
1216 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1218 pdbfhash = "" + pdbfile.hashCode();
1220 if (pdbentry != null)
1222 // search pdbentries and sequences to find correct pdbentry for this
1224 for (int pe = 0; pe < pdbentry.length; pe++)
1226 boolean matches = false;
1227 if (fileName == null)
1230 // see JAL-623 - need method of matching pasted data up
1232 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
1233 AppletFormatAdapter.PASTE);
1234 pdbentry[modelnum].setFile("INLINE" + pdb.id);
1242 if (matches = (fl = new File(pdbentry[pe].getFile()))
1243 .equals(new File(fileName)))
1246 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1249 // to be tested. See mantis bug
1250 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1251 String protocol = AppletFormatAdapter.URL;
1256 protocol = AppletFormatAdapter.FILE;
1258 } catch (Exception e)
1263 // Explicitly map to the filename used by Jmol ;
1264 pdb = ssm.setMapping(sequence[pe], chains[pe], fileName,
1266 // pdbentry[pe].getFile(), protocol);
1272 // add an entry for every chain in the model
1273 for (int i = 0; i < pdb.chains.size(); i++)
1275 String chid = new String(pdb.id + ":"
1276 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
1277 chainFile.put(chid, fileName);
1278 chainNames.addElement(chid);
1280 notifyLoaded = true;
1284 if (!foundEntry && associateNewStructs)
1286 // this is a foreign pdb file that jalview doesn't know about - add
1287 // it to the dataset and try to find a home - either on a matching
1288 // sequence or as a new sequence.
1289 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1291 // parse pdb file into a chain, etc.
1292 // locate best match for pdb in associated views and add mapping to
1294 // if properly registered then
1295 notifyLoaded = true;
1300 // so finally, update the jmol bits and pieces
1301 if (jmolpopup != null)
1303 // potential for deadlock here:
1304 // jmolpopup.updateComputedMenus();
1306 if (!isLoadingFromArchive())
1308 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1310 // register ourselves as a listener and notify the gui that it needs to
1312 ssm.addStructureViewerListener(this);
1315 FeatureRenderer fr = getFeatureRenderer(null);
1321 loadNotifiesHandled++;
1323 setLoadingFromArchive(false);
1326 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1328 notifyAtomPicked(iatom, strMeasure, null);
1331 public abstract void notifyScriptTermination(String strStatus,
1335 * display a message echoed from the jmol viewer
1339 public abstract void sendConsoleEcho(String strEcho); /*
1340 * { showConsole(true);
1342 * history.append("\n" +
1346 // /End JmolStatusListener
1347 // /////////////////////////////
1351 * status message - usually the response received after a script
1354 public abstract void sendConsoleMessage(String strStatus);
1356 public void setCallbackFunction(String callbackType,
1357 String callbackFunction)
1359 System.err.println("Ignoring set-callback request to associate "
1360 + callbackType + " with function " + callbackFunction);
1364 public void setJalviewColourScheme(ColourSchemeI cs)
1366 colourBySequence = false;
1375 // TODO: Switch between nucleotide or aa selection expressions
1376 Enumeration en = ResidueProperties.aa3Hash.keys();
1377 StringBuffer command = new StringBuffer("select *;color white;");
1378 while (en.hasMoreElements())
1380 res = en.nextElement().toString();
1381 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
1385 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
1387 command.append("select " + res + ";color[" + col.getRed() + ","
1388 + col.getGreen() + "," + col.getBlue() + "];");
1391 evalStateCommand(command.toString());
1395 public void showHelp()
1397 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1401 * open the URL somehow
1405 public abstract void showUrl(String url, String target);
1408 * called when the binding thinks the UI needs to be refreshed after a Jmol
1409 * state change. this could be because structures were loaded, or because an
1410 * error has occured.
1412 public abstract void refreshGUI();
1415 * called to show or hide the associated console window container.
1419 public abstract void showConsole(boolean show);
1422 * @param renderPanel
1424 * - when true will initialise jmol's file IO system (should be false
1425 * in applet context)
1427 * @param documentBase
1429 * @param commandOptions
1431 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1432 String htmlName, URL documentBase, URL codeBase,
1433 String commandOptions)
1435 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1436 codeBase, commandOptions, null, null);
1441 * @param renderPanel
1443 * - when true will initialise jmol's file IO system (should be false
1444 * in applet context)
1446 * @param documentBase
1448 * @param commandOptions
1449 * @param consolePanel
1450 * - panel to contain Jmol console
1451 * @param buttonsToShow
1452 * - buttons to show on the console, in ordr
1454 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1455 String htmlName, URL documentBase, URL codeBase,
1456 String commandOptions, final Container consolePanel,
1457 String buttonsToShow)
1459 if (commandOptions == null)
1461 commandOptions = "";
1463 viewer = JmolViewer.allocateViewer(renderPanel,
1464 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1465 + ((Object) this).toString(), documentBase, codeBase,
1466 commandOptions, this);
1468 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
1469 if (consolePanel != null)
1471 consolePanel.addComponentListener(this);
1477 protected abstract JmolAppConsoleInterface createJmolConsole(
1478 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
1480 protected org.jmol.api.JmolAppConsoleInterface console = null;
1482 public void componentResized(ComponentEvent e)
1487 public void componentMoved(ComponentEvent e)
1492 public void componentShown(ComponentEvent e)
1497 public void componentHidden(ComponentEvent e)
1502 public void setLoadingFromArchive(boolean loadingFromArchive)
1504 this.loadingFromArchive = loadingFromArchive;
1509 * @return true if Jmol is still restoring state or loading is still going on (see setFinsihedLoadingFromArchive)
1511 public boolean isLoadingFromArchive()
1513 return loadingFromArchive && !loadingFinished;
1517 * modify flag which controls if sequence colouring events are honoured by the binding.
1518 * Should be true for normal operation
1519 * @param finishedLoading
1521 public void setFinishedLoadingFromArchive(boolean finishedLoading)
1523 loadingFinished = finishedLoading;
1526 public void setBackgroundColour(java.awt.Color col)
1529 viewer.evalStringQuiet("background [" + col.getRed() + ","
1530 + col.getGreen() + "," + col.getBlue() + "];");
1535 * add structures and any known sequence associations
1537 * @returns the pdb entries added to the current set.
1539 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
1540 SequenceI[][] seq, String[][] chns)
1543 Vector v = new Vector();
1544 Vector rtn = new Vector();
1545 for (int i = 0; i < pdbentry.length; i++)
1547 v.addElement(pdbentry[i]);
1549 for (int i = 0; i < pdbe.length; i++)
1551 int r = v.indexOf(pdbe[i]);
1552 if (r == -1 || r >= pdbentry.length)
1554 rtn.addElement(new int[]
1556 v.addElement(pdbe[i]);
1560 // just make sure the sequence/chain entries are all up to date
1561 addSequenceAndChain(r, seq[i], chns[i]);
1564 pdbe = new PDBEntry[v.size()];
1569 // expand the tied seuqence[] and string[] arrays
1570 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
1571 String[][] sch = new String[pdbentry.length][];
1572 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
1573 System.arraycopy(chains, 0, sch, 0, this.chains.length);
1576 pdbe = new PDBEntry[rtn.size()];
1577 for (int r = 0; r < pdbe.length; r++)
1579 int[] stri = ((int[]) rtn.elementAt(r));
1580 // record the pdb file as a new addition
1581 pdbe[r] = pdbentry[stri[0]];
1582 // and add the new sequence/chain entries
1583 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
1593 public void addSequence(int pe, SequenceI[] seq)
1595 // add sequences to the pe'th pdbentry's seuqence set.
1596 addSequenceAndChain(pe, seq, null);
1599 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
1601 if (pe < 0 || pe >= pdbentry.length)
1604 "Implementation error - no corresponding pdbentry (for index "
1605 + pe + ") to add sequences mappings to");
1607 final String nullChain = "TheNullChain";
1608 Vector s = new Vector();
1609 Vector c = new Vector();
1612 chains = new String[pdbentry.length][];
1614 if (sequence[pe] != null)
1616 for (int i = 0; i < sequence[pe].length; i++)
1618 s.addElement(sequence[pe][i]);
1619 if (chains[pe] != null)
1621 if (i < chains[pe].length)
1623 c.addElement(chains[pe][i]);
1627 c.addElement(nullChain);
1632 if (tchain != null && tchain.length > 0)
1634 c.addElement(nullChain);
1639 for (int i = 0; i < seq.length; i++)
1641 if (!s.contains(seq[i]))
1643 s.addElement(seq[i]);
1644 if (tchain != null && i < tchain.length)
1646 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
1650 SequenceI[] tmp = new SequenceI[s.size()];
1655 String[] tch = new String[c.size()];
1657 for (int i = 0; i < tch.length; i++)
1659 if (tch[i] == nullChain)
1675 * @return text report of alignment between pdbfile and any associated
1676 * alignment sequences
1678 public String printMapping(String pdbfile)
1680 return ssm.printMapping(pdbfile);
1684 public void resizeInnerPanel(String data)
1686 // Jalview doesn't honour resize panel requests