2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3 * Copyright (C) 2014 The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
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 jalview.api.AlignmentViewPanel;
24 import jalview.api.FeatureRenderer;
25 import jalview.api.SequenceRenderer;
26 import jalview.datamodel.AlignmentI;
27 import jalview.datamodel.ColumnSelection;
28 import jalview.datamodel.PDBEntry;
29 import jalview.datamodel.SequenceI;
30 import jalview.io.AppletFormatAdapter;
31 import jalview.schemes.ColourSchemeI;
32 import jalview.schemes.ResidueProperties;
33 import jalview.structure.StructureMapping;
34 import jalview.structure.StructureMappingcommandSet;
35 import jalview.structure.StructureSelectionManager;
36 import jalview.structures.models.AAStructureBindingModel;
37 import jalview.util.MessageManager;
39 import java.awt.Color;
40 import java.awt.Container;
41 import java.awt.event.ComponentEvent;
42 import java.awt.event.ComponentListener;
45 import java.security.AccessControlException;
46 import java.util.Hashtable;
48 import java.util.Vector;
50 import org.jmol.adapter.smarter.SmarterJmolAdapter;
51 import org.jmol.api.JmolAppConsoleInterface;
52 import org.jmol.api.JmolSelectionListener;
53 import org.jmol.api.JmolStatusListener;
54 import org.jmol.api.JmolViewer;
55 import org.jmol.constant.EnumCallback;
56 import org.jmol.popup.JmolPopup;
58 public abstract class JalviewJmolBinding extends AAStructureBindingModel
59 implements JmolStatusListener, JmolSelectionListener,
63 * state flag used to check if the Jmol viewer's paint method can be called
65 private boolean finishedInit = false;
67 boolean allChainsSelected = false;
70 * when true, try to search the associated datamodel for sequences that are
71 * associated with any unknown structures in the Jmol view.
73 private boolean associateNewStructs = false;
75 Vector atomsPicked = new Vector();
77 public Vector chainNames;
81 StringBuffer eval = new StringBuffer();
83 public String fileLoadingError;
86 * the default or current model displayed if the model cannot be identified
87 * from the selection message
91 protected JmolPopup jmolpopup;
100 * current set of model filenames loaded in the Jmol instance
102 String[] modelFileNames = null;
104 StringBuffer resetLastRes = new StringBuffer();
106 public JmolViewer viewer;
108 public JalviewJmolBinding(StructureSelectionManager ssm,
109 PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
112 super(ssm, pdbentry, sequenceIs, chains, protocol);
114 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
115 * "jalviewJmol", ap.av.applet .getDocumentBase(),
116 * ap.av.applet.getCodeBase(), "", this);
118 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
122 public JalviewJmolBinding(StructureSelectionManager ssm,
123 SequenceI[][] seqs, JmolViewer theViewer)
128 viewer.setJmolStatusListener(this);
129 viewer.addSelectionListener(this);
133 * construct a title string for the viewer window based on the data jalview
138 public String getViewerTitle()
140 return getViewerTitle("JMol", true);
144 * prepare the view for a given set of models/chains. chainList contains
145 * strings of the form 'pdbfilename:Chaincode'
148 * list of chains to make visible
150 public void centerViewer(Vector chainList)
152 StringBuffer cmd = new StringBuffer();
155 for (int i = 0, iSize = chainList.size(); i < iSize; i++)
158 lbl = (String) chainList.elementAt(i);
162 mlength = lbl.indexOf(":", p);
163 } while (p < mlength && mlength < (lbl.length() - 2));
164 // TODO: lookup each pdb id and recover proper model number for it.
165 cmd.append(":" + lbl.substring(mlength + 1) + " /"
166 + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");
168 if (cmd.length() > 0)
170 cmd.setLength(cmd.length() - 4);
172 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
175 public void closeViewer()
177 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
178 // remove listeners for all structures in viewer
179 getSsm().removeStructureViewerListener(this, this.getPdbFile());
180 // and shut down jmol
181 viewer.evalStringQuiet("zap");
182 viewer.setJmolStatusListener(null);
185 releaseUIResources();
188 public void colourByChain()
190 colourBySequence = false;
191 // TODO: colour by chain should colour each chain distinctly across all
193 // TODO: http://issues.jalview.org/browse/JAL-628
194 evalStateCommand("select *;color chain");
197 public void colourByCharge()
199 colourBySequence = false;
200 evalStateCommand("select *;color white;select ASP,GLU;color red;"
201 + "select LYS,ARG;color blue;select CYS;color yellow");
205 * superpose the structures associated with sequences in the alignment
206 * according to their corresponding positions.
208 public void superposeStructures(AlignmentI alignment)
210 superposeStructures(alignment, -1, null);
214 * superpose the structures associated with sequences in the alignment
215 * according to their corresponding positions. ded)
217 * @param refStructure
218 * - select which pdb file to use as reference (default is -1 - the
219 * first structure in the alignment)
221 public void superposeStructures(AlignmentI alignment, int refStructure)
223 superposeStructures(alignment, refStructure, null);
227 * superpose the structures associated with sequences in the alignment
228 * according to their corresponding positions. ded)
230 * @param refStructure
231 * - select which pdb file to use as reference (default is -1 - the
232 * first structure in the alignment)
236 public void superposeStructures(AlignmentI alignment, int refStructure,
237 ColumnSelection hiddenCols)
239 superposeStructures(new AlignmentI[]
240 { alignment }, new int[]
241 { refStructure }, new ColumnSelection[]
245 public void superposeStructures(AlignmentI[] _alignment,
246 int[] _refStructure, ColumnSelection[] _hiddenCols)
248 assert (_alignment.length == _refStructure.length && _alignment.length != _hiddenCols.length);
250 String[] files = getPdbFile();
251 // check to see if we are still waiting for Jmol files
252 long starttime = System.currentTimeMillis();
253 boolean waiting = true;
257 for (String file : files)
261 // HACK - in Jalview 2.8 this call may not be threadsafe so we catch
262 // every possible exception
263 StructureMapping[] sm = getSsm().getMapping(file);
264 if (sm == null || sm.length == 0)
268 } catch (Exception x)
276 // we wait around for a reasonable time before we give up
278 && System.currentTimeMillis() < (10000 + 1000 * files.length + starttime));
282 .println("RUNTIME PROBLEM: Jmol seems to be taking a long time to process all the structures.");
285 StringBuffer selectioncom = new StringBuffer();
286 // In principle - nSeconds specifies the speed of animation for each
287 // superposition - but is seems to behave weirdly, so we don't specify it.
288 String nSeconds = " ";
289 if (files.length > 10)
291 nSeconds = " 0.00001 ";
295 nSeconds = " " + (2.0 / files.length) + " ";
296 // if (nSeconds).substring(0,5)+" ";
298 // see JAL-1345 - should really automatically turn off the animation for
299 // large numbers of structures, but Jmol doesn't seem to allow that.
301 // union of all aligned positions are collected together.
302 for (int a = 0; a < _alignment.length; a++)
304 int refStructure = _refStructure[a];
305 AlignmentI alignment = _alignment[a];
306 ColumnSelection hiddenCols = _hiddenCols[a];
308 && selectioncom.length() > 0
309 && !selectioncom.substring(selectioncom.length() - 1).equals(
312 selectioncom.append("|");
314 // process this alignment
315 if (refStructure >= files.length)
317 System.err.println("Invalid reference structure value "
321 if (refStructure < -1)
325 StringBuffer command = new StringBuffer();
327 boolean matched[] = new boolean[alignment.getWidth()];
328 for (int m = 0; m < matched.length; m++)
331 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
334 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
335 String isel[] = new String[files.length];
336 // reference structure - all others are superposed in it
337 String[] targetC = new String[files.length];
338 String[] chainNames = new String[files.length];
339 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
341 StructureMapping[] mapping = getSsm().getMapping(files[pdbfnum]);
342 // RACE CONDITION - getMapping only returns Jmol loaded filenames once
343 // Jmol callback has completed.
344 if (mapping == null || mapping.length < 1)
346 throw new Error(MessageManager.getString("error.implementation_error_jmol_getting_data"));
349 final int sequenceCountForPdbFile = getSequence()[pdbfnum].length;
350 for (int s = 0; s < sequenceCountForPdbFile; s++)
352 for (int sp, m = 0; m < mapping.length; m++)
354 if (mapping[m].getSequence() == getSequence()[pdbfnum][s]
355 && (sp = alignment.findIndex(getSequence()[pdbfnum][s])) > -1)
357 if (refStructure == -1)
359 refStructure = pdbfnum;
361 SequenceI asp = alignment.getSequenceAt(sp);
362 for (int r = 0; r < matched.length; r++)
368 matched[r] = false; // assume this is not a good site
369 if (r >= asp.getLength())
374 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
376 // no mapping to gaps in sequence
379 int t = asp.findPosition(r); // sequence position
380 int apos = mapping[m].getAtomNum(t);
381 int pos = mapping[m].getPDBResNum(t);
383 if (pos < 1 || pos == lastPos)
385 // can't align unmapped sequence
388 matched[r] = true; // this is a good ite
390 // just record this residue position
391 commonrpositions[pdbfnum][r] = pos;
393 // create model selection suffix
394 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
395 if (mapping[m].getChain() == null
396 || mapping[m].getChain().trim().length() == 0)
398 targetC[pdbfnum] = "";
402 targetC[pdbfnum] = ":" + mapping[m].getChain();
404 chainNames[pdbfnum] = mapping[m].getPdbId()
406 // move on to next pdb file
407 s = getSequence()[pdbfnum].length;
414 // TODO: consider bailing if nmatched less than 4 because superposition
417 // TODO: refactor superposable position search (above) from jmol selection
418 // construction (below)
420 String[] selcom = new String[files.length];
422 // generate select statements to select regions to superimpose structures
424 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
426 String chainCd = targetC[pdbfnum];
429 StringBuffer molsel = new StringBuffer();
431 for (int r = 0; r < matched.length; r++)
439 if (lpos != commonrpositions[pdbfnum][r] - 1)
445 molsel.append(chainCd);
446 // molsel.append("} {");
452 // continuous run - and lpos >-1
455 // at the beginning, so add dash
461 lpos = commonrpositions[pdbfnum][r];
462 // molsel.append(lpos);
465 // add final selection phrase
469 molsel.append(chainCd);
472 if (molsel.length() > 1)
474 selcom[pdbfnum] = molsel.toString();
475 selectioncom.append("((");
476 selectioncom.append(selcom[pdbfnum].substring(1,
477 selcom[pdbfnum].length() - 1));
478 selectioncom.append(" )& ");
479 selectioncom.append(pdbfnum + 1);
480 selectioncom.append(".1)");
481 if (pdbfnum < files.length - 1)
483 selectioncom.append("|");
488 selcom[pdbfnum] = null;
492 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
494 if (pdbfnum == refStructure || selcom[pdbfnum] == null
495 || selcom[refStructure] == null)
499 command.append("echo ");
500 command.append("\"Superposing (");
501 command.append(chainNames[pdbfnum]);
502 command.append(") against reference (");
503 command.append(chainNames[refStructure]);
504 command.append(")\";\ncompare " + nSeconds);
506 command.append(1 + pdbfnum);
507 command.append(".1} {");
508 command.append(1 + refStructure);
509 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
511 // form the matched pair strings
513 for (int s = 0; s < 2; s++)
515 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
517 command.append(" ROTATE TRANSLATE;\n");
519 if (selectioncom.length() > 0)
521 System.out.println("Select regions:\n" + selectioncom.toString());
522 evalStateCommand("select *; cartoons off; backbone; select ("
523 + selectioncom.toString() + "); cartoons; ");
524 // selcom.append("; ribbons; ");
526 .println("Superimpose command(s):\n" + command.toString());
528 evalStateCommand(command.toString());
531 if (selectioncom.length() > 0)
532 {// finally, mark all regions that were superposed.
533 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
535 selectioncom.setLength(selectioncom.length() - 1);
537 System.out.println("Select regions:\n" + selectioncom.toString());
538 evalStateCommand("select *; cartoons off; backbone; select ("
539 + selectioncom.toString() + "); cartoons; ");
540 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
544 public void evalStateCommand(String command)
547 if (lastCommand == null || !lastCommand.equals(command))
549 viewer.evalStringQuiet(command + "\n");
552 lastCommand = command;
556 * colour any structures associated with sequences in the given alignment
557 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
558 * if colourBySequence is enabled.
560 public void colourBySequence(boolean showFeatures,
561 jalview.api.AlignmentViewPanel alignmentv)
563 if (!colourBySequence || !isLoadingFinished())
567 if (getSsm() == null)
571 String[] files = getPdbFile();
573 SequenceRenderer sr = getSequenceRenderer(alignmentv);
575 FeatureRenderer fr = null;
578 fr = getFeatureRenderer(alignmentv);
580 AlignmentI alignment = alignmentv.getAlignment();
582 for (jalview.structure.StructureMappingcommandSet cpdbbyseq : getColourBySequenceCommands(files, sr, fr, alignment))
584 for (String cbyseq : cpdbbyseq.commands)
586 executeWhenReady(cbyseq);
598 protected StructureMappingcommandSet[] getColourBySequenceCommands(
599 String[] files, SequenceRenderer sr, FeatureRenderer fr,
600 AlignmentI alignment)
603 .getColourBySequenceCommand(getSsm(), files, getSequence(), sr,
611 protected void executeWhenReady(String command)
613 evalStateCommand(command);
616 public void createImage(String file, String type, int quality)
618 System.out.println("JMOL CREATE IMAGE");
621 public String createImage(String fileName, String type,
622 Object textOrBytes, int quality)
624 System.out.println("JMOL CREATE IMAGE");
628 public String eval(String strEval)
630 // System.out.println(strEval);
631 // "# 'eval' is implemented only for the applet.";
635 // End StructureListener
636 // //////////////////////////
638 public float[][] functionXY(String functionName, int x, int y)
643 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
645 // TODO Auto-generated method stub
649 public Color getColour(int atomIndex, int pdbResNum, String chain,
652 if (getModelNum(pdbfile) < 0)
656 // TODO: verify atomIndex is selecting correct model.
657 return new Color(viewer.getAtomArgb(atomIndex));
661 * returns the current featureRenderer that should be used to colour the
668 public abstract FeatureRenderer getFeatureRenderer(
669 AlignmentViewPanel alignment);
672 * instruct the Jalview binding to update the pdbentries vector if necessary
673 * prior to matching the jmol view's contents to the list of structure files
674 * Jalview knows about.
676 public abstract void refreshPdbEntries();
678 private int getModelNum(String modelFileName)
680 String[] mfn = getPdbFile();
685 for (int i = 0; i < mfn.length; i++)
687 if (mfn[i].equalsIgnoreCase(modelFileName))
696 * map between index of model filename returned from getPdbFile and the first
697 * index of models from this file in the viewer. Note - this is not trimmed -
698 * use getPdbFile to get number of unique models.
700 private int _modelFileNameMap[];
702 // ////////////////////////////////
703 // /StructureListener
704 public synchronized String[] getPdbFile()
708 return new String[0];
710 if (modelFileNames == null)
713 String mset[] = new String[viewer.getModelCount()];
714 _modelFileNameMap = new int[mset.length];
716 String m = viewer.getModelFileName(0);
721 mset[0] = new File(m).getAbsolutePath();
722 } catch (AccessControlException x)
724 // usually not allowed to do this in applet, so keep raw handle
726 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
729 for (int i = 1; i < mset.length; i++)
731 m = viewer.getModelFileName(i);
736 mset[j] = new File(m).getAbsolutePath();
737 } catch (AccessControlException x)
739 // usually not allowed to do this in applet, so keep raw handle
741 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
744 _modelFileNameMap[j] = i; // record the model index for the filename
745 // skip any additional models in the same file (NMR structures)
746 if ((mset[j] == null ? mset[j] != mset[j - 1]
747 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
752 modelFileNames = new String[j];
753 System.arraycopy(mset, 0, modelFileNames, 0, j);
755 return modelFileNames;
759 * map from string to applet
762 public Map<String, Object> getRegistryInfo()
764 // TODO Auto-generated method stub
769 * returns the current sequenceRenderer that should be used to colour the
776 public abstract SequenceRenderer getSequenceRenderer(
777 AlignmentViewPanel alignment);
779 // ///////////////////////////////
780 // JmolStatusListener
782 public void handlePopupMenu(int x, int y)
784 jmolpopup.show(x, y);
788 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
791 if (modelFileNames == null)
796 // look up file model number for this pdbfile
799 // may need to adjust for URLencoding here - we don't worry about that yet.
800 while (mdlNum < modelFileNames.length
801 && !pdbfile.equals(modelFileNames[mdlNum]))
803 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
806 if (mdlNum == modelFileNames.length)
812 // if (!pdbfile.equals(pdbentry.getFile()))
814 if (resetLastRes.length() > 0)
816 viewer.evalStringQuiet(resetLastRes.toString());
820 eval.append("select " + pdbResNum); // +modelNum
822 resetLastRes.setLength(0);
823 resetLastRes.append("select " + pdbResNum); // +modelNum
826 resetLastRes.append(":");
827 if (!chain.equals(" "))
830 resetLastRes.append(chain);
833 eval.append(" /" + (mdlNum + 1));
834 resetLastRes.append("/" + (mdlNum + 1));
836 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
838 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
839 + " and not hetero; spacefill 0;");
841 eval.append("spacefill 200;select none");
843 viewer.evalStringQuiet(eval.toString());
848 boolean debug = true;
850 private void jmolHistory(boolean enable)
852 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
855 public void loadInline(String string)
859 // viewer.loadInline(strModel, isAppend);
861 // construct fake fullPathName and fileName so we can identify the file
863 // Then, construct pass a reader for the string to Jmol.
864 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
865 // fileName, null, reader, false, null, null, 0);
866 viewer.openStringInline(string);
869 public void mouseOverStructure(int atomIndex, String strInfo)
872 int alocsep = strInfo.indexOf("^");
873 int mdlSep = strInfo.indexOf("/");
874 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
876 if (chainSeparator == -1)
878 chainSeparator = strInfo.indexOf(".");
879 if (mdlSep > -1 && mdlSep < chainSeparator)
881 chainSeparator1 = chainSeparator;
882 chainSeparator = mdlSep;
885 // handle insertion codes
888 pdbResNum = Integer.parseInt(strInfo.substring(
889 strInfo.indexOf("]") + 1, alocsep));
894 pdbResNum = Integer.parseInt(strInfo.substring(
895 strInfo.indexOf("]") + 1, chainSeparator));
899 if (strInfo.indexOf(":") > -1)
901 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
902 strInfo.indexOf("."));
909 String pdbfilename = modelFileNames[frameNo]; // default is first or current
913 if (chainSeparator1 == -1)
915 chainSeparator1 = strInfo.indexOf(".", mdlSep);
917 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
918 chainSeparator1) : strInfo.substring(mdlSep + 1);
921 // recover PDB filename for the model hovered over.
922 int _mp = _modelFileNameMap.length - 1, mnumber = new Integer(mdlId)
924 while (mnumber < _modelFileNameMap[_mp])
928 pdbfilename = modelFileNames[_mp];
929 if (pdbfilename == null)
931 pdbfilename = new File(viewer.getModelFileName(mnumber))
935 } catch (Exception e)
940 if (lastMessage == null || !lastMessage.equals(strInfo))
942 getSsm().mouseOverStructure(pdbResNum, chainId, pdbfilename);
945 lastMessage = strInfo;
948 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
952 System.err.println("Ignoring additional hover info: " + data
953 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
955 mouseOverStructure(atomIndex, strInfo);
959 * { if (history != null && strStatus != null &&
960 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
964 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
967 * this implements the toggle label behaviour copied from the original
968 * structure viewer, MCView
972 System.err.println("Ignoring additional pick data string " + strData);
974 int chainSeparator = strInfo.indexOf(":");
976 if (chainSeparator == -1)
978 chainSeparator = strInfo.indexOf(".");
981 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
983 String mdlString = "";
984 if ((p = strInfo.indexOf(":")) > -1)
986 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
989 if ((p = strInfo.indexOf("/")) > -1)
991 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
993 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
997 if (!atomsPicked.contains(picked))
999 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
1000 atomsPicked.addElement(picked);
1004 viewer.evalString("select " + picked + ";label off");
1005 atomsPicked.removeElement(picked);
1008 // TODO: in application this happens
1010 // if (scriptWindow != null)
1012 // scriptWindow.sendConsoleMessage(strInfo);
1013 // scriptWindow.sendConsoleMessage("\n");
1019 public void notifyCallback(EnumCallback type, Object[] data)
1026 notifyFileLoaded((String) data[1], (String) data[2],
1027 (String) data[3], (String) data[4],
1028 ((Integer) data[5]).intValue());
1032 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
1034 // also highlight in alignment
1036 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1040 notifyScriptTermination((String) data[2],
1041 ((Integer) data[3]).intValue());
1044 sendConsoleEcho((String) data[1]);
1047 sendConsoleMessage((data == null) ? ((String) null)
1048 : (String) data[1]);
1051 // System.err.println("Ignoring error callback.");
1061 System.err.println("Unhandled callback " + type + " "
1062 + data[1].toString());
1065 } catch (Exception e)
1067 System.err.println("Squashed Jmol callback handler error:");
1068 e.printStackTrace();
1073 public boolean notifyEnabled(EnumCallback callbackPick)
1075 switch (callbackPick)
1095 // incremented every time a load notification is successfully handled -
1096 // lightweight mechanism for other threads to detect when they can start
1097 // referrring to new structures.
1098 private long loadNotifiesHandled = 0;
1100 public long getLoadNotifiesHandled()
1102 return loadNotifiesHandled;
1105 public void notifyFileLoaded(String fullPathName, String fileName2,
1106 String modelName, String errorMsg, int modelParts)
1108 if (errorMsg != null)
1110 fileLoadingError = errorMsg;
1114 // TODO: deal sensibly with models loaded inLine:
1115 // modelName will be null, as will fullPathName.
1117 // the rest of this routine ignores the arguments, and simply interrogates
1118 // the Jmol view to find out what structures it contains, and adds them to
1119 // the structure selection manager.
1120 fileLoadingError = null;
1121 String[] oldmodels = modelFileNames;
1122 modelFileNames = null;
1123 chainNames = new Vector();
1124 chainFile = new Hashtable();
1125 boolean notifyLoaded = false;
1126 String[] modelfilenames = getPdbFile();
1127 // first check if we've lost any structures
1128 if (oldmodels != null && oldmodels.length > 0)
1131 for (int i = 0; i < oldmodels.length; i++)
1133 for (int n = 0; n < modelfilenames.length; n++)
1135 if (modelfilenames[n] == oldmodels[i])
1137 oldmodels[i] = null;
1141 if (oldmodels[i] != null)
1148 String[] oldmfn = new String[oldm];
1150 for (int i = 0; i < oldmodels.length; i++)
1152 if (oldmodels[i] != null)
1154 oldmfn[oldm++] = oldmodels[i];
1157 // deregister the Jmol instance for these structures - we'll add
1158 // ourselves again at the end for the current structure set.
1159 getSsm().removeStructureViewerListener(this, oldmfn);
1162 refreshPdbEntries();
1163 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1165 String fileName = modelfilenames[modelnum];
1166 boolean foundEntry = false;
1167 MCview.PDBfile pdb = null;
1168 String pdbfile = null, pdbfhash = null;
1169 // model was probably loaded inline - so check the pdb file hashcode
1172 // calculate essential attributes for the pdb data imported inline.
1173 // prolly need to resolve modelnumber properly - for now just use our
1175 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1177 pdbfhash = "" + pdbfile.hashCode();
1179 // search pdbentries and sequences to find correct pdbentry for this
1181 for (int pe = 0; pe < getPdbCount(); pe++)
1183 boolean matches = false;
1184 if (fileName == null)
1187 // see JAL-623 - need method of matching pasted data up
1189 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1190 pdbfile, AppletFormatAdapter.PASTE);
1191 getPdbEntry(modelnum).setFile("INLINE" + pdb.id);
1199 if (matches = (fl = new File(getPdbEntry(pe).getFile()))
1200 .equals(new File(fileName)))
1203 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1206 // to be tested. See mantis bug
1207 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1208 String protocol = AppletFormatAdapter.URL;
1213 protocol = AppletFormatAdapter.FILE;
1215 } catch (Exception e)
1220 // Explicitly map to the filename used by Jmol ;
1221 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
1222 fileName, protocol);
1223 // pdbentry[pe].getFile(), protocol);
1229 // add an entry for every chain in the model
1230 for (int i = 0; i < pdb.chains.size(); i++)
1232 String chid = new String(pdb.id + ":"
1233 + pdb.chains.elementAt(i).id);
1234 chainFile.put(chid, fileName);
1235 chainNames.addElement(chid);
1237 notifyLoaded = true;
1241 if (!foundEntry && associateNewStructs)
1243 // this is a foreign pdb file that jalview doesn't know about - add
1244 // it to the dataset and try to find a home - either on a matching
1245 // sequence or as a new sequence.
1246 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1248 // parse pdb file into a chain, etc.
1249 // locate best match for pdb in associated views and add mapping to
1251 // if properly registered then
1252 notifyLoaded = true;
1257 // so finally, update the jmol bits and pieces
1258 if (jmolpopup != null)
1260 // potential for deadlock here:
1261 // jmolpopup.updateComputedMenus();
1263 if (!isLoadingFromArchive())
1265 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1267 // register ourselves as a listener and notify the gui that it needs to
1269 getSsm().addStructureViewerListener(this);
1272 FeatureRenderer fr = getFeatureRenderer(null);
1278 loadNotifiesHandled++;
1280 setLoadingFromArchive(false);
1283 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1285 notifyAtomPicked(iatom, strMeasure, null);
1288 public abstract void notifyScriptTermination(String strStatus,
1292 * display a message echoed from the jmol viewer
1296 public abstract void sendConsoleEcho(String strEcho); /*
1297 * { showConsole(true);
1299 * history.append("\n" +
1303 // /End JmolStatusListener
1304 // /////////////////////////////
1308 * status message - usually the response received after a script
1311 public abstract void sendConsoleMessage(String strStatus);
1313 public void setCallbackFunction(String callbackType,
1314 String callbackFunction)
1316 System.err.println("Ignoring set-callback request to associate "
1317 + callbackType + " with function " + callbackFunction);
1321 public void setJalviewColourScheme(ColourSchemeI cs)
1323 colourBySequence = false;
1333 // TODO: Switch between nucleotide or aa selection expressions
1334 StringBuilder command = new StringBuilder(128);
1335 command.append("select *;color white;");
1336 for (String res : ResidueProperties.aa3Hash.keySet())
1338 index = ResidueProperties.aa3Hash.get(res).intValue();
1344 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
1346 command.append("select " + res + ";color[" + col.getRed() + ","
1347 + col.getGreen() + "," + col.getBlue() + "];");
1350 evalStateCommand(command.toString());
1354 public void showHelp()
1356 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1360 * open the URL somehow
1364 public abstract void showUrl(String url, String target);
1367 * called when the binding thinks the UI needs to be refreshed after a Jmol
1368 * state change. this could be because structures were loaded, or because an
1369 * error has occured.
1371 public abstract void refreshGUI();
1374 * called to show or hide the associated console window container.
1378 public abstract void showConsole(boolean show);
1381 * @param renderPanel
1383 * - when true will initialise jmol's file IO system (should be false
1384 * in applet context)
1386 * @param documentBase
1388 * @param commandOptions
1390 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1391 String htmlName, URL documentBase, URL codeBase,
1392 String commandOptions)
1394 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1395 codeBase, commandOptions, null, null);
1400 * @param renderPanel
1402 * - when true will initialise jmol's file IO system (should be false
1403 * in applet context)
1405 * @param documentBase
1407 * @param commandOptions
1408 * @param consolePanel
1409 * - panel to contain Jmol console
1410 * @param buttonsToShow
1411 * - buttons to show on the console, in ordr
1413 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1414 String htmlName, URL documentBase, URL codeBase,
1415 String commandOptions, final Container consolePanel,
1416 String buttonsToShow)
1418 if (commandOptions == null)
1420 commandOptions = "";
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 setBackgroundColour(java.awt.Color col)
1444 viewer.evalStringQuiet("background [" + col.getRed() + ","
1445 + col.getGreen() + "," + col.getBlue() + "];");
1452 * @return text report of alignment between pdbfile and any associated
1453 * alignment sequences
1455 public String printMapping(String pdbfile)
1457 return getSsm().printMapping(pdbfile);
1461 public void resizeInnerPanel(String data)
1463 // Jalview doesn't honour resize panel requests
1467 public boolean isFinishedInit()
1469 return finishedInit;
1472 public void setFinishedInit(boolean finishedInit)
1474 this.finishedInit = finishedInit;
1480 protected void closeConsole()
1482 if (console != null)
1486 console.setVisible(false);
1489 } catch (Exception x)
1498 * ComponentListener method
1501 public void componentMoved(ComponentEvent e)
1506 * ComponentListener method
1509 public void componentResized(ComponentEvent e)
1514 * ComponentListener method
1517 public void componentShown(ComponentEvent e)
1523 * ComponentListener method
1526 public void componentHidden(ComponentEvent e)