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 // conformation=1 excludes alternate locations for CA (JAL-1757)
511 command.append(".1} SUBSET {(*.CA | *.P) and conformation=1} ATOMS ");
513 // form the matched pair strings
515 for (int s = 0; s < 2; s++)
517 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
519 command.append(" ROTATE TRANSLATE;\n");
521 if (selectioncom.length() > 0)
523 System.out.println("Select regions:\n" + selectioncom.toString());
524 evalStateCommand("select *; cartoons off; backbone; select ("
525 + selectioncom.toString() + "); cartoons; ");
526 // selcom.append("; ribbons; ");
528 .println("Superimpose command(s):\n" + command.toString());
530 evalStateCommand(command.toString());
533 if (selectioncom.length() > 0)
534 {// finally, mark all regions that were superposed.
535 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
537 selectioncom.setLength(selectioncom.length() - 1);
539 System.out.println("Select regions:\n" + selectioncom.toString());
540 evalStateCommand("select *; cartoons off; backbone; select ("
541 + selectioncom.toString() + "); cartoons; ");
542 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
546 public void evalStateCommand(String command)
549 if (lastCommand == null || !lastCommand.equals(command))
551 viewer.evalStringQuiet(command + "\n");
554 lastCommand = command;
558 * colour any structures associated with sequences in the given alignment
559 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
560 * if colourBySequence is enabled.
562 public void colourBySequence(boolean showFeatures,
563 jalview.api.AlignmentViewPanel alignmentv)
565 if (!colourBySequence || !isLoadingFinished())
569 if (getSsm() == null)
573 String[] files = getPdbFile();
575 SequenceRenderer sr = getSequenceRenderer(alignmentv);
577 FeatureRenderer fr = null;
580 fr = getFeatureRenderer(alignmentv);
582 AlignmentI alignment = alignmentv.getAlignment();
584 for (jalview.structure.StructureMappingcommandSet cpdbbyseq : getColourBySequenceCommands(files, sr, fr, alignment))
586 for (String cbyseq : cpdbbyseq.commands)
588 executeWhenReady(cbyseq);
600 protected StructureMappingcommandSet[] getColourBySequenceCommands(
601 String[] files, SequenceRenderer sr, FeatureRenderer fr,
602 AlignmentI alignment)
605 .getColourBySequenceCommand(getSsm(), files, getSequence(), sr,
613 protected void executeWhenReady(String command)
615 evalStateCommand(command);
618 public void createImage(String file, String type, int quality)
620 System.out.println("JMOL CREATE IMAGE");
623 public String createImage(String fileName, String type,
624 Object textOrBytes, int quality)
626 System.out.println("JMOL CREATE IMAGE");
630 public String eval(String strEval)
632 // System.out.println(strEval);
633 // "# 'eval' is implemented only for the applet.";
637 // End StructureListener
638 // //////////////////////////
640 public float[][] functionXY(String functionName, int x, int y)
645 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
647 // TODO Auto-generated method stub
651 public Color getColour(int atomIndex, int pdbResNum, String chain,
654 if (getModelNum(pdbfile) < 0)
658 // TODO: verify atomIndex is selecting correct model.
659 return new Color(viewer.getAtomArgb(atomIndex));
663 * returns the current featureRenderer that should be used to colour the
670 public abstract FeatureRenderer getFeatureRenderer(
671 AlignmentViewPanel alignment);
674 * instruct the Jalview binding to update the pdbentries vector if necessary
675 * prior to matching the jmol view's contents to the list of structure files
676 * Jalview knows about.
678 public abstract void refreshPdbEntries();
680 private int getModelNum(String modelFileName)
682 String[] mfn = getPdbFile();
687 for (int i = 0; i < mfn.length; i++)
689 if (mfn[i].equalsIgnoreCase(modelFileName))
698 * map between index of model filename returned from getPdbFile and the first
699 * index of models from this file in the viewer. Note - this is not trimmed -
700 * use getPdbFile to get number of unique models.
702 private int _modelFileNameMap[];
704 // ////////////////////////////////
705 // /StructureListener
706 public synchronized String[] getPdbFile()
710 return new String[0];
712 if (modelFileNames == null)
715 String mset[] = new String[viewer.getModelCount()];
716 _modelFileNameMap = new int[mset.length];
718 String m = viewer.getModelFileName(0);
723 mset[0] = new File(m).getAbsolutePath();
724 } catch (AccessControlException x)
726 // usually not allowed to do this in applet, so keep raw handle
728 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
731 for (int i = 1; i < mset.length; i++)
733 m = viewer.getModelFileName(i);
738 mset[j] = new File(m).getAbsolutePath();
739 } catch (AccessControlException x)
741 // usually not allowed to do this in applet, so keep raw handle
743 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
746 _modelFileNameMap[j] = i; // record the model index for the filename
747 // skip any additional models in the same file (NMR structures)
748 if ((mset[j] == null ? mset[j] != mset[j - 1]
749 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
754 modelFileNames = new String[j];
755 System.arraycopy(mset, 0, modelFileNames, 0, j);
757 return modelFileNames;
761 * map from string to applet
764 public Map<String, Object> getRegistryInfo()
766 // TODO Auto-generated method stub
771 * returns the current sequenceRenderer that should be used to colour the
778 public abstract SequenceRenderer getSequenceRenderer(
779 AlignmentViewPanel alignment);
781 // ///////////////////////////////
782 // JmolStatusListener
784 public void handlePopupMenu(int x, int y)
786 jmolpopup.show(x, y);
790 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
793 if (modelFileNames == null)
798 // look up file model number for this pdbfile
801 // may need to adjust for URLencoding here - we don't worry about that yet.
802 while (mdlNum < modelFileNames.length
803 && !pdbfile.equals(modelFileNames[mdlNum]))
805 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
808 if (mdlNum == modelFileNames.length)
814 // if (!pdbfile.equals(pdbentry.getFile()))
816 if (resetLastRes.length() > 0)
818 viewer.evalStringQuiet(resetLastRes.toString());
822 eval.append("select " + pdbResNum); // +modelNum
824 resetLastRes.setLength(0);
825 resetLastRes.append("select " + pdbResNum); // +modelNum
828 resetLastRes.append(":");
829 if (!chain.equals(" "))
832 resetLastRes.append(chain);
835 eval.append(" /" + (mdlNum + 1));
836 resetLastRes.append("/" + (mdlNum + 1));
838 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
840 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
841 + " and not hetero; spacefill 0;");
843 eval.append("spacefill 200;select none");
845 viewer.evalStringQuiet(eval.toString());
850 boolean debug = true;
852 private void jmolHistory(boolean enable)
854 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
857 public void loadInline(String string)
861 // viewer.loadInline(strModel, isAppend);
863 // construct fake fullPathName and fileName so we can identify the file
865 // Then, construct pass a reader for the string to Jmol.
866 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
867 // fileName, null, reader, false, null, null, 0);
868 viewer.openStringInline(string);
871 public void mouseOverStructure(int atomIndex, String strInfo)
874 int alocsep = strInfo.indexOf("^");
875 int mdlSep = strInfo.indexOf("/");
876 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
878 if (chainSeparator == -1)
880 chainSeparator = strInfo.indexOf(".");
881 if (mdlSep > -1 && mdlSep < chainSeparator)
883 chainSeparator1 = chainSeparator;
884 chainSeparator = mdlSep;
887 // handle insertion codes
890 pdbResNum = Integer.parseInt(strInfo.substring(
891 strInfo.indexOf("]") + 1, alocsep));
896 pdbResNum = Integer.parseInt(strInfo.substring(
897 strInfo.indexOf("]") + 1, chainSeparator));
901 if (strInfo.indexOf(":") > -1)
903 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
904 strInfo.indexOf("."));
911 String pdbfilename = modelFileNames[frameNo]; // default is first or current
915 if (chainSeparator1 == -1)
917 chainSeparator1 = strInfo.indexOf(".", mdlSep);
919 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
920 chainSeparator1) : strInfo.substring(mdlSep + 1);
923 // recover PDB filename for the model hovered over.
924 int _mp = _modelFileNameMap.length - 1, mnumber = new Integer(mdlId)
926 while (mnumber < _modelFileNameMap[_mp])
930 pdbfilename = modelFileNames[_mp];
931 if (pdbfilename == null)
933 pdbfilename = new File(viewer.getModelFileName(mnumber))
937 } catch (Exception e)
942 if (lastMessage == null || !lastMessage.equals(strInfo))
944 getSsm().mouseOverStructure(pdbResNum, chainId, pdbfilename);
947 lastMessage = strInfo;
950 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
954 System.err.println("Ignoring additional hover info: " + data
955 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
957 mouseOverStructure(atomIndex, strInfo);
961 * { if (history != null && strStatus != null &&
962 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
966 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
969 * this implements the toggle label behaviour copied from the original
970 * structure viewer, MCView
974 System.err.println("Ignoring additional pick data string " + strData);
976 int chainSeparator = strInfo.indexOf(":");
978 if (chainSeparator == -1)
980 chainSeparator = strInfo.indexOf(".");
983 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
985 String mdlString = "";
986 if ((p = strInfo.indexOf(":")) > -1)
988 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
991 if ((p = strInfo.indexOf("/")) > -1)
993 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
995 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
999 if (!atomsPicked.contains(picked))
1001 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
1002 atomsPicked.addElement(picked);
1006 viewer.evalString("select " + picked + ";label off");
1007 atomsPicked.removeElement(picked);
1010 // TODO: in application this happens
1012 // if (scriptWindow != null)
1014 // scriptWindow.sendConsoleMessage(strInfo);
1015 // scriptWindow.sendConsoleMessage("\n");
1021 public void notifyCallback(EnumCallback type, Object[] data)
1028 notifyFileLoaded((String) data[1], (String) data[2],
1029 (String) data[3], (String) data[4],
1030 ((Integer) data[5]).intValue());
1034 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
1036 // also highlight in alignment
1038 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1042 notifyScriptTermination((String) data[2],
1043 ((Integer) data[3]).intValue());
1046 sendConsoleEcho((String) data[1]);
1049 sendConsoleMessage((data == null) ? ((String) null)
1050 : (String) data[1]);
1053 // System.err.println("Ignoring error callback.");
1063 System.err.println("Unhandled callback " + type + " "
1064 + data[1].toString());
1067 } catch (Exception e)
1069 System.err.println("Squashed Jmol callback handler error:");
1070 e.printStackTrace();
1075 public boolean notifyEnabled(EnumCallback callbackPick)
1077 switch (callbackPick)
1097 // incremented every time a load notification is successfully handled -
1098 // lightweight mechanism for other threads to detect when they can start
1099 // referrring to new structures.
1100 private long loadNotifiesHandled = 0;
1102 public long getLoadNotifiesHandled()
1104 return loadNotifiesHandled;
1107 public void notifyFileLoaded(String fullPathName, String fileName2,
1108 String modelName, String errorMsg, int modelParts)
1110 if (errorMsg != null)
1112 fileLoadingError = errorMsg;
1116 // TODO: deal sensibly with models loaded inLine:
1117 // modelName will be null, as will fullPathName.
1119 // the rest of this routine ignores the arguments, and simply interrogates
1120 // the Jmol view to find out what structures it contains, and adds them to
1121 // the structure selection manager.
1122 fileLoadingError = null;
1123 String[] oldmodels = modelFileNames;
1124 modelFileNames = null;
1125 chainNames = new Vector();
1126 chainFile = new Hashtable();
1127 boolean notifyLoaded = false;
1128 String[] modelfilenames = getPdbFile();
1129 // first check if we've lost any structures
1130 if (oldmodels != null && oldmodels.length > 0)
1133 for (int i = 0; i < oldmodels.length; i++)
1135 for (int n = 0; n < modelfilenames.length; n++)
1137 if (modelfilenames[n] == oldmodels[i])
1139 oldmodels[i] = null;
1143 if (oldmodels[i] != null)
1150 String[] oldmfn = new String[oldm];
1152 for (int i = 0; i < oldmodels.length; i++)
1154 if (oldmodels[i] != null)
1156 oldmfn[oldm++] = oldmodels[i];
1159 // deregister the Jmol instance for these structures - we'll add
1160 // ourselves again at the end for the current structure set.
1161 getSsm().removeStructureViewerListener(this, oldmfn);
1164 refreshPdbEntries();
1165 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1167 String fileName = modelfilenames[modelnum];
1168 boolean foundEntry = false;
1169 MCview.PDBfile pdb = null;
1170 String pdbfile = null, pdbfhash = null;
1171 // model was probably loaded inline - so check the pdb file hashcode
1174 // calculate essential attributes for the pdb data imported inline.
1175 // prolly need to resolve modelnumber properly - for now just use our
1177 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1179 pdbfhash = "" + pdbfile.hashCode();
1181 // search pdbentries and sequences to find correct pdbentry for this
1183 for (int pe = 0; pe < getPdbCount(); pe++)
1185 boolean matches = false;
1186 if (fileName == null)
1189 // see JAL-623 - need method of matching pasted data up
1191 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1192 pdbfile, AppletFormatAdapter.PASTE);
1193 getPdbEntry(modelnum).setFile("INLINE" + pdb.id);
1201 if (matches = (fl = new File(getPdbEntry(pe).getFile()))
1202 .equals(new File(fileName)))
1205 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1208 // to be tested. See mantis bug
1209 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1210 String protocol = AppletFormatAdapter.URL;
1215 protocol = AppletFormatAdapter.FILE;
1217 } catch (Exception e)
1222 // Explicitly map to the filename used by Jmol ;
1223 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1224 fileName, protocol);
1225 // pdbentry[pe].getFile(), protocol);
1231 // add an entry for every chain in the model
1232 for (int i = 0; i < pdb.chains.size(); i++)
1234 String chid = new String(pdb.id + ":"
1235 + pdb.chains.elementAt(i).id);
1236 chainFile.put(chid, fileName);
1237 chainNames.addElement(chid);
1239 notifyLoaded = true;
1243 if (!foundEntry && associateNewStructs)
1245 // this is a foreign pdb file that jalview doesn't know about - add
1246 // it to the dataset and try to find a home - either on a matching
1247 // sequence or as a new sequence.
1248 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1250 // parse pdb file into a chain, etc.
1251 // locate best match for pdb in associated views and add mapping to
1253 // if properly registered then
1254 notifyLoaded = true;
1259 // so finally, update the jmol bits and pieces
1260 if (jmolpopup != null)
1262 // potential for deadlock here:
1263 // jmolpopup.updateComputedMenus();
1265 if (!isLoadingFromArchive())
1267 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1269 // register ourselves as a listener and notify the gui that it needs to
1271 getSsm().addStructureViewerListener(this);
1274 FeatureRenderer fr = getFeatureRenderer(null);
1280 loadNotifiesHandled++;
1282 setLoadingFromArchive(false);
1285 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1287 notifyAtomPicked(iatom, strMeasure, null);
1290 public abstract void notifyScriptTermination(String strStatus,
1294 * display a message echoed from the jmol viewer
1298 public abstract void sendConsoleEcho(String strEcho); /*
1299 * { showConsole(true);
1301 * history.append("\n" +
1305 // /End JmolStatusListener
1306 // /////////////////////////////
1310 * status message - usually the response received after a script
1313 public abstract void sendConsoleMessage(String strStatus);
1315 public void setCallbackFunction(String callbackType,
1316 String callbackFunction)
1318 System.err.println("Ignoring set-callback request to associate "
1319 + callbackType + " with function " + callbackFunction);
1323 public void setJalviewColourScheme(ColourSchemeI cs)
1325 colourBySequence = false;
1333 StringBuilder command = new StringBuilder(128);
1334 command.append("select *;color white;");
1335 List<String> residueSet = ResidueProperties.getResidues(isNucleotide(),
1337 for (String res : residueSet)
1339 Color col = cs.findColour(res.charAt(0));
1340 command.append("select " + res + ";color[" + col.getRed() + ","
1341 + col.getGreen() + "," + col.getBlue() + "];");
1344 evalStateCommand(command.toString());
1348 public void showHelp()
1350 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1354 * open the URL somehow
1358 public abstract void showUrl(String url, String target);
1361 * called when the binding thinks the UI needs to be refreshed after a Jmol
1362 * state change. this could be because structures were loaded, or because an
1363 * error has occured.
1365 public abstract void refreshGUI();
1368 * called to show or hide the associated console window container.
1372 public abstract void showConsole(boolean show);
1375 * @param renderPanel
1377 * - when true will initialise jmol's file IO system (should be false
1378 * in applet context)
1380 * @param documentBase
1382 * @param commandOptions
1384 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1385 String htmlName, URL documentBase, URL codeBase,
1386 String commandOptions)
1388 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1389 codeBase, commandOptions, null, null);
1394 * @param renderPanel
1396 * - when true will initialise jmol's file IO system (should be false
1397 * in applet context)
1399 * @param documentBase
1401 * @param commandOptions
1402 * @param consolePanel
1403 * - panel to contain Jmol console
1404 * @param buttonsToShow
1405 * - buttons to show on the console, in ordr
1407 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1408 String htmlName, URL documentBase, URL codeBase,
1409 String commandOptions, final Container consolePanel,
1410 String buttonsToShow)
1412 if (commandOptions == null)
1414 commandOptions = "";
1416 viewer = JmolViewer.allocateViewer(renderPanel,
1417 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1418 + ((Object) this).toString(), documentBase, codeBase,
1419 commandOptions, this);
1421 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
1422 if (consolePanel != null)
1424 consolePanel.addComponentListener(this);
1430 protected abstract JmolAppConsoleInterface createJmolConsole(
1431 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
1433 protected org.jmol.api.JmolAppConsoleInterface console = null;
1435 public void setBackgroundColour(java.awt.Color col)
1438 viewer.evalStringQuiet("background [" + col.getRed() + ","
1439 + col.getGreen() + "," + col.getBlue() + "];");
1444 public void resizeInnerPanel(String data)
1446 // Jalview doesn't honour resize panel requests
1450 public boolean isFinishedInit()
1452 return finishedInit;
1455 public void setFinishedInit(boolean finishedInit)
1457 this.finishedInit = finishedInit;
1463 protected void closeConsole()
1465 if (console != null)
1469 console.setVisible(false);
1472 } catch (Exception x)
1481 * ComponentListener method
1484 public void componentMoved(ComponentEvent e)
1489 * ComponentListener method
1492 public void componentResized(ComponentEvent e)
1497 * ComponentListener method
1500 public void componentShown(ComponentEvent e)
1506 * ComponentListener method
1509 public void componentHidden(ComponentEvent e)