2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
3 * Copyright (C) 2010 J Procter, AM Waterhouse, 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;
23 import java.applet.Applet;
25 import java.awt.event.*;
27 import javax.swing.JPanel;
29 import jalview.api.AlignmentViewPanel;
30 import jalview.api.FeatureRenderer;
31 import jalview.api.SequenceRenderer;
32 import jalview.api.SequenceStructureBinding;
33 import jalview.datamodel.*;
34 import jalview.structure.*;
37 import org.jmol.api.*;
38 import org.jmol.adapter.smarter.SmarterJmolAdapter;
40 import org.jmol.popup.*;
41 import org.jmol.viewer.JmolConstants;
42 import org.jmol.viewer.Viewer;
44 import jalview.schemes.*;
46 public abstract class JalviewJmolBinding implements StructureListener,
47 JmolStatusListener, SequenceStructureBinding,
48 JmolSelectionListener, ComponentListener
52 * set if Jmol state is being restored from some source - instructs binding
53 * not to apply default display style when structure set is updated for first
56 private boolean loadingFromArchive = false;
59 * state flag used to check if the Jmol viewer's paint method can be called
61 private boolean finishedInit = false;
63 public boolean isFinishedInit()
68 public void setFinishedInit(boolean finishedInit)
70 this.finishedInit = finishedInit;
73 boolean allChainsSelected = false;
76 * when true, try to search the associated datamodel for sequences that are
77 * associated with any unknown structures in the Jmol view.
79 private boolean associateNewStructs = false;
81 Vector atomsPicked = new Vector();
83 public Vector chainNames;
88 * array of target chains for seuqences - tied to pdbentry and sequence[]
90 protected String[][] chains;
92 boolean colourBySequence = true;
94 StringBuffer eval = new StringBuffer();
96 public String fileLoadingError;
99 * the default or current model displayed if the model cannot be identified
100 * from the selection message
104 protected JmolPopup jmolpopup;
110 boolean loadedInline;
113 * current set of model filenames loaded in the Jmol instance
115 String[] modelFileNames = null;
117 public PDBEntry[] pdbentry;
120 * datasource protocol for access to PDBEntrylatest
122 String protocol = null;
124 StringBuffer resetLastRes = new StringBuffer();
127 * sequences mapped to each pdbentry
129 public SequenceI[][] sequence;
131 StructureSelectionManager ssm;
133 public JmolViewer viewer;
135 public JalviewJmolBinding(PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
136 String[][] chains, String protocol)
138 this.sequence = sequenceIs;
139 this.chains = chains;
140 this.pdbentry = pdbentry;
141 this.protocol = protocol;
144 this.chains = new String[pdbentry.length][];
147 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
148 * "jalviewJmol", ap.av.applet .getDocumentBase(),
149 * ap.av.applet.getCodeBase(), "", this);
151 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
155 public JalviewJmolBinding(JmolViewer viewer2)
158 viewer.setJmolStatusListener(this);
159 viewer.addSelectionListener(this);
163 * construct a title string for the viewer window based on the data jalview
168 public String getViewerTitle()
170 if (sequence == null || pdbentry == null || sequence.length < 1
171 || pdbentry.length < 1 || sequence[0].length < 1)
173 return ("Jalview Jmol Window");
175 // TODO: give a more informative title when multiple structures are
177 StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
178 + pdbentry[0].getId());
180 if (pdbentry[0].getProperty() != null)
182 if (pdbentry[0].getProperty().get("method") != null)
184 title.append(" Method: ");
185 title.append(pdbentry[0].getProperty().get("method"));
187 if (pdbentry[0].getProperty().get("chains") != null)
189 title.append(" Chain:");
190 title.append(pdbentry[0].getProperty().get("chains"));
193 return title.toString();
197 * prepare the view for a given set of models/chains. chainList contains
198 * strings of the form 'pdbfilename:Chaincode'
201 * list of chains to make visible
203 public void centerViewer(Vector chainList)
205 StringBuffer cmd = new StringBuffer();
208 for (int i = 0, iSize = chainList.size(); i < iSize; i++)
211 lbl = (String) chainList.elementAt(i);
215 mlength = lbl.indexOf(":", p);
216 } while (p < mlength && mlength < (lbl.length() - 2));
217 // TODO: lookup each pdb id and recover proper model number for it.
218 cmd.append(":" + lbl.substring(mlength + 1) + " /"
219 + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");
221 if (cmd.length() > 0)
222 cmd.setLength(cmd.length() - 4);
223 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
226 public void closeViewer()
228 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
229 // remove listeners for all structures in viewer
230 StructureSelectionManager.getStructureSelectionManager()
231 .removeStructureViewerListener(this, this.getPdbFile());
232 // and shut down jmol
233 viewer.evalStringQuiet("zap");
234 viewer.setJmolStatusListener(null);
237 releaseUIResources();
241 * called by JalviewJmolbinding after closeViewer is called - release any
242 * resources and references so they can be garbage collected.
244 protected abstract void releaseUIResources();
246 public void colourByChain()
248 colourBySequence = false;
249 // TODO: colour by chain should colour each chain distinctly across all
251 // TODO: http://issues.jalview.org/browse/JAL-628
252 evalStateCommand("select *;color chain");
255 public void colourByCharge()
257 colourBySequence = false;
258 evalStateCommand("select *;color white;select ASP,GLU;color red;"
259 + "select LYS,ARG;color blue;select CYS;color yellow");
263 * superpose the structures associated with sequences in the alignment
264 * according to their corresponding positions.
266 public void superposeStructures(AlignmentI alignment)
268 superposeStructures(alignment, -1, null);
272 * superpose the structures associated with sequences in the alignment
273 * according to their corresponding positions. ded)
275 * @param refStructure
276 * - select which pdb file to use as reference (default is -1 - the
277 * first structure in the alignment)
279 public void superposeStructures(AlignmentI alignment, int refStructure)
281 superposeStructures(alignment, refStructure, null);
285 * superpose the structures associated with sequences in the alignment
286 * according to their corresponding positions. ded)
288 * @param refStructure
289 * - select which pdb file to use as reference (default is -1 - the
290 * first structure in the alignment)
294 public void superposeStructures(AlignmentI alignment, int refStructure,
295 ColumnSelection hiddenCols)
297 superposeStructures(new AlignmentI[]
298 { alignment }, new int[]
299 { refStructure }, new ColumnSelection[]
303 public void superposeStructures(AlignmentI[] _alignment,
304 int[] _refStructure, ColumnSelection[] _hiddenCols)
306 String[] files = getPdbFile();
307 StringBuffer selectioncom = new StringBuffer();
308 assert (_alignment.length == _refStructure.length && _alignment.length != _hiddenCols.length);
309 // union of all aligned positions are collected together.
310 for (int a = 0; a < _alignment.length; a++)
312 int refStructure = _refStructure[a];
313 AlignmentI alignment = _alignment[a];
314 ColumnSelection hiddenCols = _hiddenCols[a];
316 && selectioncom.length() > 0
317 && !selectioncom.substring(selectioncom.length() - 1).equals(
320 selectioncom.append("|");
322 // process this alignment
323 if (refStructure >= files.length)
325 System.err.println("Invalid reference structure value "
329 if (refStructure < -1)
333 StringBuffer command = new StringBuffer();
335 boolean matched[] = new boolean[alignment.getWidth()];
336 for (int m = 0; m < matched.length; m++)
339 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
342 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
343 String isel[] = new String[files.length];
344 // reference structure - all others are superposed in it
345 String[] targetC = new String[files.length];
346 String[] chainNames = new String[files.length];
347 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
349 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
351 if (mapping == null || mapping.length < 1)
355 for (int s = 0; s < sequence[pdbfnum].length; s++)
357 for (int sp, m = 0; m < mapping.length; m++)
359 if (mapping[m].getSequence() == sequence[pdbfnum][s]
360 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
362 if (refStructure == -1)
364 refStructure = pdbfnum;
366 SequenceI asp = alignment.getSequenceAt(sp);
367 for (int r = 0; r < matched.length; r++)
373 matched[r] = false; // assume this is not a good site
374 if (r >= asp.getLength())
379 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
381 // no mapping to gaps in sequence
384 int t = asp.findPosition(r); // sequence position
385 int apos = mapping[m].getAtomNum(t);
386 int pos = mapping[m].getPDBResNum(t);
388 if (pos < 1 || pos == lastPos)
390 // can't align unmapped sequence
393 matched[r] = true; // this is a good ite
395 // just record this residue position
396 commonrpositions[pdbfnum][r] = pos;
398 // create model selection suffix
399 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
400 if (mapping[m].getChain() == null
401 || mapping[m].getChain().trim().length() == 0)
403 targetC[pdbfnum] = "";
407 targetC[pdbfnum] = ":" + mapping[m].getChain();
409 chainNames[pdbfnum] = mapping[m].getPdbId()
411 // move on to next pdb file
412 s = sequence[pdbfnum].length;
418 String[] selcom = new String[files.length];
420 // generate select statements to select regions to superimpose structures
422 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
424 String chainCd = targetC[pdbfnum];
427 StringBuffer molsel = new StringBuffer();
429 for (int r = 0; r < matched.length; r++)
437 if (lpos != commonrpositions[pdbfnum][r] - 1)
443 molsel.append(chainCd);
444 // molsel.append("} {");
450 // continuous run - and lpos >-1
453 // at the beginning, so add dash
459 lpos = commonrpositions[pdbfnum][r];
460 // molsel.append(lpos);
463 // add final selection phrase
467 molsel.append(chainCd);
470 selcom[pdbfnum] = molsel.toString();
471 selectioncom.append("((");
472 selectioncom.append(selcom[pdbfnum].substring(1,
473 selcom[pdbfnum].length() - 1));
474 selectioncom.append(" )& ");
475 selectioncom.append(pdbfnum + 1);
476 selectioncom.append(".1)");
477 if (pdbfnum < files.length - 1)
479 selectioncom.append("|");
483 // TODO: consider bailing if nmatched less than 4 because superposition
486 // TODO: refactor superposable position search (above) from jmol selection
487 // construction (below)
488 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
490 if (pdbfnum == refStructure)
494 command.append("echo ");
495 command.append("\"Superposing (");
496 command.append(chainNames[pdbfnum]);
497 command.append(") against reference (");
498 command.append(chainNames[refStructure]);
499 command.append(")\";\ncompare ");
501 command.append(1 + pdbfnum);
502 command.append(".1} {");
503 command.append(1 + refStructure);
504 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
506 // form the matched pair strings
508 for (int s = 0; s < 2; s++)
510 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
512 command.append(" ROTATE TRANSLATE;\n");
514 System.out.println("Select regions:\n" + selectioncom.toString());
515 evalStateCommand("select *; cartoons off; backbone; select ("
516 + selectioncom.toString() + "); cartoons; ");
517 // selcom.append("; ribbons; ");
518 System.out.println("Superimpose command(s):\n" + command.toString());
520 evalStateCommand(command.toString());
522 if (selectioncom.length() > 0)
523 {// finally, mark all regions that were superposed.
524 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
526 selectioncom.setLength(selectioncom.length() - 1);
528 System.out.println("Select regions:\n" + selectioncom.toString());
529 evalStateCommand("select *; cartoons off; backbone; select ("
530 + selectioncom.toString() + "); cartoons; ");
531 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
535 public void evalStateCommand(String command)
538 if (lastCommand == null || !lastCommand.equals(command))
540 viewer.evalStringQuiet(command + "\n");
543 lastCommand = command;
547 * colour any structures associated with sequences in the given alignment
548 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
549 * if colourBySequence is enabled.
551 public void colourBySequence(boolean showFeatures,
552 jalview.api.AlignmentViewPanel alignmentv)
554 if (!colourBySequence)
560 String[] files = getPdbFile();
562 SequenceRenderer sr = getSequenceRenderer(alignmentv);
564 FeatureRenderer fr = null;
567 fr = getFeatureRenderer(alignmentv);
569 AlignmentI alignment = alignmentv.getAlignment();
570 StringBuffer command = new StringBuffer();
572 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
574 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
576 if (mapping == null || mapping.length < 1)
580 for (int s = 0; s < sequence[pdbfnum].length; s++)
582 for (int sp, m = 0; m < mapping.length; m++)
584 if (mapping[m].getSequence() == sequence[pdbfnum][s]
585 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
587 SequenceI asp = alignment.getSequenceAt(sp);
588 for (int r = 0; r < asp.getLength(); r++)
590 // no mapping to gaps in sequence
591 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
595 int pos = mapping[m].getPDBResNum(asp.findPosition(r));
597 if (pos < 1 || pos == lastPos)
602 Color col = sr.getResidueBoxColour(sequence[pdbfnum][s], r);
604 if (showFeatures && fr != null)
605 col = fr.findFeatureColour(col, sequence[pdbfnum][s], r);
606 String newSelcom = (mapping[m].getChain() != " " ? ":"
607 + mapping[m].getChain() : "")
616 + col.getBlue() + "]";
617 if (command.toString().endsWith(newSelcom))
619 command = condenseCommand(command.toString(), pos);
622 // TODO: deal with case when buffer is too large for Jmol to parse
623 // - execute command and flush
625 command.append(";select " + pos);
626 command.append(newSelcom);
633 evalStateCommand(command.toString());
636 public boolean isColourBySequence()
638 return colourBySequence;
641 public void setColourBySequence(boolean colourBySequence)
643 this.colourBySequence = colourBySequence;
646 StringBuffer condenseCommand(String command, int pos)
649 StringBuffer sb = new StringBuffer(command.substring(0,
650 command.lastIndexOf("select") + 7));
652 command = command.substring(sb.length());
656 if (command.indexOf("-") > -1)
658 start = command.substring(0, command.indexOf("-"));
662 start = command.substring(0, command.indexOf(":"));
665 sb.append(start + "-" + pos + command.substring(command.indexOf(":")));
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 mset[0] = viewer.getModelFileName(0);
767 for (int i = 1; i < mset.length; i++)
769 mset[j] = viewer.getModelFileName(i);
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.
946 .getModelFileName(new Integer(mdlId).intValue() - 1);
947 } catch (Exception e)
952 if (lastMessage == null || !lastMessage.equals(strInfo))
953 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
955 lastMessage = strInfo;
958 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
962 System.err.println("Ignoring additional hover info: " + data
963 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
965 mouseOverStructure(atomIndex, strInfo);
969 * { if (history != null && strStatus != null &&
970 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
974 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
977 * this implements the toggle label behaviour copied from the original
978 * structure viewer, MCView
982 System.err.println("Ignoring additional pick data string " + strData);
984 int chainSeparator = strInfo.indexOf(":");
986 if (chainSeparator == -1)
987 chainSeparator = strInfo.indexOf(".");
989 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
991 String mdlString = "";
992 if ((p = strInfo.indexOf(":")) > -1)
993 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
995 if ((p = strInfo.indexOf("/")) > -1)
997 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
999 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
1003 if (!atomsPicked.contains(picked))
1005 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
1006 atomsPicked.addElement(picked);
1010 viewer.evalString("select " + picked + ";label off");
1011 atomsPicked.removeElement(picked);
1014 // TODO: in application this happens
1016 // if (scriptWindow != null)
1018 // scriptWindow.sendConsoleMessage(strInfo);
1019 // scriptWindow.sendConsoleMessage("\n");
1024 public void notifyCallback(int type, Object[] data)
1030 case JmolConstants.CALLBACK_LOADSTRUCT:
1031 notifyFileLoaded((String) data[1], (String) data[2],
1032 (String) data[3], (String) data[4],
1033 ((Integer) data[5]).intValue());
1036 case JmolConstants.CALLBACK_PICK:
1037 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
1039 // also highlight in alignment
1040 case JmolConstants.CALLBACK_HOVER:
1041 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1044 case JmolConstants.CALLBACK_SCRIPT:
1045 notifyScriptTermination((String) data[2],
1046 ((Integer) data[3]).intValue());
1048 case JmolConstants.CALLBACK_ECHO:
1049 sendConsoleEcho((String) data[1]);
1051 case JmolConstants.CALLBACK_MESSAGE:
1052 sendConsoleMessage((data == null) ? ((String) null)
1053 : (String) data[1]);
1055 case JmolConstants.CALLBACK_ERROR:
1056 // System.err.println("Ignoring error callback.");
1058 case JmolConstants.CALLBACK_SYNC:
1059 case JmolConstants.CALLBACK_RESIZE:
1062 case JmolConstants.CALLBACK_MEASURE:
1064 case JmolConstants.CALLBACK_CLICK:
1066 System.err.println("Unhandled callback " + type + " "
1067 + data[1].toString());
1070 } catch (Exception e)
1072 System.err.println("Squashed Jmol callback handler error:");
1073 e.printStackTrace();
1077 public boolean notifyEnabled(int callbackPick)
1079 switch (callbackPick)
1081 case JmolConstants.CALLBACK_ECHO:
1082 case JmolConstants.CALLBACK_LOADSTRUCT:
1083 case JmolConstants.CALLBACK_MEASURE:
1084 case JmolConstants.CALLBACK_MESSAGE:
1085 case JmolConstants.CALLBACK_PICK:
1086 case JmolConstants.CALLBACK_SCRIPT:
1087 case JmolConstants.CALLBACK_HOVER:
1088 case JmolConstants.CALLBACK_ERROR:
1090 case JmolConstants.CALLBACK_RESIZE:
1091 case JmolConstants.CALLBACK_SYNC:
1092 case JmolConstants.CALLBACK_CLICK:
1093 case JmolConstants.CALLBACK_ANIMFRAME:
1094 case JmolConstants.CALLBACK_MINIMIZATION:
1099 // incremented every time a load notification is successfully handled -
1100 // lightweight mechanism for other threads to detect when they can start
1101 // referrring to new structures.
1102 private long loadNotifiesHandled = 0;
1104 public long getLoadNotifiesHandled()
1106 return loadNotifiesHandled;
1109 public void notifyFileLoaded(String fullPathName, String fileName2,
1110 String modelName, String errorMsg, int modelParts)
1112 if (errorMsg != null)
1114 fileLoadingError = errorMsg;
1118 // TODO: deal sensibly with models loaded inLine:
1119 // modelName will be null, as will fullPathName.
1121 // the rest of this routine ignores the arguments, and simply interrogates
1122 // the Jmol view to find out what structures it contains, and adds them to
1123 // the structure selection manager.
1124 fileLoadingError = null;
1125 String[] oldmodels = modelFileNames;
1126 modelFileNames = null;
1127 chainNames = new Vector();
1128 chainFile = new Hashtable();
1129 boolean notifyLoaded = false;
1130 String[] modelfilenames = getPdbFile();
1131 ssm = StructureSelectionManager.getStructureSelectionManager();
1132 // first check if we've lost any structures
1133 if (oldmodels != null && oldmodels.length > 0)
1136 for (int i = 0; i < oldmodels.length; i++)
1138 for (int n = 0; n < modelfilenames.length; n++)
1140 if (modelfilenames[n] == oldmodels[i])
1142 oldmodels[i] = null;
1146 if (oldmodels[i] != null)
1153 String[] oldmfn = new String[oldm];
1155 for (int i = 0; i < oldmodels.length; i++)
1157 if (oldmodels[i] != null)
1159 oldmfn[oldm++] = oldmodels[i];
1162 // deregister the Jmol instance for these structures - we'll add
1163 // ourselves again at the end for the current structure set.
1164 ssm.removeStructureViewerListener(this, oldmfn);
1167 refreshPdbEntries();
1168 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1170 String fileName = modelfilenames[modelnum];
1171 boolean foundEntry = false;
1172 MCview.PDBfile pdb = null;
1173 String pdbfile = null, pdbfhash = null;
1174 // model was probably loaded inline - so check the pdb file hashcode
1177 // calculate essential attributes for the pdb data imported inline.
1178 // prolly need to resolve modelnumber properly - for now just use our
1180 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1182 pdbfhash = "" + pdbfile.hashCode();
1184 if (pdbentry != null)
1186 // search pdbentries and sequences to find correct pdbentry for this
1188 for (int pe = 0; pe < pdbentry.length; pe++)
1190 boolean matches = false;
1191 if (fileName == null)
1194 // see JAL-623 - need method of matching pasted data up
1196 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
1197 AppletFormatAdapter.PASTE);
1198 pdbentry[modelnum].setFile("INLINE" + pdb.id);
1205 if (matches = pdbentry[pe].getFile().equals(fileName))
1208 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1211 // to be tested. See mantis bug
1212 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1213 String protocol = AppletFormatAdapter.URL;
1216 File fl = new java.io.File(pdbentry[pe].getFile());
1219 protocol = AppletFormatAdapter.FILE;
1221 } catch (Exception e)
1227 pdb = ssm.setMapping(sequence[pe], chains[pe],
1228 pdbentry[pe].getFile(), protocol);
1234 pdbentry[pe].setId(pdb.id);
1235 // add an entry for every chain in the model
1236 for (int i = 0; i < pdb.chains.size(); i++)
1238 String chid = new String(pdb.id + ":"
1239 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
1240 chainFile.put(chid, pdbentry[pe].getFile());
1241 chainNames.addElement(chid);
1243 notifyLoaded = true;
1247 if (!foundEntry && associateNewStructs)
1249 // this is a foreign pdb file that jalview doesn't know about - add
1250 // it to the dataset and try to find a home - either on a matching
1251 // sequence or as a new sequence.
1252 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1254 // parse pdb file into a chain, etc.
1255 // locate best match for pdb in associated views and add mapping to
1257 // if properly registered then
1258 notifyLoaded = true;
1263 // so finally, update the jmol bits and pieces
1264 if (jmolpopup != null)
1266 // potential for deadlock here:
1267 // jmolpopup.updateComputedMenus();
1269 if (!isLoadingFromArchive())
1271 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1273 setLoadingFromArchive(false);
1274 // register ourselves as a listener and notify the gui that it needs to
1276 ssm.addStructureViewerListener(this);
1279 FeatureRenderer fr = getFeatureRenderer(null);
1285 loadNotifiesHandled++;
1289 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1291 notifyAtomPicked(iatom, strMeasure, null);
1294 public abstract void notifyScriptTermination(String strStatus,
1298 * display a message echoed from the jmol viewer
1302 public abstract void sendConsoleEcho(String strEcho); /*
1303 * { showConsole(true);
1305 * history.append("\n" +
1309 // /End JmolStatusListener
1310 // /////////////////////////////
1314 * status message - usually the response received after a script
1317 public abstract void sendConsoleMessage(String strStatus);
1319 public void setCallbackFunction(String callbackType,
1320 String callbackFunction)
1322 System.err.println("Ignoring set-callback request to associate "
1323 + callbackType + " with function " + callbackFunction);
1327 public void setJalviewColourScheme(ColourSchemeI cs)
1329 colourBySequence = false;
1338 // TODO: Switch between nucleotide or aa selection expressions
1339 Enumeration en = ResidueProperties.aa3Hash.keys();
1340 StringBuffer command = new StringBuffer("select *;color white;");
1341 while (en.hasMoreElements())
1343 res = en.nextElement().toString();
1344 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
1348 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
1350 command.append("select " + res + ";color[" + col.getRed() + ","
1351 + col.getGreen() + "," + col.getBlue() + "];");
1354 evalStateCommand(command.toString());
1358 public void showHelp()
1360 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1364 * open the URL somehow
1368 public abstract void showUrl(String url, String target);
1371 * called when the binding thinks the UI needs to be refreshed after a Jmol
1372 * state change. this could be because structures were loaded, or because an
1373 * error has occured.
1375 public abstract void refreshGUI();
1378 * called to show or hide the associated console window container.
1382 public abstract void showConsole(boolean show);
1385 * @param renderPanel
1387 * - when true will initialise jmol's file IO system (should be false
1388 * in applet context)
1390 * @param documentBase
1392 * @param commandOptions
1394 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1395 String htmlName, URL documentBase, URL codeBase,
1396 String commandOptions)
1398 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1399 codeBase, commandOptions, null, null);
1404 * @param renderPanel
1406 * - when true will initialise jmol's file IO system (should be false
1407 * in applet context)
1409 * @param documentBase
1411 * @param commandOptions
1412 * @param consolePanel
1413 * - panel to contain Jmol console
1414 * @param buttonsToShow
1415 * - buttons to show on the console, in ordr
1417 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1418 String htmlName, URL documentBase, URL codeBase,
1419 String commandOptions, final Container consolePanel,
1420 String buttonsToShow)
1422 viewer = JmolViewer.allocateViewer(renderPanel,
1423 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1424 + ((Object) this).toString(), documentBase, codeBase,
1425 commandOptions, this);
1427 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
1428 if (consolePanel != null)
1430 consolePanel.addComponentListener(this);
1436 protected abstract JmolAppConsoleInterface createJmolConsole(
1437 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
1439 protected org.jmol.api.JmolAppConsoleInterface console = null;
1441 public void componentResized(ComponentEvent e)
1446 public void componentMoved(ComponentEvent e)
1451 public void componentShown(ComponentEvent e)
1456 public void componentHidden(ComponentEvent e)
1461 public void setLoadingFromArchive(boolean loadingFromArchive)
1463 this.loadingFromArchive = loadingFromArchive;
1466 public boolean isLoadingFromArchive()
1468 return loadingFromArchive;
1471 public void setBackgroundColour(java.awt.Color col)
1474 viewer.evalStringQuiet("background [" + col.getRed() + ","
1475 + col.getGreen() + "," + col.getBlue() + "];");
1480 * add structures and any known sequence associations
1482 * @returns the pdb entries added to the current set.
1484 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
1485 SequenceI[][] seq, String[][] chns)
1488 Vector v = new Vector();
1489 Vector rtn = new Vector();
1490 for (int i = 0; i < pdbentry.length; i++)
1492 v.addElement(pdbentry[i]);
1494 for (int i = 0; i < pdbe.length; i++)
1496 int r = v.indexOf(pdbe[i]);
1497 if (r == -1 || r >= pdbentry.length)
1499 rtn.addElement(new int[]
1501 v.addElement(pdbe[i]);
1505 // just make sure the sequence/chain entries are all up to date
1506 addSequenceAndChain(r, seq[i], chns[i]);
1509 pdbe = new PDBEntry[v.size()];
1514 // expand the tied seuqence[] and string[] arrays
1515 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
1516 String[][] sch = new String[pdbentry.length][];
1517 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
1518 System.arraycopy(chains, 0, sch, 0, this.chains.length);
1521 pdbe = new PDBEntry[rtn.size()];
1522 for (int r = 0; r < pdbe.length; r++)
1524 int[] stri = ((int[]) rtn.elementAt(r));
1525 // record the pdb file as a new addition
1526 pdbe[r] = pdbentry[stri[0]];
1527 // and add the new sequence/chain entries
1528 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
1538 public void addSequence(int pe, SequenceI[] seq)
1540 // add sequences to the pe'th pdbentry's seuqence set.
1541 addSequenceAndChain(pe, seq, null);
1544 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
1546 if (pe < 0 || pe >= pdbentry.length)
1549 "Implementation error - no corresponding pdbentry (for index "
1550 + pe + ") to add sequences mappings to");
1552 final String nullChain = "TheNullChain";
1553 Vector s = new Vector();
1554 Vector c = new Vector();
1557 chains = new String[pdbentry.length][];
1559 if (sequence[pe] != null)
1561 for (int i = 0; i < sequence[pe].length; i++)
1563 s.addElement(sequence[pe][i]);
1564 if (chains[pe] != null)
1566 if (i < chains[pe].length)
1568 c.addElement(chains[pe][i]);
1572 c.addElement(nullChain);
1577 if (tchain != null && tchain.length > 0)
1579 c.addElement(nullChain);
1584 for (int i = 0; i < seq.length; i++)
1586 if (!s.contains(seq[i]))
1588 s.addElement(seq[i]);
1589 if (tchain != null && i < tchain.length)
1591 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
1595 SequenceI[] tmp = new SequenceI[s.size()];
1600 String[] tch = new String[c.size()];
1602 for (int i = 0; i < tch.length; i++)
1604 if (tch[i] == nullChain)