2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ 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
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.ext.jmol;
23 import java.awt.Color;
24 import java.awt.Container;
25 import java.awt.event.ComponentEvent;
26 import java.awt.event.ComponentListener;
29 import java.security.AccessControlException;
30 import java.util.Hashtable;
31 import java.util.List;
33 import java.util.Vector;
35 import org.jmol.adapter.smarter.SmarterJmolAdapter;
36 import org.jmol.api.JmolAppConsoleInterface;
37 import org.jmol.api.JmolSelectionListener;
38 import org.jmol.api.JmolStatusListener;
39 import org.jmol.api.JmolViewer;
40 import org.jmol.constant.EnumCallback;
41 import org.jmol.popup.JmolPopup;
43 import jalview.api.AlignmentViewPanel;
44 import jalview.api.FeatureRenderer;
45 import jalview.api.SequenceRenderer;
46 import jalview.datamodel.AlignmentI;
47 import jalview.datamodel.ColumnSelection;
48 import jalview.datamodel.PDBEntry;
49 import jalview.datamodel.SequenceI;
50 import jalview.io.AppletFormatAdapter;
51 import jalview.schemes.ColourSchemeI;
52 import jalview.schemes.ResidueProperties;
53 import jalview.structure.StructureMapping;
54 import jalview.structure.StructureMappingcommandSet;
55 import jalview.structure.StructureSelectionManager;
56 import jalview.structures.models.AAStructureBindingModel;
57 import jalview.util.MessageManager;
59 public abstract class JalviewJmolBinding extends AAStructureBindingModel
60 implements JmolStatusListener, JmolSelectionListener,
64 * state flag used to check if the Jmol viewer's paint method can be called
66 private boolean finishedInit = false;
68 boolean allChainsSelected = false;
71 * when true, try to search the associated datamodel for sequences that are
72 * associated with any unknown structures in the Jmol view.
74 private boolean associateNewStructs = false;
76 Vector atomsPicked = new Vector();
78 public Vector chainNames;
82 StringBuffer eval = new StringBuffer();
84 public String fileLoadingError;
87 * the default or current model displayed if the model cannot be identified
88 * from the selection message
92 protected JmolPopup jmolpopup;
101 * current set of model filenames loaded in the Jmol instance
103 String[] modelFileNames = null;
105 StringBuffer resetLastRes = new StringBuffer();
107 public JmolViewer viewer;
109 public JalviewJmolBinding(StructureSelectionManager ssm,
110 PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
113 super(ssm, pdbentry, sequenceIs, chains, protocol);
115 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
116 * "jalviewJmol", ap.av.applet .getDocumentBase(),
117 * ap.av.applet.getCodeBase(), "", this);
119 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
123 public JalviewJmolBinding(StructureSelectionManager ssm,
124 SequenceI[][] seqs, JmolViewer theViewer)
129 viewer.setJmolStatusListener(this);
130 viewer.addSelectionListener(this);
134 * construct a title string for the viewer window based on the data jalview
139 public String getViewerTitle()
141 return getViewerTitle("JMol", true);
145 * prepare the view for a given set of models/chains. chainList contains
146 * strings of the form 'pdbfilename:Chaincode'
149 * list of chains to make visible
151 public void centerViewer(Vector chainList)
153 StringBuffer cmd = new StringBuffer();
156 for (int i = 0, iSize = chainList.size(); i < iSize; i++)
159 lbl = (String) chainList.elementAt(i);
163 mlength = lbl.indexOf(":", p);
164 } while (p < mlength && mlength < (lbl.length() - 2));
165 // TODO: lookup each pdb id and recover proper model number for it.
166 cmd.append(":" + lbl.substring(mlength + 1) + " /"
167 + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");
169 if (cmd.length() > 0)
171 cmd.setLength(cmd.length() - 4);
173 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
176 public void closeViewer()
178 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
179 // remove listeners for all structures in viewer
180 getSsm().removeStructureViewerListener(this, this.getPdbFile());
181 // and shut down jmol
182 viewer.evalStringQuiet("zap");
183 viewer.setJmolStatusListener(null);
186 releaseUIResources();
189 public void colourByChain()
191 colourBySequence = false;
192 // TODO: colour by chain should colour each chain distinctly across all
194 // TODO: http://issues.jalview.org/browse/JAL-628
195 evalStateCommand("select *;color chain");
198 public void colourByCharge()
200 colourBySequence = false;
201 evalStateCommand("select *;color white;select ASP,GLU;color red;"
202 + "select LYS,ARG;color blue;select CYS;color yellow");
206 * superpose the structures associated with sequences in the alignment
207 * according to their corresponding positions.
209 public void superposeStructures(AlignmentI alignment)
211 superposeStructures(alignment, -1, null);
215 * superpose the structures associated with sequences in the alignment
216 * according to their corresponding positions. ded)
218 * @param refStructure
219 * - select which pdb file to use as reference (default is -1 - the
220 * first structure in the alignment)
222 public void superposeStructures(AlignmentI alignment, int refStructure)
224 superposeStructures(alignment, refStructure, null);
228 * superpose the structures associated with sequences in the alignment
229 * according to their corresponding positions. ded)
231 * @param refStructure
232 * - select which pdb file to use as reference (default is -1 - the
233 * first structure in the alignment)
237 public void superposeStructures(AlignmentI alignment, int refStructure,
238 ColumnSelection hiddenCols)
240 superposeStructures(new AlignmentI[]
241 { alignment }, new int[]
242 { refStructure }, new ColumnSelection[]
246 public void superposeStructures(AlignmentI[] _alignment,
247 int[] _refStructure, ColumnSelection[] _hiddenCols)
249 assert (_alignment.length == _refStructure.length && _alignment.length != _hiddenCols.length);
251 String[] files = getPdbFile();
252 // check to see if we are still waiting for Jmol files
253 long starttime = System.currentTimeMillis();
254 boolean waiting = true;
258 for (String file : files)
262 // HACK - in Jalview 2.8 this call may not be threadsafe so we catch
263 // every possible exception
264 StructureMapping[] sm = getSsm().getMapping(file);
265 if (sm == null || sm.length == 0)
269 } catch (Exception x)
277 // we wait around for a reasonable time before we give up
279 && System.currentTimeMillis() < (10000 + 1000 * files.length + starttime));
283 .println("RUNTIME PROBLEM: Jmol seems to be taking a long time to process all the structures.");
286 StringBuffer selectioncom = new StringBuffer();
287 // In principle - nSeconds specifies the speed of animation for each
288 // superposition - but is seems to behave weirdly, so we don't specify it.
289 String nSeconds = " ";
290 if (files.length > 10)
292 nSeconds = " 0.00001 ";
296 nSeconds = " " + (2.0 / files.length) + " ";
297 // if (nSeconds).substring(0,5)+" ";
299 // see JAL-1345 - should really automatically turn off the animation for
300 // large numbers of structures, but Jmol doesn't seem to allow that.
302 // union of all aligned positions are collected together.
303 for (int a = 0; a < _alignment.length; a++)
305 int refStructure = _refStructure[a];
306 AlignmentI alignment = _alignment[a];
307 ColumnSelection hiddenCols = _hiddenCols[a];
309 && selectioncom.length() > 0
310 && !selectioncom.substring(selectioncom.length() - 1).equals(
313 selectioncom.append("|");
315 // process this alignment
316 if (refStructure >= files.length)
318 System.err.println("Invalid reference structure value "
322 if (refStructure < -1)
326 StringBuffer command = new StringBuffer();
328 boolean matched[] = new boolean[alignment.getWidth()];
329 for (int m = 0; m < matched.length; m++)
332 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
335 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
336 String isel[] = new String[files.length];
337 // reference structure - all others are superposed in it
338 String[] targetC = new String[files.length];
339 String[] chainNames = new String[files.length];
340 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
342 StructureMapping[] mapping = getSsm().getMapping(files[pdbfnum]);
343 // RACE CONDITION - getMapping only returns Jmol loaded filenames once
344 // Jmol callback has completed.
345 if (mapping == null || mapping.length < 1)
347 throw new Error(MessageManager.getString("error.implementation_error_jmol_getting_data"));
350 final int sequenceCountForPdbFile = getSequence()[pdbfnum].length;
351 for (int s = 0; s < sequenceCountForPdbFile; s++)
353 for (int sp, m = 0; m < mapping.length; m++)
355 if (mapping[m].getSequence() == getSequence()[pdbfnum][s]
356 && (sp = alignment.findIndex(getSequence()[pdbfnum][s])) > -1)
358 if (refStructure == -1)
360 refStructure = pdbfnum;
362 SequenceI asp = alignment.getSequenceAt(sp);
363 for (int r = 0; r < matched.length; r++)
369 matched[r] = false; // assume this is not a good site
370 if (r >= asp.getLength())
375 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
377 // no mapping to gaps in sequence
380 int t = asp.findPosition(r); // sequence position
381 int apos = mapping[m].getAtomNum(t);
382 int pos = mapping[m].getPDBResNum(t);
384 if (pos < 1 || pos == lastPos)
386 // can't align unmapped sequence
389 matched[r] = true; // this is a good ite
391 // just record this residue position
392 commonrpositions[pdbfnum][r] = pos;
394 // create model selection suffix
395 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
396 if (mapping[m].getChain() == null
397 || mapping[m].getChain().trim().length() == 0)
399 targetC[pdbfnum] = "";
403 targetC[pdbfnum] = ":" + mapping[m].getChain();
405 chainNames[pdbfnum] = mapping[m].getPdbId()
407 // move on to next pdb file
408 s = getSequence()[pdbfnum].length;
415 // TODO: consider bailing if nmatched less than 4 because superposition
418 // TODO: refactor superposable position search (above) from jmol selection
419 // construction (below)
421 String[] selcom = new String[files.length];
423 // generate select statements to select regions to superimpose structures
425 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
427 String chainCd = targetC[pdbfnum];
430 StringBuffer molsel = new StringBuffer();
432 for (int r = 0; r < matched.length; r++)
440 if (lpos != commonrpositions[pdbfnum][r] - 1)
446 molsel.append(chainCd);
447 // molsel.append("} {");
453 // continuous run - and lpos >-1
456 // at the beginning, so add dash
462 lpos = commonrpositions[pdbfnum][r];
463 // molsel.append(lpos);
466 // add final selection phrase
470 molsel.append(chainCd);
473 if (molsel.length() > 1)
475 selcom[pdbfnum] = molsel.toString();
476 selectioncom.append("((");
477 selectioncom.append(selcom[pdbfnum].substring(1,
478 selcom[pdbfnum].length() - 1));
479 selectioncom.append(" )& ");
480 selectioncom.append(pdbfnum + 1);
481 selectioncom.append(".1)");
482 if (pdbfnum < files.length - 1)
484 selectioncom.append("|");
489 selcom[pdbfnum] = null;
493 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
495 if (pdbfnum == refStructure || selcom[pdbfnum] == null
496 || selcom[refStructure] == null)
500 command.append("echo ");
501 command.append("\"Superposing (");
502 command.append(chainNames[pdbfnum]);
503 command.append(") against reference (");
504 command.append(chainNames[refStructure]);
505 command.append(")\";\ncompare " + nSeconds);
507 command.append(1 + pdbfnum);
508 command.append(".1} {");
509 command.append(1 + refStructure);
510 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
512 // form the matched pair strings
514 for (int s = 0; s < 2; s++)
516 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
518 command.append(" ROTATE TRANSLATE;\n");
520 if (selectioncom.length() > 0)
522 System.out.println("Select regions:\n" + selectioncom.toString());
523 evalStateCommand("select *; cartoons off; backbone; select ("
524 + selectioncom.toString() + "); cartoons; ");
525 // selcom.append("; ribbons; ");
527 .println("Superimpose command(s):\n" + command.toString());
529 evalStateCommand(command.toString());
532 if (selectioncom.length() > 0)
533 {// finally, mark all regions that were superposed.
534 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
536 selectioncom.setLength(selectioncom.length() - 1);
538 System.out.println("Select regions:\n" + selectioncom.toString());
539 evalStateCommand("select *; cartoons off; backbone; select ("
540 + selectioncom.toString() + "); cartoons; ");
541 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
545 public void evalStateCommand(String command)
548 if (lastCommand == null || !lastCommand.equals(command))
550 viewer.evalStringQuiet(command + "\n");
553 lastCommand = command;
557 * colour any structures associated with sequences in the given alignment
558 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
559 * if colourBySequence is enabled.
561 public void colourBySequence(boolean showFeatures,
562 jalview.api.AlignmentViewPanel alignmentv)
564 if (!colourBySequence || !isLoadingFinished())
568 if (getSsm() == null)
572 String[] files = getPdbFile();
574 SequenceRenderer sr = getSequenceRenderer(alignmentv);
576 FeatureRenderer fr = null;
579 fr = getFeatureRenderer(alignmentv);
581 AlignmentI alignment = alignmentv.getAlignment();
583 for (jalview.structure.StructureMappingcommandSet cpdbbyseq : getColourBySequenceCommands(files, sr, fr, alignment))
585 for (String cbyseq : cpdbbyseq.commands)
587 executeWhenReady(cbyseq);
599 protected StructureMappingcommandSet[] getColourBySequenceCommands(
600 String[] files, SequenceRenderer sr, FeatureRenderer fr,
601 AlignmentI alignment)
604 .getColourBySequenceCommand(getSsm(), files, getSequence(), sr,
612 protected void executeWhenReady(String command)
614 evalStateCommand(command);
617 public void createImage(String file, String type, int quality)
619 System.out.println("JMOL CREATE IMAGE");
622 public String createImage(String fileName, String type,
623 Object textOrBytes, int quality)
625 System.out.println("JMOL CREATE IMAGE");
629 public String eval(String strEval)
631 // System.out.println(strEval);
632 // "# 'eval' is implemented only for the applet.";
636 // End StructureListener
637 // //////////////////////////
639 public float[][] functionXY(String functionName, int x, int y)
644 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
646 // TODO Auto-generated method stub
650 public Color getColour(int atomIndex, int pdbResNum, String chain,
653 if (getModelNum(pdbfile) < 0)
657 // TODO: verify atomIndex is selecting correct model.
658 return new Color(viewer.getAtomArgb(atomIndex));
662 * returns the current featureRenderer that should be used to colour the
669 public abstract FeatureRenderer getFeatureRenderer(
670 AlignmentViewPanel alignment);
673 * instruct the Jalview binding to update the pdbentries vector if necessary
674 * prior to matching the jmol view's contents to the list of structure files
675 * Jalview knows about.
677 public abstract void refreshPdbEntries();
679 private int getModelNum(String modelFileName)
681 String[] mfn = getPdbFile();
686 for (int i = 0; i < mfn.length; i++)
688 if (mfn[i].equalsIgnoreCase(modelFileName))
697 * map between index of model filename returned from getPdbFile and the first
698 * index of models from this file in the viewer. Note - this is not trimmed -
699 * use getPdbFile to get number of unique models.
701 private int _modelFileNameMap[];
703 // ////////////////////////////////
704 // /StructureListener
705 public synchronized String[] getPdbFile()
709 return new String[0];
711 if (modelFileNames == null)
714 String mset[] = new String[viewer.getModelCount()];
715 _modelFileNameMap = new int[mset.length];
717 String m = viewer.getModelFileName(0);
722 mset[0] = new File(m).getAbsolutePath();
723 } catch (AccessControlException x)
725 // usually not allowed to do this in applet, so keep raw handle
727 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
730 for (int i = 1; i < mset.length; i++)
732 m = viewer.getModelFileName(i);
737 mset[j] = new File(m).getAbsolutePath();
738 } catch (AccessControlException x)
740 // usually not allowed to do this in applet, so keep raw handle
742 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
745 _modelFileNameMap[j] = i; // record the model index for the filename
746 // skip any additional models in the same file (NMR structures)
747 if ((mset[j] == null ? mset[j] != mset[j - 1]
748 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
753 modelFileNames = new String[j];
754 System.arraycopy(mset, 0, modelFileNames, 0, j);
756 return modelFileNames;
760 * map from string to applet
763 public Map<String, Object> getRegistryInfo()
765 // TODO Auto-generated method stub
770 * returns the current sequenceRenderer that should be used to colour the
777 public abstract SequenceRenderer getSequenceRenderer(
778 AlignmentViewPanel alignment);
780 // ///////////////////////////////
781 // JmolStatusListener
783 public void handlePopupMenu(int x, int y)
785 jmolpopup.show(x, y);
789 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
792 if (modelFileNames == null)
797 // look up file model number for this pdbfile
800 // may need to adjust for URLencoding here - we don't worry about that yet.
801 while (mdlNum < modelFileNames.length
802 && !pdbfile.equals(modelFileNames[mdlNum]))
804 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
807 if (mdlNum == modelFileNames.length)
813 // if (!pdbfile.equals(pdbentry.getFile()))
815 if (resetLastRes.length() > 0)
817 viewer.evalStringQuiet(resetLastRes.toString());
821 eval.append("select " + pdbResNum); // +modelNum
823 resetLastRes.setLength(0);
824 resetLastRes.append("select " + pdbResNum); // +modelNum
827 resetLastRes.append(":");
828 if (!chain.equals(" "))
831 resetLastRes.append(chain);
834 eval.append(" /" + (mdlNum + 1));
835 resetLastRes.append("/" + (mdlNum + 1));
837 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
839 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
840 + " and not hetero; spacefill 0;");
842 eval.append("spacefill 200;select none");
844 viewer.evalStringQuiet(eval.toString());
849 boolean debug = true;
851 private void jmolHistory(boolean enable)
853 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
856 public void loadInline(String string)
860 // viewer.loadInline(strModel, isAppend);
862 // construct fake fullPathName and fileName so we can identify the file
864 // Then, construct pass a reader for the string to Jmol.
865 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
866 // fileName, null, reader, false, null, null, 0);
867 viewer.openStringInline(string);
870 public void mouseOverStructure(int atomIndex, String strInfo)
873 int alocsep = strInfo.indexOf("^");
874 int mdlSep = strInfo.indexOf("/");
875 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
877 if (chainSeparator == -1)
879 chainSeparator = strInfo.indexOf(".");
880 if (mdlSep > -1 && mdlSep < chainSeparator)
882 chainSeparator1 = chainSeparator;
883 chainSeparator = mdlSep;
886 // handle insertion codes
889 pdbResNum = Integer.parseInt(strInfo.substring(
890 strInfo.indexOf("]") + 1, alocsep));
895 pdbResNum = Integer.parseInt(strInfo.substring(
896 strInfo.indexOf("]") + 1, chainSeparator));
900 if (strInfo.indexOf(":") > -1)
902 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
903 strInfo.indexOf("."));
910 String pdbfilename = modelFileNames[frameNo]; // default is first or current
914 if (chainSeparator1 == -1)
916 chainSeparator1 = strInfo.indexOf(".", mdlSep);
918 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
919 chainSeparator1) : strInfo.substring(mdlSep + 1);
922 // recover PDB filename for the model hovered over.
923 int _mp = _modelFileNameMap.length - 1, mnumber = new Integer(mdlId)
925 while (mnumber < _modelFileNameMap[_mp])
929 pdbfilename = modelFileNames[_mp];
930 if (pdbfilename == null)
932 pdbfilename = new File(viewer.getModelFileName(mnumber))
936 } catch (Exception e)
941 if (lastMessage == null || !lastMessage.equals(strInfo))
943 getSsm().mouseOverStructure(pdbResNum, chainId, pdbfilename);
946 lastMessage = strInfo;
949 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
953 System.err.println("Ignoring additional hover info: " + data
954 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
956 mouseOverStructure(atomIndex, strInfo);
960 * { if (history != null && strStatus != null &&
961 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
965 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
968 * this implements the toggle label behaviour copied from the original
969 * structure viewer, MCView
973 System.err.println("Ignoring additional pick data string " + strData);
975 int chainSeparator = strInfo.indexOf(":");
977 if (chainSeparator == -1)
979 chainSeparator = strInfo.indexOf(".");
982 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
984 String mdlString = "";
985 if ((p = strInfo.indexOf(":")) > -1)
987 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
990 if ((p = strInfo.indexOf("/")) > -1)
992 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
994 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
998 if (!atomsPicked.contains(picked))
1000 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
1001 atomsPicked.addElement(picked);
1005 viewer.evalString("select " + picked + ";label off");
1006 atomsPicked.removeElement(picked);
1009 // TODO: in application this happens
1011 // if (scriptWindow != null)
1013 // scriptWindow.sendConsoleMessage(strInfo);
1014 // scriptWindow.sendConsoleMessage("\n");
1020 public void notifyCallback(EnumCallback type, Object[] data)
1027 notifyFileLoaded((String) data[1], (String) data[2],
1028 (String) data[3], (String) data[4],
1029 ((Integer) data[5]).intValue());
1033 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
1035 // also highlight in alignment
1037 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1041 notifyScriptTermination((String) data[2],
1042 ((Integer) data[3]).intValue());
1045 sendConsoleEcho((String) data[1]);
1048 sendConsoleMessage((data == null) ? ((String) null)
1049 : (String) data[1]);
1052 // System.err.println("Ignoring error callback.");
1062 System.err.println("Unhandled callback " + type + " "
1063 + data[1].toString());
1066 } catch (Exception e)
1068 System.err.println("Squashed Jmol callback handler error:");
1069 e.printStackTrace();
1074 public boolean notifyEnabled(EnumCallback callbackPick)
1076 switch (callbackPick)
1096 // incremented every time a load notification is successfully handled -
1097 // lightweight mechanism for other threads to detect when they can start
1098 // referrring to new structures.
1099 private long loadNotifiesHandled = 0;
1101 public long getLoadNotifiesHandled()
1103 return loadNotifiesHandled;
1106 public void notifyFileLoaded(String fullPathName, String fileName2,
1107 String modelName, String errorMsg, int modelParts)
1109 if (errorMsg != null)
1111 fileLoadingError = errorMsg;
1115 // TODO: deal sensibly with models loaded inLine:
1116 // modelName will be null, as will fullPathName.
1118 // the rest of this routine ignores the arguments, and simply interrogates
1119 // the Jmol view to find out what structures it contains, and adds them to
1120 // the structure selection manager.
1121 fileLoadingError = null;
1122 String[] oldmodels = modelFileNames;
1123 modelFileNames = null;
1124 chainNames = new Vector();
1125 chainFile = new Hashtable();
1126 boolean notifyLoaded = false;
1127 String[] modelfilenames = getPdbFile();
1128 // first check if we've lost any structures
1129 if (oldmodels != null && oldmodels.length > 0)
1132 for (int i = 0; i < oldmodels.length; i++)
1134 for (int n = 0; n < modelfilenames.length; n++)
1136 if (modelfilenames[n] == oldmodels[i])
1138 oldmodels[i] = null;
1142 if (oldmodels[i] != null)
1149 String[] oldmfn = new String[oldm];
1151 for (int i = 0; i < oldmodels.length; i++)
1153 if (oldmodels[i] != null)
1155 oldmfn[oldm++] = oldmodels[i];
1158 // deregister the Jmol instance for these structures - we'll add
1159 // ourselves again at the end for the current structure set.
1160 getSsm().removeStructureViewerListener(this, oldmfn);
1163 refreshPdbEntries();
1164 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1166 String fileName = modelfilenames[modelnum];
1167 boolean foundEntry = false;
1168 MCview.PDBfile pdb = null;
1169 String pdbfile = null, pdbfhash = null;
1170 // model was probably loaded inline - so check the pdb file hashcode
1173 // calculate essential attributes for the pdb data imported inline.
1174 // prolly need to resolve modelnumber properly - for now just use our
1176 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1178 pdbfhash = "" + pdbfile.hashCode();
1180 // search pdbentries and sequences to find correct pdbentry for this
1182 for (int pe = 0; pe < getPdbCount(); pe++)
1184 boolean matches = false;
1185 if (fileName == null)
1188 // see JAL-623 - need method of matching pasted data up
1190 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1191 pdbfile, AppletFormatAdapter.PASTE);
1192 getPdbEntry(modelnum).setFile("INLINE" + pdb.id);
1200 if (matches = (fl = new File(getPdbEntry(pe).getFile()))
1201 .equals(new File(fileName)))
1204 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1207 // to be tested. See mantis bug
1208 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1209 String protocol = AppletFormatAdapter.URL;
1214 protocol = AppletFormatAdapter.FILE;
1216 } catch (Exception e)
1221 // Explicitly map to the filename used by Jmol ;
1222 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1223 fileName, protocol);
1224 // pdbentry[pe].getFile(), protocol);
1230 // add an entry for every chain in the model
1231 for (int i = 0; i < pdb.chains.size(); i++)
1233 String chid = new String(pdb.id + ":"
1234 + pdb.chains.elementAt(i).id);
1235 chainFile.put(chid, fileName);
1236 chainNames.addElement(chid);
1238 notifyLoaded = true;
1242 if (!foundEntry && associateNewStructs)
1244 // this is a foreign pdb file that jalview doesn't know about - add
1245 // it to the dataset and try to find a home - either on a matching
1246 // sequence or as a new sequence.
1247 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1249 // parse pdb file into a chain, etc.
1250 // locate best match for pdb in associated views and add mapping to
1252 // if properly registered then
1253 notifyLoaded = true;
1258 // so finally, update the jmol bits and pieces
1259 if (jmolpopup != null)
1261 // potential for deadlock here:
1262 // jmolpopup.updateComputedMenus();
1264 if (!isLoadingFromArchive())
1266 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1268 // register ourselves as a listener and notify the gui that it needs to
1270 getSsm().addStructureViewerListener(this);
1273 FeatureRenderer fr = getFeatureRenderer(null);
1279 loadNotifiesHandled++;
1281 setLoadingFromArchive(false);
1284 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1286 notifyAtomPicked(iatom, strMeasure, null);
1289 public abstract void notifyScriptTermination(String strStatus,
1293 * display a message echoed from the jmol viewer
1297 public abstract void sendConsoleEcho(String strEcho); /*
1298 * { showConsole(true);
1300 * history.append("\n" +
1304 // /End JmolStatusListener
1305 // /////////////////////////////
1309 * status message - usually the response received after a script
1312 public abstract void sendConsoleMessage(String strStatus);
1314 public void setCallbackFunction(String callbackType,
1315 String callbackFunction)
1317 System.err.println("Ignoring set-callback request to associate "
1318 + callbackType + " with function " + callbackFunction);
1322 public void setJalviewColourScheme(ColourSchemeI cs)
1324 colourBySequence = false;
1332 StringBuilder command = new StringBuilder(128);
1333 command.append("select *;color white;");
1334 List<String> residueSet = ResidueProperties.getResidues(isNucleotide(),
1336 for (String res : residueSet)
1338 Color col = cs.findColour(res.charAt(0));
1339 command.append("select " + res + ";color[" + col.getRed() + ","
1340 + col.getGreen() + "," + col.getBlue() + "];");
1343 evalStateCommand(command.toString());
1347 public void showHelp()
1349 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1353 * open the URL somehow
1357 public abstract void showUrl(String url, String target);
1360 * called when the binding thinks the UI needs to be refreshed after a Jmol
1361 * state change. this could be because structures were loaded, or because an
1362 * error has occured.
1364 public abstract void refreshGUI();
1367 * called to show or hide the associated console window container.
1371 public abstract void showConsole(boolean show);
1374 * @param renderPanel
1376 * - when true will initialise jmol's file IO system (should be false
1377 * in applet context)
1379 * @param documentBase
1381 * @param commandOptions
1383 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1384 String htmlName, URL documentBase, URL codeBase,
1385 String commandOptions)
1387 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1388 codeBase, commandOptions, null, null);
1393 * @param renderPanel
1395 * - when true will initialise jmol's file IO system (should be false
1396 * in applet context)
1398 * @param documentBase
1400 * @param commandOptions
1401 * @param consolePanel
1402 * - panel to contain Jmol console
1403 * @param buttonsToShow
1404 * - buttons to show on the console, in ordr
1406 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1407 String htmlName, URL documentBase, URL codeBase,
1408 String commandOptions, final Container consolePanel,
1409 String buttonsToShow)
1411 if (commandOptions == null)
1413 commandOptions = "";
1415 viewer = JmolViewer.allocateViewer(renderPanel,
1416 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1417 + ((Object) this).toString(), documentBase, codeBase,
1418 commandOptions, this);
1420 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
1421 if (consolePanel != null)
1423 consolePanel.addComponentListener(this);
1429 protected abstract JmolAppConsoleInterface createJmolConsole(
1430 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
1432 protected org.jmol.api.JmolAppConsoleInterface console = null;
1434 public void setBackgroundColour(java.awt.Color col)
1437 viewer.evalStringQuiet("background [" + col.getRed() + ","
1438 + col.getGreen() + "," + col.getBlue() + "];");
1445 * @return text report of alignment between pdbfile and any associated
1446 * alignment sequences
1448 public String printMapping(String pdbfile)
1450 return getSsm().printMapping(pdbfile);
1454 public void resizeInnerPanel(String data)
1456 // Jalview doesn't honour resize panel requests
1460 public boolean isFinishedInit()
1462 return finishedInit;
1465 public void setFinishedInit(boolean finishedInit)
1467 this.finishedInit = finishedInit;
1473 protected void closeConsole()
1475 if (console != null)
1479 console.setVisible(false);
1482 } catch (Exception x)
1491 * ComponentListener method
1494 public void componentMoved(ComponentEvent e)
1499 * ComponentListener method
1502 public void componentResized(ComponentEvent e)
1507 * ComponentListener method
1510 public void componentShown(ComponentEvent e)
1516 * ComponentListener method
1519 public void componentHidden(ComponentEvent e)