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.api.SequenceStructureBinding;
27 import jalview.api.StructureSelectionManagerProvider;
28 import jalview.datamodel.AlignmentI;
29 import jalview.datamodel.ColumnSelection;
30 import jalview.datamodel.PDBEntry;
31 import jalview.datamodel.SequenceI;
32 import jalview.io.AppletFormatAdapter;
33 import jalview.schemes.ColourSchemeI;
34 import jalview.schemes.ResidueProperties;
35 import jalview.structure.StructureListener;
36 import jalview.structure.StructureMapping;
37 import jalview.structure.StructureSelectionManager;
38 import jalview.structures.models.SequenceStructureBindingModel;
39 import jalview.util.MessageManager;
41 import java.awt.Color;
42 import java.awt.Container;
43 import java.awt.event.ComponentEvent;
44 import java.awt.event.ComponentListener;
47 import java.security.AccessControlException;
48 import java.util.Enumeration;
49 import java.util.Hashtable;
51 import java.util.Vector;
53 import org.jmol.adapter.smarter.SmarterJmolAdapter;
54 import org.jmol.api.JmolAppConsoleInterface;
55 import org.jmol.api.JmolSelectionListener;
56 import org.jmol.api.JmolStatusListener;
57 import org.jmol.api.JmolViewer;
58 import org.jmol.constant.EnumCallback;
59 import org.jmol.popup.JmolPopup;
61 public abstract class JalviewJmolBinding extends SequenceStructureBindingModel implements StructureListener,
62 JmolStatusListener, SequenceStructureBinding,
63 JmolSelectionListener, ComponentListener,
64 StructureSelectionManagerProvider
68 * state flag used to check if the Jmol viewer's paint method can be called
70 private boolean finishedInit = false;
72 public boolean isFinishedInit()
77 public void setFinishedInit(boolean finishedInit)
79 this.finishedInit = finishedInit;
82 boolean allChainsSelected = false;
85 * when true, try to search the associated datamodel for sequences that are
86 * associated with any unknown structures in the Jmol view.
88 private boolean associateNewStructs = false;
90 Vector atomsPicked = new Vector();
92 public Vector chainNames;
97 * array of target chains for seuqences - tied to pdbentry and sequence[]
99 protected String[][] chains;
101 boolean colourBySequence = true;
103 StringBuffer eval = new StringBuffer();
105 public String fileLoadingError;
108 * the default or current model displayed if the model cannot be identified
109 * from the selection message
113 protected JmolPopup jmolpopup;
119 boolean loadedInline;
122 * current set of model filenames loaded in the Jmol instance
124 String[] modelFileNames = null;
126 public PDBEntry[] pdbentry;
129 * datasource protocol for access to PDBEntrylatest
131 String protocol = null;
133 StringBuffer resetLastRes = new StringBuffer();
136 * sequences mapped to each pdbentry
138 public SequenceI[][] sequence;
140 public StructureSelectionManager ssm;
142 public JmolViewer viewer;
144 public JalviewJmolBinding(StructureSelectionManager ssm,
145 PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
149 this.sequence = sequenceIs;
150 this.chains = chains;
151 this.pdbentry = pdbentry;
152 this.protocol = protocol;
155 this.chains = new String[pdbentry.length][];
158 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
159 * "jalviewJmol", ap.av.applet .getDocumentBase(),
160 * ap.av.applet.getCodeBase(), "", this);
162 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
166 public JalviewJmolBinding(StructureSelectionManager ssm,
171 viewer.setJmolStatusListener(this);
172 viewer.addSelectionListener(this);
176 * construct a title string for the viewer window based on the data jalview
181 public String getViewerTitle()
183 if (sequence == null || pdbentry == null || sequence.length < 1
184 || pdbentry.length < 1 || sequence[0].length < 1)
186 return ("Jalview Jmol Window");
188 // TODO: give a more informative title when multiple structures are
190 StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
191 + pdbentry[0].getId());
193 if (pdbentry[0].getProperty() != null)
195 if (pdbentry[0].getProperty().get("method") != null)
197 title.append(" Method: ");
198 title.append(pdbentry[0].getProperty().get("method"));
200 if (pdbentry[0].getProperty().get("chains") != null)
202 title.append(" Chain:");
203 title.append(pdbentry[0].getProperty().get("chains"));
206 return title.toString();
210 * prepare the view for a given set of models/chains. chainList contains
211 * strings of the form 'pdbfilename:Chaincode'
214 * list of chains to make visible
216 public void centerViewer(Vector chainList)
218 StringBuffer cmd = new StringBuffer();
221 for (int i = 0, iSize = chainList.size(); i < iSize; i++)
224 lbl = (String) chainList.elementAt(i);
228 mlength = lbl.indexOf(":", p);
229 } while (p < mlength && mlength < (lbl.length() - 2));
230 // TODO: lookup each pdb id and recover proper model number for it.
231 cmd.append(":" + lbl.substring(mlength + 1) + " /"
232 + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");
234 if (cmd.length() > 0)
235 cmd.setLength(cmd.length() - 4);
236 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
239 public void closeViewer()
241 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
242 // remove listeners for all structures in viewer
243 ssm.removeStructureViewerListener(this, this.getPdbFile());
244 // and shut down jmol
245 viewer.evalStringQuiet("zap");
246 viewer.setJmolStatusListener(null);
249 releaseUIResources();
253 * called by JalviewJmolbinding after closeViewer is called - release any
254 * resources and references so they can be garbage collected.
256 protected abstract void releaseUIResources();
258 public void colourByChain()
260 colourBySequence = false;
261 // TODO: colour by chain should colour each chain distinctly across all
263 // TODO: http://issues.jalview.org/browse/JAL-628
264 evalStateCommand("select *;color chain");
267 public void colourByCharge()
269 colourBySequence = false;
270 evalStateCommand("select *;color white;select ASP,GLU;color red;"
271 + "select LYS,ARG;color blue;select CYS;color yellow");
275 * superpose the structures associated with sequences in the alignment
276 * according to their corresponding positions.
278 public void superposeStructures(AlignmentI alignment)
280 superposeStructures(alignment, -1, null);
284 * superpose the structures associated with sequences in the alignment
285 * according to their corresponding positions. ded)
287 * @param refStructure
288 * - select which pdb file to use as reference (default is -1 - the
289 * first structure in the alignment)
291 public void superposeStructures(AlignmentI alignment, int refStructure)
293 superposeStructures(alignment, refStructure, null);
297 * superpose the structures associated with sequences in the alignment
298 * according to their corresponding positions. ded)
300 * @param refStructure
301 * - select which pdb file to use as reference (default is -1 - the
302 * first structure in the alignment)
306 public void superposeStructures(AlignmentI alignment, int refStructure,
307 ColumnSelection hiddenCols)
309 superposeStructures(new AlignmentI[]
310 { alignment }, new int[]
311 { refStructure }, new ColumnSelection[]
315 public void superposeStructures(AlignmentI[] _alignment,
316 int[] _refStructure, ColumnSelection[] _hiddenCols)
318 assert (_alignment.length == _refStructure.length && _alignment.length != _hiddenCols.length);
320 String[] files = getPdbFile();
321 // check to see if we are still waiting for Jmol files
322 long starttime = System.currentTimeMillis();
323 boolean waiting = true;
327 for (String file : files)
331 // HACK - in Jalview 2.8 this call may not be threadsafe so we catch
332 // every possible exception
333 StructureMapping[] sm = ssm.getMapping(file);
334 if (sm == null || sm.length == 0)
338 } catch (Exception x)
346 // we wait around for a reasonable time before we give up
348 && System.currentTimeMillis() < (10000 + 1000 * files.length + starttime));
352 .println("RUNTIME PROBLEM: Jmol seems to be taking a long time to process all the structures.");
355 StringBuffer selectioncom = new StringBuffer();
356 // In principle - nSeconds specifies the speed of animation for each
357 // superposition - but is seems to behave weirdly, so we don't specify it.
358 String nSeconds = " ";
359 if (files.length > 10)
361 nSeconds = " 0.00001 ";
365 nSeconds = " " + (2.0 / files.length) + " ";
366 // if (nSeconds).substring(0,5)+" ";
368 // see JAL-1345 - should really automatically turn off the animation for
369 // large numbers of structures, but Jmol doesn't seem to allow that.
371 // union of all aligned positions are collected together.
372 for (int a = 0; a < _alignment.length; a++)
374 int refStructure = _refStructure[a];
375 AlignmentI alignment = _alignment[a];
376 ColumnSelection hiddenCols = _hiddenCols[a];
378 && selectioncom.length() > 0
379 && !selectioncom.substring(selectioncom.length() - 1).equals(
382 selectioncom.append("|");
384 // process this alignment
385 if (refStructure >= files.length)
387 System.err.println("Invalid reference structure value "
391 if (refStructure < -1)
395 StringBuffer command = new StringBuffer();
397 boolean matched[] = new boolean[alignment.getWidth()];
398 for (int m = 0; m < matched.length; m++)
401 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
404 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
405 String isel[] = new String[files.length];
406 // reference structure - all others are superposed in it
407 String[] targetC = new String[files.length];
408 String[] chainNames = new String[files.length];
409 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
411 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
412 // RACE CONDITION - getMapping only returns Jmol loaded filenames once
413 // Jmol callback has completed.
414 if (mapping == null || mapping.length < 1)
416 throw new Error(MessageManager.getString("error.implementation_error_jmol_getting_data"));
419 for (int s = 0; s < sequence[pdbfnum].length; s++)
421 for (int sp, m = 0; m < mapping.length; m++)
423 if (mapping[m].getSequence() == sequence[pdbfnum][s]
424 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
426 if (refStructure == -1)
428 refStructure = pdbfnum;
430 SequenceI asp = alignment.getSequenceAt(sp);
431 for (int r = 0; r < matched.length; r++)
437 matched[r] = false; // assume this is not a good site
438 if (r >= asp.getLength())
443 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
445 // no mapping to gaps in sequence
448 int t = asp.findPosition(r); // sequence position
449 int apos = mapping[m].getAtomNum(t);
450 int pos = mapping[m].getPDBResNum(t);
452 if (pos < 1 || pos == lastPos)
454 // can't align unmapped sequence
457 matched[r] = true; // this is a good ite
459 // just record this residue position
460 commonrpositions[pdbfnum][r] = pos;
462 // create model selection suffix
463 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
464 if (mapping[m].getChain() == null
465 || mapping[m].getChain().trim().length() == 0)
467 targetC[pdbfnum] = "";
471 targetC[pdbfnum] = ":" + mapping[m].getChain();
473 chainNames[pdbfnum] = mapping[m].getPdbId()
475 // move on to next pdb file
476 s = sequence[pdbfnum].length;
483 // TODO: consider bailing if nmatched less than 4 because superposition
486 // TODO: refactor superposable position search (above) from jmol selection
487 // construction (below)
489 String[] selcom = new String[files.length];
491 // generate select statements to select regions to superimpose structures
493 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
495 String chainCd = targetC[pdbfnum];
498 StringBuffer molsel = new StringBuffer();
500 for (int r = 0; r < matched.length; r++)
508 if (lpos != commonrpositions[pdbfnum][r] - 1)
514 molsel.append(chainCd);
515 // molsel.append("} {");
521 // continuous run - and lpos >-1
524 // at the beginning, so add dash
530 lpos = commonrpositions[pdbfnum][r];
531 // molsel.append(lpos);
534 // add final selection phrase
538 molsel.append(chainCd);
541 if (molsel.length() > 1)
543 selcom[pdbfnum] = molsel.toString();
544 selectioncom.append("((");
545 selectioncom.append(selcom[pdbfnum].substring(1,
546 selcom[pdbfnum].length() - 1));
547 selectioncom.append(" )& ");
548 selectioncom.append(pdbfnum + 1);
549 selectioncom.append(".1)");
550 if (pdbfnum < files.length - 1)
552 selectioncom.append("|");
557 selcom[pdbfnum] = null;
561 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
563 if (pdbfnum == refStructure || selcom[pdbfnum] == null
564 || selcom[refStructure] == null)
568 command.append("echo ");
569 command.append("\"Superposing (");
570 command.append(chainNames[pdbfnum]);
571 command.append(") against reference (");
572 command.append(chainNames[refStructure]);
573 command.append(")\";\ncompare " + nSeconds);
575 command.append(1 + pdbfnum);
576 command.append(".1} {");
577 command.append(1 + refStructure);
578 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
580 // form the matched pair strings
582 for (int s = 0; s < 2; s++)
584 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
586 command.append(" ROTATE TRANSLATE;\n");
588 if (selectioncom.length() > 0)
590 System.out.println("Select regions:\n" + selectioncom.toString());
591 evalStateCommand("select *; cartoons off; backbone; select ("
592 + selectioncom.toString() + "); cartoons; ");
593 // selcom.append("; ribbons; ");
595 .println("Superimpose command(s):\n" + command.toString());
597 evalStateCommand(command.toString());
600 if (selectioncom.length() > 0)
601 {// finally, mark all regions that were superposed.
602 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
604 selectioncom.setLength(selectioncom.length() - 1);
606 System.out.println("Select regions:\n" + selectioncom.toString());
607 evalStateCommand("select *; cartoons off; backbone; select ("
608 + selectioncom.toString() + "); cartoons; ");
609 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
613 public void evalStateCommand(String command)
616 if (lastCommand == null || !lastCommand.equals(command))
618 viewer.evalStringQuiet(command + "\n");
621 lastCommand = command;
625 * colour any structures associated with sequences in the given alignment
626 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
627 * if colourBySequence is enabled.
629 public void colourBySequence(boolean showFeatures,
630 jalview.api.AlignmentViewPanel alignmentv)
632 if (!colourBySequence || !isLoadingFinished())
638 String[] files = getPdbFile();
640 SequenceRenderer sr = getSequenceRenderer(alignmentv);
642 FeatureRenderer fr = null;
645 fr = getFeatureRenderer(alignmentv);
647 AlignmentI alignment = alignmentv.getAlignment();
649 for (jalview.structure.StructureMappingcommandSet cpdbbyseq : JmolCommands
650 .getColourBySequenceCommand(ssm, files, sequence, sr, fr,
652 for (String cbyseq : cpdbbyseq.commands)
654 evalStateCommand(cbyseq);
658 public boolean isColourBySequence()
660 return colourBySequence;
663 public void setColourBySequence(boolean colourBySequence)
665 this.colourBySequence = colourBySequence;
668 public void createImage(String file, String type, int quality)
670 System.out.println("JMOL CREATE IMAGE");
673 public String createImage(String fileName, String type,
674 Object textOrBytes, int quality)
676 System.out.println("JMOL CREATE IMAGE");
680 public String eval(String strEval)
682 // System.out.println(strEval);
683 // "# 'eval' is implemented only for the applet.";
687 // End StructureListener
688 // //////////////////////////
690 public float[][] functionXY(String functionName, int x, int y)
695 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
697 // TODO Auto-generated method stub
701 public Color getColour(int atomIndex, int pdbResNum, String chain,
704 if (getModelNum(pdbfile) < 0)
706 // TODO: verify atomIndex is selecting correct model.
707 return new Color(viewer.getAtomArgb(atomIndex));
711 * returns the current featureRenderer that should be used to colour the
718 public abstract FeatureRenderer getFeatureRenderer(
719 AlignmentViewPanel alignment);
722 * instruct the Jalview binding to update the pdbentries vector if necessary
723 * prior to matching the jmol view's contents to the list of structure files
724 * Jalview knows about.
726 public abstract void refreshPdbEntries();
728 private int getModelNum(String modelFileName)
730 String[] mfn = getPdbFile();
735 for (int i = 0; i < mfn.length; i++)
737 if (mfn[i].equalsIgnoreCase(modelFileName))
744 * map between index of model filename returned from getPdbFile and the first
745 * index of models from this file in the viewer. Note - this is not trimmed -
746 * use getPdbFile to get number of unique models.
748 private int _modelFileNameMap[];
750 // ////////////////////////////////
751 // /StructureListener
752 public synchronized String[] getPdbFile()
756 return new String[0];
758 if (modelFileNames == null)
761 String mset[] = new String[viewer.getModelCount()];
762 _modelFileNameMap = new int[mset.length];
764 String m = viewer.getModelFileName(0);
769 mset[0] = new File(m).getAbsolutePath();
770 } catch (AccessControlException x)
772 // usually not allowed to do this in applet, so keep raw handle
774 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
777 for (int i = 1; i < mset.length; i++)
779 m = viewer.getModelFileName(i);
784 mset[j] = new File(m).getAbsolutePath();
785 } catch (AccessControlException x)
787 // usually not allowed to do this in applet, so keep raw handle
789 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
792 _modelFileNameMap[j] = i; // record the model index for the filename
793 // skip any additional models in the same file (NMR structures)
794 if ((mset[j] == null ? mset[j] != mset[j - 1]
795 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
800 modelFileNames = new String[j];
801 System.arraycopy(mset, 0, modelFileNames, 0, j);
803 return modelFileNames;
807 * map from string to applet
809 public Map getRegistryInfo()
811 // TODO Auto-generated method stub
816 * returns the current sequenceRenderer that should be used to colour the
823 public abstract SequenceRenderer getSequenceRenderer(
824 AlignmentViewPanel alignment);
826 // ///////////////////////////////
827 // JmolStatusListener
829 public void handlePopupMenu(int x, int y)
831 jmolpopup.show(x, y);
835 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
838 if (modelFileNames == null)
843 // look up file model number for this pdbfile
846 // may need to adjust for URLencoding here - we don't worry about that yet.
847 while (mdlNum < modelFileNames.length
848 && !pdbfile.equals(modelFileNames[mdlNum]))
850 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
853 if (mdlNum == modelFileNames.length)
859 // if (!pdbfile.equals(pdbentry.getFile()))
861 if (resetLastRes.length() > 0)
863 viewer.evalStringQuiet(resetLastRes.toString());
867 eval.append("select " + pdbResNum); // +modelNum
869 resetLastRes.setLength(0);
870 resetLastRes.append("select " + pdbResNum); // +modelNum
873 resetLastRes.append(":");
874 if (!chain.equals(" "))
877 resetLastRes.append(chain);
880 eval.append(" /" + (mdlNum + 1));
881 resetLastRes.append("/" + (mdlNum + 1));
883 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
885 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
886 + " and not hetero; spacefill 0;");
888 eval.append("spacefill 200;select none");
890 viewer.evalStringQuiet(eval.toString());
895 boolean debug = true;
897 private void jmolHistory(boolean enable)
899 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
902 public void loadInline(String string)
906 // viewer.loadInline(strModel, isAppend);
908 // construct fake fullPathName and fileName so we can identify the file
910 // Then, construct pass a reader for the string to Jmol.
911 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
912 // fileName, null, reader, false, null, null, 0);
913 viewer.openStringInline(string);
916 public void mouseOverStructure(int atomIndex, String strInfo)
919 int alocsep = strInfo.indexOf("^");
920 int mdlSep = strInfo.indexOf("/");
921 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
923 if (chainSeparator == -1)
925 chainSeparator = strInfo.indexOf(".");
926 if (mdlSep > -1 && mdlSep < chainSeparator)
928 chainSeparator1 = chainSeparator;
929 chainSeparator = mdlSep;
932 // handle insertion codes
935 pdbResNum = Integer.parseInt(strInfo.substring(
936 strInfo.indexOf("]") + 1, alocsep));
941 pdbResNum = Integer.parseInt(strInfo.substring(
942 strInfo.indexOf("]") + 1, chainSeparator));
946 if (strInfo.indexOf(":") > -1)
947 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
948 strInfo.indexOf("."));
954 String pdbfilename = modelFileNames[frameNo]; // default is first or current
958 if (chainSeparator1 == -1)
960 chainSeparator1 = strInfo.indexOf(".", mdlSep);
962 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
963 chainSeparator1) : strInfo.substring(mdlSep + 1);
966 // recover PDB filename for the model hovered over.
967 int _mp = _modelFileNameMap.length - 1, mnumber = new Integer(mdlId)
969 while (mnumber < _modelFileNameMap[_mp])
973 pdbfilename = modelFileNames[_mp];
974 if (pdbfilename == null)
976 pdbfilename = new File(viewer.getModelFileName(mnumber))
980 } catch (Exception e)
985 if (lastMessage == null || !lastMessage.equals(strInfo))
986 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
988 lastMessage = strInfo;
991 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
995 System.err.println("Ignoring additional hover info: " + data
996 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
998 mouseOverStructure(atomIndex, strInfo);
1002 * { if (history != null && strStatus != null &&
1003 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
1007 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
1010 * this implements the toggle label behaviour copied from the original
1011 * structure viewer, MCView
1013 if (strData != null)
1015 System.err.println("Ignoring additional pick data string " + strData);
1017 int chainSeparator = strInfo.indexOf(":");
1019 if (chainSeparator == -1)
1020 chainSeparator = strInfo.indexOf(".");
1022 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
1024 String mdlString = "";
1025 if ((p = strInfo.indexOf(":")) > -1)
1026 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
1028 if ((p = strInfo.indexOf("/")) > -1)
1030 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
1032 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
1036 if (!atomsPicked.contains(picked))
1038 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
1039 atomsPicked.addElement(picked);
1043 viewer.evalString("select " + picked + ";label off");
1044 atomsPicked.removeElement(picked);
1047 // TODO: in application this happens
1049 // if (scriptWindow != null)
1051 // scriptWindow.sendConsoleMessage(strInfo);
1052 // scriptWindow.sendConsoleMessage("\n");
1058 public void notifyCallback(EnumCallback type, Object[] data)
1065 notifyFileLoaded((String) data[1], (String) data[2],
1066 (String) data[3], (String) data[4],
1067 ((Integer) data[5]).intValue());
1071 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
1073 // also highlight in alignment
1075 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
1079 notifyScriptTermination((String) data[2],
1080 ((Integer) data[3]).intValue());
1083 sendConsoleEcho((String) data[1]);
1086 sendConsoleMessage((data == null) ? ((String) null)
1087 : (String) data[1]);
1090 // System.err.println("Ignoring error callback.");
1100 System.err.println("Unhandled callback " + type + " "
1101 + data[1].toString());
1104 } catch (Exception e)
1106 System.err.println("Squashed Jmol callback handler error:");
1107 e.printStackTrace();
1112 public boolean notifyEnabled(EnumCallback callbackPick)
1114 switch (callbackPick)
1134 // incremented every time a load notification is successfully handled -
1135 // lightweight mechanism for other threads to detect when they can start
1136 // referrring to new structures.
1137 private long loadNotifiesHandled = 0;
1139 public long getLoadNotifiesHandled()
1141 return loadNotifiesHandled;
1144 public void notifyFileLoaded(String fullPathName, String fileName2,
1145 String modelName, String errorMsg, int modelParts)
1147 if (errorMsg != null)
1149 fileLoadingError = errorMsg;
1153 // TODO: deal sensibly with models loaded inLine:
1154 // modelName will be null, as will fullPathName.
1156 // the rest of this routine ignores the arguments, and simply interrogates
1157 // the Jmol view to find out what structures it contains, and adds them to
1158 // the structure selection manager.
1159 fileLoadingError = null;
1160 String[] oldmodels = modelFileNames;
1161 modelFileNames = null;
1162 chainNames = new Vector();
1163 chainFile = new Hashtable();
1164 boolean notifyLoaded = false;
1165 String[] modelfilenames = getPdbFile();
1166 // first check if we've lost any structures
1167 if (oldmodels != null && oldmodels.length > 0)
1170 for (int i = 0; i < oldmodels.length; i++)
1172 for (int n = 0; n < modelfilenames.length; n++)
1174 if (modelfilenames[n] == oldmodels[i])
1176 oldmodels[i] = null;
1180 if (oldmodels[i] != null)
1187 String[] oldmfn = new String[oldm];
1189 for (int i = 0; i < oldmodels.length; i++)
1191 if (oldmodels[i] != null)
1193 oldmfn[oldm++] = oldmodels[i];
1196 // deregister the Jmol instance for these structures - we'll add
1197 // ourselves again at the end for the current structure set.
1198 ssm.removeStructureViewerListener(this, oldmfn);
1201 refreshPdbEntries();
1202 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1204 String fileName = modelfilenames[modelnum];
1205 boolean foundEntry = false;
1206 MCview.PDBfile pdb = null;
1207 String pdbfile = null, pdbfhash = null;
1208 // model was probably loaded inline - so check the pdb file hashcode
1211 // calculate essential attributes for the pdb data imported inline.
1212 // prolly need to resolve modelnumber properly - for now just use our
1214 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1216 pdbfhash = "" + pdbfile.hashCode();
1218 if (pdbentry != null)
1220 // search pdbentries and sequences to find correct pdbentry for this
1222 for (int pe = 0; pe < pdbentry.length; pe++)
1224 boolean matches = false;
1225 if (fileName == null)
1228 // see JAL-623 - need method of matching pasted data up
1230 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
1231 AppletFormatAdapter.PASTE);
1232 pdbentry[modelnum].setFile("INLINE" + pdb.id);
1240 if (matches = (fl = new File(pdbentry[pe].getFile()))
1241 .equals(new File(fileName)))
1244 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1247 // to be tested. See mantis bug
1248 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1249 String protocol = AppletFormatAdapter.URL;
1254 protocol = AppletFormatAdapter.FILE;
1256 } catch (Exception e)
1261 // Explicitly map to the filename used by Jmol ;
1262 pdb = ssm.setMapping(sequence[pe], chains[pe], fileName,
1264 // pdbentry[pe].getFile(), protocol);
1270 // add an entry for every chain in the model
1271 for (int i = 0; i < pdb.chains.size(); i++)
1273 String chid = new String(pdb.id + ":"
1274 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
1275 chainFile.put(chid, fileName);
1276 chainNames.addElement(chid);
1278 notifyLoaded = true;
1282 if (!foundEntry && associateNewStructs)
1284 // this is a foreign pdb file that jalview doesn't know about - add
1285 // it to the dataset and try to find a home - either on a matching
1286 // sequence or as a new sequence.
1287 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1289 // parse pdb file into a chain, etc.
1290 // locate best match for pdb in associated views and add mapping to
1292 // if properly registered then
1293 notifyLoaded = true;
1298 // so finally, update the jmol bits and pieces
1299 if (jmolpopup != null)
1301 // potential for deadlock here:
1302 // jmolpopup.updateComputedMenus();
1304 if (!isLoadingFromArchive())
1306 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1308 // register ourselves as a listener and notify the gui that it needs to
1310 ssm.addStructureViewerListener(this);
1313 FeatureRenderer fr = getFeatureRenderer(null);
1319 loadNotifiesHandled++;
1321 setLoadingFromArchive(false);
1324 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1326 notifyAtomPicked(iatom, strMeasure, null);
1329 public abstract void notifyScriptTermination(String strStatus,
1333 * display a message echoed from the jmol viewer
1337 public abstract void sendConsoleEcho(String strEcho); /*
1338 * { showConsole(true);
1340 * history.append("\n" +
1344 // /End JmolStatusListener
1345 // /////////////////////////////
1349 * status message - usually the response received after a script
1352 public abstract void sendConsoleMessage(String strStatus);
1354 public void setCallbackFunction(String callbackType,
1355 String callbackFunction)
1357 System.err.println("Ignoring set-callback request to associate "
1358 + callbackType + " with function " + callbackFunction);
1362 public void setJalviewColourScheme(ColourSchemeI cs)
1364 colourBySequence = false;
1373 // TODO: Switch between nucleotide or aa selection expressions
1374 Enumeration en = ResidueProperties.aa3Hash.keys();
1375 StringBuffer command = new StringBuffer("select *;color white;");
1376 while (en.hasMoreElements())
1378 res = en.nextElement().toString();
1379 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
1383 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
1385 command.append("select " + res + ";color[" + col.getRed() + ","
1386 + col.getGreen() + "," + col.getBlue() + "];");
1389 evalStateCommand(command.toString());
1393 public void showHelp()
1395 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1399 * open the URL somehow
1403 public abstract void showUrl(String url, String target);
1406 * called when the binding thinks the UI needs to be refreshed after a Jmol
1407 * state change. this could be because structures were loaded, or because an
1408 * error has occured.
1410 public abstract void refreshGUI();
1413 * called to show or hide the associated console window container.
1417 public abstract void showConsole(boolean show);
1420 * @param renderPanel
1422 * - when true will initialise jmol's file IO system (should be false
1423 * in applet context)
1425 * @param documentBase
1427 * @param commandOptions
1429 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1430 String htmlName, URL documentBase, URL codeBase,
1431 String commandOptions)
1433 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1434 codeBase, commandOptions, null, null);
1439 * @param renderPanel
1441 * - when true will initialise jmol's file IO system (should be false
1442 * in applet context)
1444 * @param documentBase
1446 * @param commandOptions
1447 * @param consolePanel
1448 * - panel to contain Jmol console
1449 * @param buttonsToShow
1450 * - buttons to show on the console, in ordr
1452 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1453 String htmlName, URL documentBase, URL codeBase,
1454 String commandOptions, final Container consolePanel,
1455 String buttonsToShow)
1457 if (commandOptions == null)
1459 commandOptions = "";
1461 viewer = JmolViewer.allocateViewer(renderPanel,
1462 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1463 + ((Object) this).toString(), documentBase, codeBase,
1464 commandOptions, this);
1466 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
1467 if (consolePanel != null)
1469 consolePanel.addComponentListener(this);
1475 protected abstract JmolAppConsoleInterface createJmolConsole(
1476 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
1478 protected org.jmol.api.JmolAppConsoleInterface console = null;
1480 public void componentResized(ComponentEvent e)
1485 public void componentMoved(ComponentEvent e)
1490 public void componentShown(ComponentEvent e)
1495 public void componentHidden(ComponentEvent e)
1500 public void setBackgroundColour(java.awt.Color col)
1503 viewer.evalStringQuiet("background [" + col.getRed() + ","
1504 + col.getGreen() + "," + col.getBlue() + "];");
1509 * add structures and any known sequence associations
1511 * @returns the pdb entries added to the current set.
1513 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
1514 SequenceI[][] seq, String[][] chns)
1517 Vector v = new Vector();
1518 Vector rtn = new Vector();
1519 for (int i = 0; i < pdbentry.length; i++)
1521 v.addElement(pdbentry[i]);
1523 for (int i = 0; i < pdbe.length; i++)
1525 int r = v.indexOf(pdbe[i]);
1526 if (r == -1 || r >= pdbentry.length)
1528 rtn.addElement(new int[]
1530 v.addElement(pdbe[i]);
1534 // just make sure the sequence/chain entries are all up to date
1535 addSequenceAndChain(r, seq[i], chns[i]);
1538 pdbe = new PDBEntry[v.size()];
1543 // expand the tied seuqence[] and string[] arrays
1544 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
1545 String[][] sch = new String[pdbentry.length][];
1546 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
1547 System.arraycopy(chains, 0, sch, 0, this.chains.length);
1550 pdbe = new PDBEntry[rtn.size()];
1551 for (int r = 0; r < pdbe.length; r++)
1553 int[] stri = ((int[]) rtn.elementAt(r));
1554 // record the pdb file as a new addition
1555 pdbe[r] = pdbentry[stri[0]];
1556 // and add the new sequence/chain entries
1557 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
1567 public void addSequence(int pe, SequenceI[] seq)
1569 // add sequences to the pe'th pdbentry's seuqence set.
1570 addSequenceAndChain(pe, seq, null);
1573 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
1575 if (pe < 0 || pe >= pdbentry.length)
1577 throw new Error(MessageManager.formatMessage("error.implementation_error_no_pdbentry_from_index", new String[]{Integer.valueOf(pe).toString()}));
1579 final String nullChain = "TheNullChain";
1580 Vector s = new Vector();
1581 Vector c = new Vector();
1584 chains = new String[pdbentry.length][];
1586 if (sequence[pe] != null)
1588 for (int i = 0; i < sequence[pe].length; i++)
1590 s.addElement(sequence[pe][i]);
1591 if (chains[pe] != null)
1593 if (i < chains[pe].length)
1595 c.addElement(chains[pe][i]);
1599 c.addElement(nullChain);
1604 if (tchain != null && tchain.length > 0)
1606 c.addElement(nullChain);
1611 for (int i = 0; i < seq.length; i++)
1613 if (!s.contains(seq[i]))
1615 s.addElement(seq[i]);
1616 if (tchain != null && i < tchain.length)
1618 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
1622 SequenceI[] tmp = new SequenceI[s.size()];
1627 String[] tch = new String[c.size()];
1629 for (int i = 0; i < tch.length; i++)
1631 if (tch[i] == nullChain)
1647 * @return text report of alignment between pdbfile and any associated
1648 * alignment sequences
1650 public String printMapping(String pdbfile)
1652 return ssm.printMapping(pdbfile);
1656 public void resizeInnerPanel(String data)
1658 // Jalview doesn't honour resize panel requests