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
874 } catch (Exception e)
\r
879 if (lastMessage == null || !lastMessage.equals(strInfo))
\r
880 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
\r
882 lastMessage = strInfo;
\r
885 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
\r
889 System.err.println("Ignoring additional hover info: " + data
\r
890 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
\r
892 mouseOverStructure(atomIndex, strInfo);
\r
896 * { if (history != null && strStatus != null &&
\r
897 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
\r
901 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
\r
904 * this implements the toggle label behaviour copied from the original
\r
905 * structure viewer, MCView
\r
907 if (strData != null)
\r
909 System.err.println("Ignoring additional pick data string " + strData);
\r
911 int chainSeparator = strInfo.indexOf(":");
\r
913 if (chainSeparator == -1)
\r
914 chainSeparator = strInfo.indexOf(".");
\r
916 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
\r
918 String mdlString = "";
\r
919 if ((p = strInfo.indexOf(":")) > -1)
\r
920 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
\r
922 if ((p = strInfo.indexOf("/")) > -1)
\r
924 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
\r
926 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
\r
927 + mdlString + "))";
\r
928 jmolHistory(false);
\r
930 if (!atomsPicked.contains(picked))
\r
932 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
\r
933 atomsPicked.addElement(picked);
\r
937 viewer.evalString("select " + picked + ";label off");
\r
938 atomsPicked.removeElement(picked);
\r
941 // TODO: in application this happens
\r
943 // if (scriptWindow != null)
\r
945 // scriptWindow.sendConsoleMessage(strInfo);
\r
946 // scriptWindow.sendConsoleMessage("\n");
\r
952 public void notifyCallback(EnumCallback type, Object[] data)
\r
959 notifyFileLoaded((String) data[1], (String) data[2],
\r
960 (String) data[3], (String) data[4],
\r
961 ((Integer) data[5]).intValue());
\r
965 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
\r
967 // also highlight in alignment
\r
969 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
\r
973 notifyScriptTermination((String) data[2],
\r
974 ((Integer) data[3]).intValue());
\r
977 sendConsoleEcho((String) data[1]);
\r
980 sendConsoleMessage((data == null) ? ((String) null)
\r
981 : (String) data[1]);
\r
984 // System.err.println("Ignoring error callback.");
\r
994 System.err.println("Unhandled callback " + type + " "
\r
995 + data[1].toString());
\r
998 } catch (Exception e)
\r
1000 System.err.println("Squashed Jmol callback handler error:");
\r
1001 e.printStackTrace();
\r
1006 public boolean notifyEnabled(EnumCallback callbackPick)
\r
1008 switch (callbackPick)
\r
1023 case MINIMIZATION:
\r
1028 // incremented every time a load notification is successfully handled -
\r
1029 // lightweight mechanism for other threads to detect when they can start
\r
1030 // referrring to new structures.
\r
1031 private long loadNotifiesHandled = 0;
\r
1033 public long getLoadNotifiesHandled()
\r
1035 return loadNotifiesHandled;
\r
1038 public void notifyFileLoaded(String fullPathName, String fileName2,
\r
1039 String modelName, String errorMsg, int modelParts)
\r
1041 if (errorMsg != null)
\r
1043 fileLoadingError = errorMsg;
\r
1047 // TODO: deal sensibly with models loaded inLine:
\r
1048 // modelName will be null, as will fullPathName.
\r
1050 // the rest of this routine ignores the arguments, and simply interrogates
\r
1051 // the Jmol view to find out what structures it contains, and adds them to
\r
1052 // the structure selection manager.
\r
1053 fileLoadingError = null;
\r
1054 String[] oldmodels = modelFileNames;
\r
1055 modelFileNames = null;
\r
1056 chainNames = new Vector();
\r
1057 chainFile = new Hashtable();
\r
1058 boolean notifyLoaded = false;
\r
1059 String[] modelfilenames = getPdbFile();
\r
1060 // first check if we've lost any structures
\r
1061 if (oldmodels != null && oldmodels.length > 0)
\r
1064 for (int i = 0; i < oldmodels.length; i++)
\r
1066 for (int n = 0; n < modelfilenames.length; n++)
\r
1068 if (modelfilenames[n] == oldmodels[i])
\r
1070 oldmodels[i] = null;
\r
1074 if (oldmodels[i] != null)
\r
1081 String[] oldmfn = new String[oldm];
\r
1083 for (int i = 0; i < oldmodels.length; i++)
\r
1085 if (oldmodels[i] != null)
\r
1087 oldmfn[oldm++] = oldmodels[i];
\r
1090 // deregister the Jmol instance for these structures - we'll add
\r
1091 // ourselves again at the end for the current structure set.
\r
1092 ssm.removeStructureViewerListener(this, oldmfn);
\r
1095 refreshPdbEntries();
\r
1096 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
\r
1098 String fileName = modelfilenames[modelnum];
\r
1099 boolean foundEntry = false;
\r
1100 MCview.PDBfile pdb = null;
\r
1101 String pdbfile = null, pdbfhash = null;
\r
1102 // model was probably loaded inline - so check the pdb file hashcode
\r
1105 // calculate essential attributes for the pdb data imported inline.
\r
1106 // prolly need to resolve modelnumber properly - for now just use our
\r
1108 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
\r
1110 pdbfhash = "" + pdbfile.hashCode();
\r
1112 if (pdbentry != null)
\r
1114 // search pdbentries and sequences to find correct pdbentry for this
\r
1116 for (int pe = 0; pe < pdbentry.length; pe++)
\r
1118 boolean matches = false;
\r
1119 if (fileName == null)
\r
1122 // see JAL-623 - need method of matching pasted data up
\r
1124 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
\r
1125 AppletFormatAdapter.PASTE);
\r
1126 pdbentry[modelnum].setFile("INLINE" + pdb.id);
\r
1128 foundEntry = true;
\r
1133 if (matches = pdbentry[pe].getFile().equals(fileName))
\r
1135 foundEntry = true;
\r
1136 // TODO: Jmol can in principle retrieve from CLASSLOADER but
\r
1139 // to be tested. See mantis bug
\r
1140 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
\r
1141 String protocol = AppletFormatAdapter.URL;
\r
1144 File fl = new java.io.File(pdbentry[pe].getFile());
\r
1147 protocol = AppletFormatAdapter.FILE;
\r
1149 } catch (Exception e)
\r
1155 pdb = ssm.setMapping(sequence[pe], chains[pe],
\r
1156 pdbentry[pe].getFile(), protocol);
\r
1162 // add an entry for every chain in the model
\r
1163 for (int i = 0; i < pdb.chains.size(); i++)
\r
1165 String chid = new String(pdb.id + ":"
\r
1166 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
\r
1167 chainFile.put(chid, pdbentry[pe].getFile());
\r
1168 chainNames.addElement(chid);
\r
1170 notifyLoaded = true;
\r
1174 if (!foundEntry && associateNewStructs)
\r
1176 // this is a foreign pdb file that jalview doesn't know about - add
\r
1177 // it to the dataset and try to find a home - either on a matching
\r
1178 // sequence or as a new sequence.
\r
1179 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
\r
1181 // parse pdb file into a chain, etc.
\r
1182 // locate best match for pdb in associated views and add mapping to
\r
1184 // if properly registered then
\r
1185 notifyLoaded = true;
\r
1190 // so finally, update the jmol bits and pieces
\r
1191 if (jmolpopup != null)
\r
1193 // potential for deadlock here:
\r
1194 // jmolpopup.updateComputedMenus();
\r
1196 if (!isLoadingFromArchive())
\r
1198 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
\r
1200 // register ourselves as a listener and notify the gui that it needs to
\r
1202 ssm.addStructureViewerListener(this);
\r
1205 FeatureRenderer fr = getFeatureRenderer(null);
\r
1208 fr.featuresAdded();
\r
1211 loadNotifiesHandled++;
\r
1213 setLoadingFromArchive(false);
\r
1216 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
\r
1218 notifyAtomPicked(iatom, strMeasure, null);
\r
1221 public abstract void notifyScriptTermination(String strStatus,
\r
1225 * display a message echoed from the jmol viewer
\r
1229 public abstract void sendConsoleEcho(String strEcho); /*
\r
1230 * { showConsole(true);
\r
1232 * history.append("\n" +
\r
1236 // /End JmolStatusListener
\r
1237 // /////////////////////////////
\r
1240 * @param strStatus
\r
1241 * status message - usually the response received after a script
\r
1244 public abstract void sendConsoleMessage(String strStatus);
\r
1246 public void setCallbackFunction(String callbackType,
\r
1247 String callbackFunction)
\r
1249 System.err.println("Ignoring set-callback request to associate "
\r
1250 + callbackType + " with function " + callbackFunction);
\r
1254 public void setJalviewColourScheme(ColourSchemeI cs)
\r
1256 colourBySequence = false;
\r
1264 jmolHistory(false);
\r
1265 // TODO: Switch between nucleotide or aa selection expressions
\r
1266 Enumeration en = ResidueProperties.aa3Hash.keys();
\r
1267 StringBuffer command = new StringBuffer("select *;color white;");
\r
1268 while (en.hasMoreElements())
\r
1270 res = en.nextElement().toString();
\r
1271 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
\r
1275 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
\r
1277 command.append("select " + res + ";color[" + col.getRed() + ","
\r
1278 + col.getGreen() + "," + col.getBlue() + "];");
\r
1281 evalStateCommand(command.toString());
\r
1282 jmolHistory(true);
\r
1285 public void showHelp()
\r
1287 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
\r
1291 * open the URL somehow
\r
1295 public abstract void showUrl(String url, String target);
\r
1298 * called when the binding thinks the UI needs to be refreshed after a Jmol
\r
1299 * state change. this could be because structures were loaded, or because an
\r
1300 * error has occured.
\r
1302 public abstract void refreshGUI();
\r
1305 * called to show or hide the associated console window container.
\r
1309 public abstract void showConsole(boolean show);
\r
1312 * @param renderPanel
\r
1313 * @param jmolfileio
\r
1314 * - when true will initialise jmol's file IO system (should be false
\r
1315 * in applet context)
\r
1317 * @param documentBase
\r
1319 * @param commandOptions
\r
1321 public void allocateViewer(Container renderPanel, boolean jmolfileio,
\r
1322 String htmlName, URL documentBase, URL codeBase,
\r
1323 String commandOptions)
\r
1325 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
\r
1326 codeBase, commandOptions, null, null);
\r
1331 * @param renderPanel
\r
1332 * @param jmolfileio
\r
1333 * - when true will initialise jmol's file IO system (should be false
\r
1334 * in applet context)
\r
1336 * @param documentBase
\r
1338 * @param commandOptions
\r
1339 * @param consolePanel
\r
1340 * - panel to contain Jmol console
\r
1341 * @param buttonsToShow
\r
1342 * - buttons to show on the console, in ordr
\r
1344 public void allocateViewer(Container renderPanel, boolean jmolfileio,
\r
1345 String htmlName, URL documentBase, URL codeBase,
\r
1346 String commandOptions, final Container consolePanel,
\r
1347 String buttonsToShow)
\r
1349 if (commandOptions==null) {
1352 viewer = JmolViewer.allocateViewer(renderPanel,
\r
1353 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
\r
1354 + ((Object) this).toString(), documentBase, codeBase,
\r
1355 commandOptions, this);
\r
1357 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
\r
1358 if (consolePanel != null)
\r
1360 consolePanel.addComponentListener(this);
\r
1366 protected abstract JmolAppConsoleInterface createJmolConsole(
\r
1367 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
\r
1369 protected org.jmol.api.JmolAppConsoleInterface console = null;
\r
1371 public void componentResized(ComponentEvent e)
\r
1376 public void componentMoved(ComponentEvent e)
\r
1381 public void componentShown(ComponentEvent e)
\r
1383 showConsole(true);
\r
1386 public void componentHidden(ComponentEvent e)
\r
1388 showConsole(false);
\r
1391 public void setLoadingFromArchive(boolean loadingFromArchive)
\r
1393 this.loadingFromArchive = loadingFromArchive;
\r
1396 public boolean isLoadingFromArchive()
\r
1398 return loadingFromArchive;
\r
1401 public void setBackgroundColour(java.awt.Color col)
\r
1403 jmolHistory(false);
\r
1404 viewer.evalStringQuiet("background [" + col.getRed() + ","
\r
1405 + col.getGreen() + "," + col.getBlue() + "];");
\r
1406 jmolHistory(true);
\r
1410 * add structures and any known sequence associations
\r
1412 * @returns the pdb entries added to the current set.
\r
1414 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
\r
1415 SequenceI[][] seq, String[][] chns)
\r
1418 Vector v = new Vector();
\r
1419 Vector rtn = new Vector();
\r
1420 for (int i = 0; i < pdbentry.length; i++)
\r
1422 v.addElement(pdbentry[i]);
\r
1424 for (int i = 0; i < pdbe.length; i++)
\r
1426 int r = v.indexOf(pdbe[i]);
\r
1427 if (r == -1 || r >= pdbentry.length)
\r
1429 rtn.addElement(new int[]
\r
1431 v.addElement(pdbe[i]);
\r
1435 // just make sure the sequence/chain entries are all up to date
\r
1436 addSequenceAndChain(r, seq[i], chns[i]);
\r
1439 pdbe = new PDBEntry[v.size()];
\r
1442 if (rtn.size() > 0)
\r
1444 // expand the tied seuqence[] and string[] arrays
\r
1445 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
\r
1446 String[][] sch = new String[pdbentry.length][];
\r
1447 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
\r
1448 System.arraycopy(chains, 0, sch, 0, this.chains.length);
\r
1451 pdbe = new PDBEntry[rtn.size()];
\r
1452 for (int r = 0; r < pdbe.length; r++)
\r
1454 int[] stri = ((int[]) rtn.elementAt(r));
\r
1455 // record the pdb file as a new addition
\r
1456 pdbe[r] = pdbentry[stri[0]];
\r
1457 // and add the new sequence/chain entries
\r
1458 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
\r
1468 public void addSequence(int pe, SequenceI[] seq)
\r
1470 // add sequences to the pe'th pdbentry's seuqence set.
\r
1471 addSequenceAndChain(pe, seq, null);
\r
1474 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
\r
1476 if (pe < 0 || pe >= pdbentry.length)
\r
1479 "Implementation error - no corresponding pdbentry (for index "
\r
1480 + pe + ") to add sequences mappings to");
\r
1482 final String nullChain = "TheNullChain";
\r
1483 Vector s = new Vector();
\r
1484 Vector c = new Vector();
\r
1485 if (chains == null)
\r
1487 chains = new String[pdbentry.length][];
\r
1489 if (sequence[pe] != null)
\r
1491 for (int i = 0; i < sequence[pe].length; i++)
\r
1493 s.addElement(sequence[pe][i]);
\r
1494 if (chains[pe] != null)
\r
1496 if (i < chains[pe].length)
\r
1498 c.addElement(chains[pe][i]);
\r
1502 c.addElement(nullChain);
\r
1507 if (tchain != null && tchain.length > 0)
\r
1509 c.addElement(nullChain);
\r
1514 for (int i = 0; i < seq.length; i++)
\r
1516 if (!s.contains(seq[i]))
\r
1518 s.addElement(seq[i]);
\r
1519 if (tchain != null && i < tchain.length)
\r
1521 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
\r
1525 SequenceI[] tmp = new SequenceI[s.size()];
\r
1527 sequence[pe] = tmp;
\r
1530 String[] tch = new String[c.size()];
\r
1532 for (int i = 0; i < tch.length; i++)
\r
1534 if (tch[i] == nullChain)
\r
1543 chains[pe] = null;
\r
1549 * @return text report of alignment between pdbfile and any associated alignment sequences
\r
1551 public String printMapping(String pdbfile)
\r
1553 return ssm.printMapping(pdbfile);
\r
1556 public void resizeInnerPanel(String data)
\r
1558 // Jalview doesn't honour resize panel requests
\r