2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
\r
3 * Copyright (C) 2011 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
\r
5 * This file is part of Jalview.
\r
7 * Jalview is free software: you can redistribute it and/or
\r
8 * modify it under the terms of the GNU General Public License
\r
9 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
\r
11 * Jalview is distributed in the hope that it will be useful, but
\r
12 * WITHOUT ANY WARRANTY; without even the implied warranty
\r
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
14 * PURPOSE. See the GNU General Public License for more details.
\r
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
\r
18 package jalview.ext.jmol;
\r
20 import jalview.api.AlignmentViewPanel;
\r
21 import jalview.api.FeatureRenderer;
\r
22 import jalview.api.SequenceRenderer;
\r
23 import jalview.api.SequenceStructureBinding;
\r
24 import jalview.api.StructureSelectionManagerProvider;
\r
25 import jalview.datamodel.AlignmentI;
\r
26 import jalview.datamodel.ColumnSelection;
\r
27 import jalview.datamodel.PDBEntry;
\r
28 import jalview.datamodel.SequenceI;
\r
29 import jalview.io.AppletFormatAdapter;
\r
30 import jalview.schemes.ColourSchemeI;
\r
31 import jalview.schemes.ResidueProperties;
\r
32 import jalview.structure.StructureListener;
\r
33 import jalview.structure.StructureMapping;
\r
34 import jalview.structure.StructureSelectionManager;
\r
36 import java.awt.Color;
\r
37 import java.awt.Container;
\r
38 import java.awt.event.ComponentEvent;
\r
39 import java.awt.event.ComponentListener;
\r
40 import java.io.File;
\r
41 import java.net.URL;
\r
42 import java.util.Enumeration;
\r
43 import java.util.Hashtable;
\r
44 import java.util.Map;
\r
45 import java.util.Vector;
\r
47 import org.jmol.adapter.smarter.SmarterJmolAdapter;
\r
48 import org.jmol.api.JmolAppConsoleInterface;
\r
49 import org.jmol.api.JmolSelectionListener;
\r
50 import org.jmol.api.JmolStatusListener;
\r
51 import org.jmol.api.JmolViewer;
\r
52 import org.jmol.constant.EnumCallback;
\r
53 import org.jmol.popup.JmolPopup;
\r
55 public abstract class JalviewJmolBinding implements StructureListener,
\r
56 JmolStatusListener, SequenceStructureBinding,
\r
57 JmolSelectionListener, ComponentListener, StructureSelectionManagerProvider
\r
61 * set if Jmol state is being restored from some source - instructs binding
\r
62 * not to apply default display style when structure set is updated for first
\r
65 private boolean loadingFromArchive = false;
\r
68 * state flag used to check if the Jmol viewer's paint method can be called
\r
70 private boolean finishedInit = false;
\r
72 public boolean isFinishedInit()
\r
74 return finishedInit;
\r
77 public void setFinishedInit(boolean finishedInit)
\r
79 this.finishedInit = finishedInit;
\r
82 boolean allChainsSelected = false;
\r
85 * when true, try to search the associated datamodel for sequences that are
\r
86 * associated with any unknown structures in the Jmol view.
\r
88 private boolean associateNewStructs = false;
\r
90 Vector atomsPicked = new Vector();
\r
92 public Vector chainNames;
\r
94 Hashtable chainFile;
\r
97 * array of target chains for seuqences - tied to pdbentry and sequence[]
\r
99 protected String[][] chains;
\r
101 boolean colourBySequence = true;
\r
103 StringBuffer eval = new StringBuffer();
\r
105 public String fileLoadingError;
\r
108 * the default or current model displayed if the model cannot be identified
\r
109 * from the selection message
\r
113 protected JmolPopup jmolpopup;
\r
115 String lastCommand;
\r
117 String lastMessage;
\r
119 boolean loadedInline;
\r
122 * current set of model filenames loaded in the Jmol instance
\r
124 String[] modelFileNames = null;
\r
126 public PDBEntry[] pdbentry;
\r
129 * datasource protocol for access to PDBEntrylatest
\r
131 String protocol = null;
\r
133 StringBuffer resetLastRes = new StringBuffer();
\r
136 * sequences mapped to each pdbentry
\r
138 public SequenceI[][] sequence;
\r
140 public StructureSelectionManager ssm;
\r
142 public JmolViewer viewer;
\r
144 public JalviewJmolBinding(StructureSelectionManager ssm, PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
\r
145 String[][] chains, String protocol)
\r
148 this.sequence = sequenceIs;
\r
149 this.chains = chains;
\r
150 this.pdbentry = pdbentry;
\r
151 this.protocol = protocol;
\r
152 if (chains == null)
\r
154 this.chains = new String[pdbentry.length][];
\r
157 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
\r
158 * "jalviewJmol", ap.av.applet .getDocumentBase(),
\r
159 * ap.av.applet.getCodeBase(), "", this);
\r
161 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
\r
165 public JalviewJmolBinding(StructureSelectionManager ssm, JmolViewer viewer2)
\r
169 viewer.setJmolStatusListener(this);
\r
170 viewer.addSelectionListener(this);
\r
174 * construct a title string for the viewer window based on the data jalview
\r
179 public String getViewerTitle()
\r
181 if (sequence == null || pdbentry == null || sequence.length < 1
\r
182 || pdbentry.length < 1 || sequence[0].length < 1)
\r
184 return ("Jalview Jmol Window");
\r
186 // TODO: give a more informative title when multiple structures are
\r
188 StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
\r
189 + pdbentry[0].getId());
\r
191 if (pdbentry[0].getProperty() != null)
\r
193 if (pdbentry[0].getProperty().get("method") != null)
\r
195 title.append(" Method: ");
\r
196 title.append(pdbentry[0].getProperty().get("method"));
\r
198 if (pdbentry[0].getProperty().get("chains") != null)
\r
200 title.append(" Chain:");
\r
201 title.append(pdbentry[0].getProperty().get("chains"));
\r
204 return title.toString();
\r
208 * prepare the view for a given set of models/chains. chainList contains
\r
209 * strings of the form 'pdbfilename:Chaincode'
\r
212 * list of chains to make visible
\r
214 public void centerViewer(Vector chainList)
\r
216 StringBuffer cmd = new StringBuffer();
\r
219 for (int i = 0, iSize = chainList.size(); i < iSize; i++)
\r
222 lbl = (String) chainList.elementAt(i);
\r
226 mlength = lbl.indexOf(":", p);
\r
227 } while (p < mlength && mlength < (lbl.length() - 2));
\r
228 // TODO: lookup each pdb id and recover proper model number for it.
\r
229 cmd.append(":" + lbl.substring(mlength + 1) + " /"
\r
230 + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");
\r
232 if (cmd.length() > 0)
\r
233 cmd.setLength(cmd.length() - 4);
\r
234 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
\r
237 public void closeViewer()
\r
239 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
\r
240 // remove listeners for all structures in viewer
\r
241 ssm.removeStructureViewerListener(this, this.getPdbFile());
\r
242 // and shut down jmol
\r
243 viewer.evalStringQuiet("zap");
\r
244 viewer.setJmolStatusListener(null);
\r
245 lastCommand = null;
\r
247 releaseUIResources();
\r
251 * called by JalviewJmolbinding after closeViewer is called - release any
\r
252 * resources and references so they can be garbage collected.
\r
254 protected abstract void releaseUIResources();
\r
256 public void colourByChain()
\r
258 colourBySequence = false;
\r
259 // TODO: colour by chain should colour each chain distinctly across all
\r
261 // TODO: http://issues.jalview.org/browse/JAL-628
\r
262 evalStateCommand("select *;color chain");
\r
265 public void colourByCharge()
\r
267 colourBySequence = false;
\r
268 evalStateCommand("select *;color white;select ASP,GLU;color red;"
\r
269 + "select LYS,ARG;color blue;select CYS;color yellow");
\r
273 * superpose the structures associated with sequences in the alignment
\r
274 * according to their corresponding positions.
\r
276 public void superposeStructures(AlignmentI alignment)
\r
278 superposeStructures(alignment, -1, null);
\r
282 * superpose the structures associated with sequences in the alignment
\r
283 * according to their corresponding positions. ded)
\r
285 * @param refStructure
\r
286 * - select which pdb file to use as reference (default is -1 - the
\r
287 * first structure in the alignment)
\r
289 public void superposeStructures(AlignmentI alignment, int refStructure)
\r
291 superposeStructures(alignment, refStructure, null);
\r
295 * superpose the structures associated with sequences in the alignment
\r
296 * according to their corresponding positions. ded)
\r
298 * @param refStructure
\r
299 * - select which pdb file to use as reference (default is -1 - the
\r
300 * first structure in the alignment)
\r
301 * @param hiddenCols
\r
304 public void superposeStructures(AlignmentI alignment, int refStructure,
\r
305 ColumnSelection hiddenCols)
\r
307 superposeStructures(new AlignmentI[]
\r
308 { alignment }, new int[]
\r
309 { refStructure }, new ColumnSelection[]
\r
313 public void superposeStructures(AlignmentI[] _alignment,
\r
314 int[] _refStructure, ColumnSelection[] _hiddenCols)
\r
316 String[] files = getPdbFile();
\r
317 StringBuffer selectioncom = new StringBuffer();
\r
318 assert (_alignment.length == _refStructure.length && _alignment.length != _hiddenCols.length);
\r
319 // union of all aligned positions are collected together.
\r
320 for (int a = 0; a < _alignment.length; a++)
\r
322 int refStructure = _refStructure[a];
\r
323 AlignmentI alignment = _alignment[a];
\r
324 ColumnSelection hiddenCols = _hiddenCols[a];
\r
326 && selectioncom.length() > 0
\r
327 && !selectioncom.substring(selectioncom.length() - 1).equals(
\r
330 selectioncom.append("|");
\r
332 // process this alignment
\r
333 if (refStructure >= files.length)
\r
335 System.err.println("Invalid reference structure value "
\r
339 if (refStructure < -1)
\r
343 StringBuffer command = new StringBuffer();
\r
345 boolean matched[] = new boolean[alignment.getWidth()];
\r
346 for (int m = 0; m < matched.length; m++)
\r
349 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
\r
352 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
\r
353 String isel[] = new String[files.length];
\r
354 // reference structure - all others are superposed in it
\r
355 String[] targetC = new String[files.length];
\r
356 String[] chainNames = new String[files.length];
\r
357 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
\r
359 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
\r
361 if (mapping == null || mapping.length < 1)
\r
365 for (int s = 0; s < sequence[pdbfnum].length; s++)
\r
367 for (int sp, m = 0; m < mapping.length; m++)
\r
369 if (mapping[m].getSequence() == sequence[pdbfnum][s]
\r
370 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
\r
372 if (refStructure == -1)
\r
374 refStructure = pdbfnum;
\r
376 SequenceI asp = alignment.getSequenceAt(sp);
\r
377 for (int r = 0; r < matched.length; r++)
\r
383 matched[r] = false; // assume this is not a good site
\r
384 if (r >= asp.getLength())
\r
389 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
\r
391 // no mapping to gaps in sequence
\r
394 int t = asp.findPosition(r); // sequence position
\r
395 int apos = mapping[m].getAtomNum(t);
\r
396 int pos = mapping[m].getPDBResNum(t);
\r
398 if (pos < 1 || pos == lastPos)
\r
400 // can't align unmapped sequence
\r
403 matched[r] = true; // this is a good ite
\r
405 // just record this residue position
\r
406 commonrpositions[pdbfnum][r] = pos;
\r
408 // create model selection suffix
\r
409 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
\r
410 if (mapping[m].getChain() == null
\r
411 || mapping[m].getChain().trim().length() == 0)
\r
413 targetC[pdbfnum] = "";
\r
417 targetC[pdbfnum] = ":" + mapping[m].getChain();
\r
419 chainNames[pdbfnum] = mapping[m].getPdbId()
\r
420 + targetC[pdbfnum];
\r
421 // move on to next pdb file
\r
422 s = sequence[pdbfnum].length;
\r
428 String[] selcom = new String[files.length];
\r
430 // generate select statements to select regions to superimpose structures
\r
432 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
\r
434 String chainCd = targetC[pdbfnum];
\r
436 boolean run = false;
\r
437 StringBuffer molsel = new StringBuffer();
\r
438 molsel.append("{");
\r
439 for (int r = 0; r < matched.length; r++)
\r
447 if (lpos != commonrpositions[pdbfnum][r] - 1)
\r
452 molsel.append(lpos);
\r
453 molsel.append(chainCd);
\r
454 // molsel.append("} {");
\r
455 molsel.append("|");
\r
460 // continuous run - and lpos >-1
\r
463 // at the beginning, so add dash
\r
464 molsel.append(lpos);
\r
465 molsel.append("-");
\r
469 lpos = commonrpositions[pdbfnum][r];
\r
470 // molsel.append(lpos);
\r
473 // add final selection phrase
\r
476 molsel.append(lpos);
\r
477 molsel.append(chainCd);
\r
478 molsel.append("}");
\r
480 selcom[pdbfnum] = molsel.toString();
\r
481 selectioncom.append("((");
\r
482 selectioncom.append(selcom[pdbfnum].substring(1,
\r
483 selcom[pdbfnum].length() - 1));
\r
484 selectioncom.append(" )& ");
\r
485 selectioncom.append(pdbfnum + 1);
\r
486 selectioncom.append(".1)");
\r
487 if (pdbfnum < files.length - 1)
\r
489 selectioncom.append("|");
\r
493 // TODO: consider bailing if nmatched less than 4 because superposition
\r
496 // TODO: refactor superposable position search (above) from jmol selection
\r
497 // construction (below)
\r
498 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
\r
500 if (pdbfnum == refStructure)
\r
504 command.append("echo ");
\r
505 command.append("\"Superposing (");
\r
506 command.append(chainNames[pdbfnum]);
\r
507 command.append(") against reference (");
\r
508 command.append(chainNames[refStructure]);
\r
509 command.append(")\";\ncompare ");
\r
510 command.append("{");
\r
511 command.append(1 + pdbfnum);
\r
512 command.append(".1} {");
\r
513 command.append(1 + refStructure);
\r
514 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
\r
516 // form the matched pair strings
\r
518 for (int s = 0; s < 2; s++)
\r
520 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
\r
522 command.append(" ROTATE TRANSLATE;\n");
\r
524 System.out.println("Select regions:\n" + selectioncom.toString());
\r
525 evalStateCommand("select *; cartoons off; backbone; select ("
\r
526 + selectioncom.toString() + "); cartoons; ");
\r
527 // selcom.append("; ribbons; ");
\r
528 System.out.println("Superimpose command(s):\n" + command.toString());
\r
530 evalStateCommand(command.toString());
\r
532 if (selectioncom.length() > 0)
\r
533 {// finally, mark all regions that were superposed.
\r
534 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
\r
536 selectioncom.setLength(selectioncom.length() - 1);
\r
538 System.out.println("Select regions:\n" + selectioncom.toString());
\r
539 evalStateCommand("select *; cartoons off; backbone; select ("
\r
540 + selectioncom.toString() + "); cartoons; ");
\r
541 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
\r
545 public void evalStateCommand(String command)
\r
547 jmolHistory(false);
\r
548 if (lastCommand == null || !lastCommand.equals(command))
\r
550 viewer.evalStringQuiet(command + "\n");
\r
553 lastCommand = command;
\r
557 * colour any structures associated with sequences in the given alignment
\r
558 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
\r
559 * if colourBySequence is enabled.
\r
561 public void colourBySequence(boolean showFeatures,
\r
562 jalview.api.AlignmentViewPanel alignmentv)
\r
564 if (!colourBySequence)
\r
570 String[] files = getPdbFile();
\r
572 SequenceRenderer sr = getSequenceRenderer(alignmentv);
\r
574 FeatureRenderer fr = null;
\r
577 fr = getFeatureRenderer(alignmentv);
\r
579 AlignmentI alignment = alignmentv.getAlignment();
\r
581 for (jalview.structure.StructureMappingcommandSet cpdbbyseq: JmolCommands.getColourBySequenceCommand(ssm, files, sequence, sr, fr, alignment))
\r
582 for (String cbyseq : cpdbbyseq.commands) {
\r
583 evalStateCommand(cbyseq);
\r
587 public boolean isColourBySequence()
\r
589 return colourBySequence;
\r
592 public void setColourBySequence(boolean colourBySequence)
\r
594 this.colourBySequence = colourBySequence;
\r
597 public void createImage(String file, String type, int quality)
\r
599 System.out.println("JMOL CREATE IMAGE");
\r
602 public String createImage(String fileName, String type,
\r
603 Object textOrBytes, int quality)
\r
605 System.out.println("JMOL CREATE IMAGE");
\r
609 public String eval(String strEval)
\r
611 // System.out.println(strEval);
\r
612 // "# 'eval' is implemented only for the applet.";
\r
616 // End StructureListener
\r
617 // //////////////////////////
\r
619 public float[][] functionXY(String functionName, int x, int y)
\r
624 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
\r
626 // TODO Auto-generated method stub
\r
630 public Color getColour(int atomIndex, int pdbResNum, String chain,
\r
633 if (getModelNum(pdbfile) < 0)
\r
635 // TODO: verify atomIndex is selecting correct model.
\r
636 return new Color(viewer.getAtomArgb(atomIndex));
\r
640 * returns the current featureRenderer that should be used to colour the
\r
647 public abstract FeatureRenderer getFeatureRenderer(
\r
648 AlignmentViewPanel alignment);
\r
651 * instruct the Jalview binding to update the pdbentries vector if necessary
\r
652 * prior to matching the jmol view's contents to the list of structure files
\r
653 * Jalview knows about.
\r
655 public abstract void refreshPdbEntries();
\r
657 private int getModelNum(String modelFileName)
\r
659 String[] mfn = getPdbFile();
\r
664 for (int i = 0; i < mfn.length; i++)
\r
666 if (mfn[i].equalsIgnoreCase(modelFileName))
\r
673 * map between index of model filename returned from getPdbFile and the first
\r
674 * index of models from this file in the viewer. Note - this is not trimmed -
\r
675 * use getPdbFile to get number of unique models.
\r
677 private int _modelFileNameMap[];
\r
679 // ////////////////////////////////
\r
680 // /StructureListener
\r
681 public synchronized String[] getPdbFile()
\r
683 if (viewer == null)
\r
685 return new String[0];
\r
687 if (modelFileNames == null)
\r
690 String mset[] = new String[viewer.getModelCount()];
\r
691 _modelFileNameMap = new int[mset.length];
\r
693 mset[0] = viewer.getModelFileName(0);
\r
694 for (int i = 1; i < mset.length; i++)
\r
696 mset[j] = viewer.getModelFileName(i);
\r
697 _modelFileNameMap[j] = i; // record the model index for the filename
\r
698 // skip any additional models in the same file (NMR structures)
\r
699 if ((mset[j] == null ? mset[j] != mset[j - 1]
\r
700 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
\r
705 modelFileNames = new String[j];
\r
706 System.arraycopy(mset, 0, modelFileNames, 0, j);
\r
708 return modelFileNames;
\r
712 * map from string to applet
\r
714 public Map getRegistryInfo()
\r
716 // TODO Auto-generated method stub
\r
721 * returns the current sequenceRenderer that should be used to colour the
\r
728 public abstract SequenceRenderer getSequenceRenderer(
\r
729 AlignmentViewPanel alignment);
\r
731 // ///////////////////////////////
\r
732 // JmolStatusListener
\r
734 public void handlePopupMenu(int x, int y)
\r
736 jmolpopup.show(x, y);
\r
740 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
\r
743 if (modelFileNames == null)
\r
748 // look up file model number for this pdbfile
\r
751 // may need to adjust for URLencoding here - we don't worry about that yet.
\r
752 while (mdlNum < modelFileNames.length
\r
753 && !pdbfile.equals(modelFileNames[mdlNum]))
\r
755 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
\r
758 if (mdlNum == modelFileNames.length)
\r
763 jmolHistory(false);
\r
764 // if (!pdbfile.equals(pdbentry.getFile()))
\r
766 if (resetLastRes.length() > 0)
\r
768 viewer.evalStringQuiet(resetLastRes.toString());
\r
772 eval.append("select " + pdbResNum); // +modelNum
\r
774 resetLastRes.setLength(0);
\r
775 resetLastRes.append("select " + pdbResNum); // +modelNum
\r
778 resetLastRes.append(":");
\r
779 if (!chain.equals(" "))
\r
781 eval.append(chain);
\r
782 resetLastRes.append(chain);
\r
785 eval.append(" /" + (mdlNum + 1));
\r
786 resetLastRes.append("/" + (mdlNum + 1));
\r
788 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
\r
790 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
\r
791 + " and not hetero; spacefill 0;");
\r
793 eval.append("spacefill 200;select none");
\r
795 viewer.evalStringQuiet(eval.toString());
\r
800 boolean debug = true;
\r
802 private void jmolHistory(boolean enable)
\r
804 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
\r
807 public void loadInline(String string)
\r
809 loadedInline = true;
\r
810 // TODO: re JAL-623
\r
811 // viewer.loadInline(strModel, isAppend);
\r
813 // construct fake fullPathName and fileName so we can identify the file
\r
815 // Then, construct pass a reader for the string to Jmol.
\r
816 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
\r
817 // fileName, null, reader, false, null, null, 0);
\r
818 viewer.openStringInline(string);
\r
821 public void mouseOverStructure(int atomIndex, String strInfo)
\r
824 int alocsep = strInfo.indexOf("^");
\r
825 int mdlSep = strInfo.indexOf("/");
\r
826 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
\r
828 if (chainSeparator == -1)
\r
830 chainSeparator = strInfo.indexOf(".");
\r
831 if (mdlSep > -1 && mdlSep < chainSeparator)
\r
833 chainSeparator1 = chainSeparator;
\r
834 chainSeparator = mdlSep;
\r
837 // handle insertion codes
\r
840 pdbResNum = Integer.parseInt(strInfo.substring(
\r
841 strInfo.indexOf("]") + 1, alocsep));
\r
846 pdbResNum = Integer.parseInt(strInfo.substring(
\r
847 strInfo.indexOf("]") + 1, chainSeparator));
\r
851 if (strInfo.indexOf(":") > -1)
\r
852 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
\r
853 strInfo.indexOf("."));
\r
859 String pdbfilename = modelFileNames[frameNo]; // default is first or current
\r
863 if (chainSeparator1 == -1)
\r
865 chainSeparator1 = strInfo.indexOf(".", mdlSep);
\r
867 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
\r
868 chainSeparator1) : strInfo.substring(mdlSep + 1);
\r
871 // recover PDB filename for the model hovered over.
\r
872 pdbfilename = viewer
\r
873 .getModelFileName(new Integer(mdlId).intValue() - 1);
\r
875 } catch (Exception e)
\r
880 if (lastMessage == null || !lastMessage.equals(strInfo))
\r
881 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
\r
883 lastMessage = strInfo;
\r
886 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
\r
890 System.err.println("Ignoring additional hover info: " + data
\r
891 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
\r
893 mouseOverStructure(atomIndex, strInfo);
\r
897 * { if (history != null && strStatus != null &&
\r
898 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
\r
902 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
\r
905 * this implements the toggle label behaviour copied from the original
\r
906 * structure viewer, MCView
\r
908 if (strData != null)
\r
910 System.err.println("Ignoring additional pick data string " + strData);
\r
912 int chainSeparator = strInfo.indexOf(":");
\r
914 if (chainSeparator == -1)
\r
915 chainSeparator = strInfo.indexOf(".");
\r
917 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
\r
919 String mdlString = "";
\r
920 if ((p = strInfo.indexOf(":")) > -1)
\r
921 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
\r
923 if ((p = strInfo.indexOf("/")) > -1)
\r
925 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
\r
927 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
\r
928 + mdlString + "))";
\r
929 jmolHistory(false);
\r
931 if (!atomsPicked.contains(picked))
\r
933 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
\r
934 atomsPicked.addElement(picked);
\r
938 viewer.evalString("select " + picked + ";label off");
\r
939 atomsPicked.removeElement(picked);
\r
942 // TODO: in application this happens
\r
944 // if (scriptWindow != null)
\r
946 // scriptWindow.sendConsoleMessage(strInfo);
\r
947 // scriptWindow.sendConsoleMessage("\n");
\r
953 public void notifyCallback(EnumCallback type, Object[] data)
\r
960 notifyFileLoaded((String) data[1], (String) data[2],
\r
961 (String) data[3], (String) data[4],
\r
962 ((Integer) data[5]).intValue());
\r
966 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
\r
968 // also highlight in alignment
\r
970 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
\r
974 notifyScriptTermination((String) data[2],
\r
975 ((Integer) data[3]).intValue());
\r
978 sendConsoleEcho((String) data[1]);
\r
981 sendConsoleMessage((data == null) ? ((String) null)
\r
982 : (String) data[1]);
\r
985 // System.err.println("Ignoring error callback.");
\r
995 System.err.println("Unhandled callback " + type + " "
\r
996 + data[1].toString());
\r
999 } catch (Exception e)
\r
1001 System.err.println("Squashed Jmol callback handler error:");
\r
1002 e.printStackTrace();
\r
1007 public boolean notifyEnabled(EnumCallback callbackPick)
\r
1009 switch (callbackPick)
\r
1024 case MINIMIZATION:
\r
1029 // incremented every time a load notification is successfully handled -
\r
1030 // lightweight mechanism for other threads to detect when they can start
\r
1031 // referrring to new structures.
\r
1032 private long loadNotifiesHandled = 0;
\r
1034 public long getLoadNotifiesHandled()
\r
1036 return loadNotifiesHandled;
\r
1039 public void notifyFileLoaded(String fullPathName, String fileName2,
\r
1040 String modelName, String errorMsg, int modelParts)
\r
1042 if (errorMsg != null)
\r
1044 fileLoadingError = errorMsg;
\r
1048 // TODO: deal sensibly with models loaded inLine:
\r
1049 // modelName will be null, as will fullPathName.
\r
1051 // the rest of this routine ignores the arguments, and simply interrogates
\r
1052 // the Jmol view to find out what structures it contains, and adds them to
\r
1053 // the structure selection manager.
\r
1054 fileLoadingError = null;
\r
1055 String[] oldmodels = modelFileNames;
\r
1056 modelFileNames = null;
\r
1057 chainNames = new Vector();
\r
1058 chainFile = new Hashtable();
\r
1059 boolean notifyLoaded = false;
\r
1060 String[] modelfilenames = getPdbFile();
\r
1061 // first check if we've lost any structures
\r
1062 if (oldmodels != null && oldmodels.length > 0)
\r
1065 for (int i = 0; i < oldmodels.length; i++)
\r
1067 for (int n = 0; n < modelfilenames.length; n++)
\r
1069 if (modelfilenames[n] == oldmodels[i])
\r
1071 oldmodels[i] = null;
\r
1075 if (oldmodels[i] != null)
\r
1082 String[] oldmfn = new String[oldm];
\r
1084 for (int i = 0; i < oldmodels.length; i++)
\r
1086 if (oldmodels[i] != null)
\r
1088 oldmfn[oldm++] = oldmodels[i];
\r
1091 // deregister the Jmol instance for these structures - we'll add
\r
1092 // ourselves again at the end for the current structure set.
\r
1093 ssm.removeStructureViewerListener(this, oldmfn);
\r
1096 refreshPdbEntries();
\r
1097 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
\r
1099 String fileName = modelfilenames[modelnum];
\r
1100 boolean foundEntry = false;
\r
1101 MCview.PDBfile pdb = null;
\r
1102 String pdbfile = null, pdbfhash = null;
\r
1103 // model was probably loaded inline - so check the pdb file hashcode
\r
1106 // calculate essential attributes for the pdb data imported inline.
\r
1107 // prolly need to resolve modelnumber properly - for now just use our
\r
1109 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
\r
1111 pdbfhash = "" + pdbfile.hashCode();
\r
1113 if (pdbentry != null)
\r
1115 // search pdbentries and sequences to find correct pdbentry for this
\r
1117 for (int pe = 0; pe < pdbentry.length; pe++)
\r
1119 boolean matches = false;
\r
1120 if (fileName == null)
\r
1123 // see JAL-623 - need method of matching pasted data up
\r
1125 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
\r
1126 AppletFormatAdapter.PASTE);
\r
1127 pdbentry[modelnum].setFile("INLINE" + pdb.id);
\r
1129 foundEntry = true;
\r
1135 if (matches = (fl=new File(pdbentry[pe].getFile())).equals(new File(fileName)))
\r
1137 foundEntry = true;
\r
1138 // TODO: Jmol can in principle retrieve from CLASSLOADER but
\r
1141 // to be tested. See mantis bug
\r
1142 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
\r
1143 String protocol = AppletFormatAdapter.URL;
\r
1148 protocol = AppletFormatAdapter.FILE;
\r
1150 } catch (Exception e)
\r
1155 //Explicitly map to the filename used by Jmol ;
\r
1156 pdb = ssm.setMapping(sequence[pe], chains[pe],
\r
1157 fileName, protocol);
\r
1158 //pdbentry[pe].getFile(), protocol);
\r
1164 // add an entry for every chain in the model
\r
1165 for (int i = 0; i < pdb.chains.size(); i++)
\r
1167 String chid = new String(pdb.id + ":"
\r
1168 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
\r
1169 chainFile.put(chid, fileName);
\r
1170 chainNames.addElement(chid);
\r
1172 notifyLoaded = true;
\r
1176 if (!foundEntry && associateNewStructs)
\r
1178 // this is a foreign pdb file that jalview doesn't know about - add
\r
1179 // it to the dataset and try to find a home - either on a matching
\r
1180 // sequence or as a new sequence.
\r
1181 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
\r
1183 // parse pdb file into a chain, etc.
\r
1184 // locate best match for pdb in associated views and add mapping to
\r
1186 // if properly registered then
\r
1187 notifyLoaded = true;
\r
1192 // so finally, update the jmol bits and pieces
\r
1193 if (jmolpopup != null)
\r
1195 // potential for deadlock here:
\r
1196 // jmolpopup.updateComputedMenus();
\r
1198 if (!isLoadingFromArchive())
\r
1200 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
\r
1202 // register ourselves as a listener and notify the gui that it needs to
\r
1204 ssm.addStructureViewerListener(this);
\r
1207 FeatureRenderer fr = getFeatureRenderer(null);
\r
1210 fr.featuresAdded();
\r
1213 loadNotifiesHandled++;
\r
1215 setLoadingFromArchive(false);
\r
1218 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
\r
1220 notifyAtomPicked(iatom, strMeasure, null);
\r
1223 public abstract void notifyScriptTermination(String strStatus,
\r
1227 * display a message echoed from the jmol viewer
\r
1231 public abstract void sendConsoleEcho(String strEcho); /*
\r
1232 * { showConsole(true);
\r
1234 * history.append("\n" +
\r
1238 // /End JmolStatusListener
\r
1239 // /////////////////////////////
\r
1242 * @param strStatus
\r
1243 * status message - usually the response received after a script
\r
1246 public abstract void sendConsoleMessage(String strStatus);
\r
1248 public void setCallbackFunction(String callbackType,
\r
1249 String callbackFunction)
\r
1251 System.err.println("Ignoring set-callback request to associate "
\r
1252 + callbackType + " with function " + callbackFunction);
\r
1256 public void setJalviewColourScheme(ColourSchemeI cs)
\r
1258 colourBySequence = false;
\r
1266 jmolHistory(false);
\r
1267 // TODO: Switch between nucleotide or aa selection expressions
\r
1268 Enumeration en = ResidueProperties.aa3Hash.keys();
\r
1269 StringBuffer command = new StringBuffer("select *;color white;");
\r
1270 while (en.hasMoreElements())
\r
1272 res = en.nextElement().toString();
\r
1273 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
\r
1277 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
\r
1279 command.append("select " + res + ";color[" + col.getRed() + ","
\r
1280 + col.getGreen() + "," + col.getBlue() + "];");
\r
1283 evalStateCommand(command.toString());
\r
1284 jmolHistory(true);
\r
1287 public void showHelp()
\r
1289 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
\r
1293 * open the URL somehow
\r
1297 public abstract void showUrl(String url, String target);
\r
1300 * called when the binding thinks the UI needs to be refreshed after a Jmol
\r
1301 * state change. this could be because structures were loaded, or because an
\r
1302 * error has occured.
\r
1304 public abstract void refreshGUI();
\r
1307 * called to show or hide the associated console window container.
\r
1311 public abstract void showConsole(boolean show);
\r
1314 * @param renderPanel
\r
1315 * @param jmolfileio
\r
1316 * - when true will initialise jmol's file IO system (should be false
\r
1317 * in applet context)
\r
1319 * @param documentBase
\r
1321 * @param commandOptions
\r
1323 public void allocateViewer(Container renderPanel, boolean jmolfileio,
\r
1324 String htmlName, URL documentBase, URL codeBase,
\r
1325 String commandOptions)
\r
1327 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
\r
1328 codeBase, commandOptions, null, null);
\r
1333 * @param renderPanel
\r
1334 * @param jmolfileio
\r
1335 * - when true will initialise jmol's file IO system (should be false
\r
1336 * in applet context)
\r
1338 * @param documentBase
\r
1340 * @param commandOptions
\r
1341 * @param consolePanel
\r
1342 * - panel to contain Jmol console
\r
1343 * @param buttonsToShow
\r
1344 * - buttons to show on the console, in ordr
\r
1346 public void allocateViewer(Container renderPanel, boolean jmolfileio,
\r
1347 String htmlName, URL documentBase, URL codeBase,
\r
1348 String commandOptions, final Container consolePanel,
\r
1349 String buttonsToShow)
\r
1351 if (commandOptions==null) {
1354 viewer = JmolViewer.allocateViewer(renderPanel,
\r
1355 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
\r
1356 + ((Object) this).toString(), documentBase, codeBase,
\r
1357 commandOptions, this);
\r
1359 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
\r
1360 if (consolePanel != null)
\r
1362 consolePanel.addComponentListener(this);
\r
1368 protected abstract JmolAppConsoleInterface createJmolConsole(
\r
1369 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
\r
1371 protected org.jmol.api.JmolAppConsoleInterface console = null;
\r
1373 public void componentResized(ComponentEvent e)
\r
1378 public void componentMoved(ComponentEvent e)
\r
1383 public void componentShown(ComponentEvent e)
\r
1385 showConsole(true);
\r
1388 public void componentHidden(ComponentEvent e)
\r
1390 showConsole(false);
\r
1393 public void setLoadingFromArchive(boolean loadingFromArchive)
\r
1395 this.loadingFromArchive = loadingFromArchive;
\r
1398 public boolean isLoadingFromArchive()
\r
1400 return loadingFromArchive;
\r
1403 public void setBackgroundColour(java.awt.Color col)
\r
1405 jmolHistory(false);
\r
1406 viewer.evalStringQuiet("background [" + col.getRed() + ","
\r
1407 + col.getGreen() + "," + col.getBlue() + "];");
\r
1408 jmolHistory(true);
\r
1412 * add structures and any known sequence associations
\r
1414 * @returns the pdb entries added to the current set.
\r
1416 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
\r
1417 SequenceI[][] seq, String[][] chns)
\r
1420 Vector v = new Vector();
\r
1421 Vector rtn = new Vector();
\r
1422 for (int i = 0; i < pdbentry.length; i++)
\r
1424 v.addElement(pdbentry[i]);
\r
1426 for (int i = 0; i < pdbe.length; i++)
\r
1428 int r = v.indexOf(pdbe[i]);
\r
1429 if (r == -1 || r >= pdbentry.length)
\r
1431 rtn.addElement(new int[]
\r
1433 v.addElement(pdbe[i]);
\r
1437 // just make sure the sequence/chain entries are all up to date
\r
1438 addSequenceAndChain(r, seq[i], chns[i]);
\r
1441 pdbe = new PDBEntry[v.size()];
\r
1444 if (rtn.size() > 0)
\r
1446 // expand the tied seuqence[] and string[] arrays
\r
1447 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
\r
1448 String[][] sch = new String[pdbentry.length][];
\r
1449 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
\r
1450 System.arraycopy(chains, 0, sch, 0, this.chains.length);
\r
1453 pdbe = new PDBEntry[rtn.size()];
\r
1454 for (int r = 0; r < pdbe.length; r++)
\r
1456 int[] stri = ((int[]) rtn.elementAt(r));
\r
1457 // record the pdb file as a new addition
\r
1458 pdbe[r] = pdbentry[stri[0]];
\r
1459 // and add the new sequence/chain entries
\r
1460 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
\r
1470 public void addSequence(int pe, SequenceI[] seq)
\r
1472 // add sequences to the pe'th pdbentry's seuqence set.
\r
1473 addSequenceAndChain(pe, seq, null);
\r
1476 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
\r
1478 if (pe < 0 || pe >= pdbentry.length)
\r
1481 "Implementation error - no corresponding pdbentry (for index "
\r
1482 + pe + ") to add sequences mappings to");
\r
1484 final String nullChain = "TheNullChain";
\r
1485 Vector s = new Vector();
\r
1486 Vector c = new Vector();
\r
1487 if (chains == null)
\r
1489 chains = new String[pdbentry.length][];
\r
1491 if (sequence[pe] != null)
\r
1493 for (int i = 0; i < sequence[pe].length; i++)
\r
1495 s.addElement(sequence[pe][i]);
\r
1496 if (chains[pe] != null)
\r
1498 if (i < chains[pe].length)
\r
1500 c.addElement(chains[pe][i]);
\r
1504 c.addElement(nullChain);
\r
1509 if (tchain != null && tchain.length > 0)
\r
1511 c.addElement(nullChain);
\r
1516 for (int i = 0; i < seq.length; i++)
\r
1518 if (!s.contains(seq[i]))
\r
1520 s.addElement(seq[i]);
\r
1521 if (tchain != null && i < tchain.length)
\r
1523 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
\r
1527 SequenceI[] tmp = new SequenceI[s.size()];
\r
1529 sequence[pe] = tmp;
\r
1532 String[] tch = new String[c.size()];
\r
1534 for (int i = 0; i < tch.length; i++)
\r
1536 if (tch[i] == nullChain)
\r
1545 chains[pe] = null;
\r
1551 * @return text report of alignment between pdbfile and any associated alignment sequences
\r
1553 public String printMapping(String pdbfile)
\r
1555 return ssm.printMapping(pdbfile);
\r
1558 public void resizeInnerPanel(String data)
\r
1560 // Jalview doesn't honour resize panel requests
\r