2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
\r
3 * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, 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
360 // RACE CONDITION - getMapping only returns Jmol loaded filenames once Jmol callback has completed.
\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 String m=viewer.getModelFileName(0);
\r
696 mset[0] = new File(m).getAbsolutePath();
\r
698 for (int i = 1; i < mset.length; i++)
\r
700 m=viewer.getModelFileName(i);
\r
702 mset[j] = new File(m).getAbsolutePath();
\r
704 _modelFileNameMap[j] = i; // record the model index for the filename
\r
705 // skip any additional models in the same file (NMR structures)
\r
706 if ((mset[j] == null ? mset[j] != mset[j - 1]
\r
707 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
\r
712 modelFileNames = new String[j];
\r
713 System.arraycopy(mset, 0, modelFileNames, 0, j);
\r
715 return modelFileNames;
\r
719 * map from string to applet
\r
721 public Map getRegistryInfo()
\r
723 // TODO Auto-generated method stub
\r
728 * returns the current sequenceRenderer that should be used to colour the
\r
735 public abstract SequenceRenderer getSequenceRenderer(
\r
736 AlignmentViewPanel alignment);
\r
738 // ///////////////////////////////
\r
739 // JmolStatusListener
\r
741 public void handlePopupMenu(int x, int y)
\r
743 jmolpopup.show(x, y);
\r
747 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
\r
750 if (modelFileNames == null)
\r
755 // look up file model number for this pdbfile
\r
758 // may need to adjust for URLencoding here - we don't worry about that yet.
\r
759 while (mdlNum < modelFileNames.length
\r
760 && !pdbfile.equals(modelFileNames[mdlNum]))
\r
762 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
\r
765 if (mdlNum == modelFileNames.length)
\r
770 jmolHistory(false);
\r
771 // if (!pdbfile.equals(pdbentry.getFile()))
\r
773 if (resetLastRes.length() > 0)
\r
775 viewer.evalStringQuiet(resetLastRes.toString());
\r
779 eval.append("select " + pdbResNum); // +modelNum
\r
781 resetLastRes.setLength(0);
\r
782 resetLastRes.append("select " + pdbResNum); // +modelNum
\r
785 resetLastRes.append(":");
\r
786 if (!chain.equals(" "))
\r
788 eval.append(chain);
\r
789 resetLastRes.append(chain);
\r
792 eval.append(" /" + (mdlNum + 1));
\r
793 resetLastRes.append("/" + (mdlNum + 1));
\r
795 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
\r
797 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
\r
798 + " and not hetero; spacefill 0;");
\r
800 eval.append("spacefill 200;select none");
\r
802 viewer.evalStringQuiet(eval.toString());
\r
807 boolean debug = true;
\r
809 private void jmolHistory(boolean enable)
\r
811 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
\r
814 public void loadInline(String string)
\r
816 loadedInline = true;
\r
817 // TODO: re JAL-623
\r
818 // viewer.loadInline(strModel, isAppend);
\r
820 // construct fake fullPathName and fileName so we can identify the file
\r
822 // Then, construct pass a reader for the string to Jmol.
\r
823 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
\r
824 // fileName, null, reader, false, null, null, 0);
\r
825 viewer.openStringInline(string);
\r
828 public void mouseOverStructure(int atomIndex, String strInfo)
\r
831 int alocsep = strInfo.indexOf("^");
\r
832 int mdlSep = strInfo.indexOf("/");
\r
833 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
\r
835 if (chainSeparator == -1)
\r
837 chainSeparator = strInfo.indexOf(".");
\r
838 if (mdlSep > -1 && mdlSep < chainSeparator)
\r
840 chainSeparator1 = chainSeparator;
\r
841 chainSeparator = mdlSep;
\r
844 // handle insertion codes
\r
847 pdbResNum = Integer.parseInt(strInfo.substring(
\r
848 strInfo.indexOf("]") + 1, alocsep));
\r
853 pdbResNum = Integer.parseInt(strInfo.substring(
\r
854 strInfo.indexOf("]") + 1, chainSeparator));
\r
858 if (strInfo.indexOf(":") > -1)
\r
859 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
\r
860 strInfo.indexOf("."));
\r
866 String pdbfilename = modelFileNames[frameNo]; // default is first or current
\r
870 if (chainSeparator1 == -1)
\r
872 chainSeparator1 = strInfo.indexOf(".", mdlSep);
\r
874 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
\r
875 chainSeparator1) : strInfo.substring(mdlSep + 1);
\r
878 // recover PDB filename for the model hovered over.
\r
879 int _mp=_modelFileNameMap.length-1,
\r
880 mnumber=new Integer(mdlId).intValue() - 1;
\r
881 while(mnumber<_modelFileNameMap[_mp])
\r
885 pdbfilename = modelFileNames[_mp];
\r
886 if (pdbfilename==null) {pdbfilename=new File(viewer
\r
887 .getModelFileName(mnumber)).getAbsolutePath();
\r
890 } catch (Exception e)
\r
895 if (lastMessage == null || !lastMessage.equals(strInfo))
\r
896 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
\r
898 lastMessage = strInfo;
\r
901 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
\r
905 System.err.println("Ignoring additional hover info: " + data
\r
906 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
\r
908 mouseOverStructure(atomIndex, strInfo);
\r
912 * { if (history != null && strStatus != null &&
\r
913 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
\r
917 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
\r
920 * this implements the toggle label behaviour copied from the original
\r
921 * structure viewer, MCView
\r
923 if (strData != null)
\r
925 System.err.println("Ignoring additional pick data string " + strData);
\r
927 int chainSeparator = strInfo.indexOf(":");
\r
929 if (chainSeparator == -1)
\r
930 chainSeparator = strInfo.indexOf(".");
\r
932 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
\r
934 String mdlString = "";
\r
935 if ((p = strInfo.indexOf(":")) > -1)
\r
936 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
\r
938 if ((p = strInfo.indexOf("/")) > -1)
\r
940 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
\r
942 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
\r
943 + mdlString + "))";
\r
944 jmolHistory(false);
\r
946 if (!atomsPicked.contains(picked))
\r
948 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
\r
949 atomsPicked.addElement(picked);
\r
953 viewer.evalString("select " + picked + ";label off");
\r
954 atomsPicked.removeElement(picked);
\r
957 // TODO: in application this happens
\r
959 // if (scriptWindow != null)
\r
961 // scriptWindow.sendConsoleMessage(strInfo);
\r
962 // scriptWindow.sendConsoleMessage("\n");
\r
968 public void notifyCallback(EnumCallback type, Object[] data)
\r
975 notifyFileLoaded((String) data[1], (String) data[2],
\r
976 (String) data[3], (String) data[4],
\r
977 ((Integer) data[5]).intValue());
\r
981 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
\r
983 // also highlight in alignment
\r
985 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
\r
989 notifyScriptTermination((String) data[2],
\r
990 ((Integer) data[3]).intValue());
\r
993 sendConsoleEcho((String) data[1]);
\r
996 sendConsoleMessage((data == null) ? ((String) null)
\r
997 : (String) data[1]);
\r
1000 // System.err.println("Ignoring error callback.");
\r
1010 System.err.println("Unhandled callback " + type + " "
\r
1011 + data[1].toString());
\r
1014 } catch (Exception e)
\r
1016 System.err.println("Squashed Jmol callback handler error:");
\r
1017 e.printStackTrace();
\r
1022 public boolean notifyEnabled(EnumCallback callbackPick)
\r
1024 switch (callbackPick)
\r
1039 case MINIMIZATION:
\r
1044 // incremented every time a load notification is successfully handled -
\r
1045 // lightweight mechanism for other threads to detect when they can start
\r
1046 // referrring to new structures.
\r
1047 private long loadNotifiesHandled = 0;
\r
1049 public long getLoadNotifiesHandled()
\r
1051 return loadNotifiesHandled;
\r
1054 public void notifyFileLoaded(String fullPathName, String fileName2,
\r
1055 String modelName, String errorMsg, int modelParts)
\r
1057 if (errorMsg != null)
\r
1059 fileLoadingError = errorMsg;
\r
1063 // TODO: deal sensibly with models loaded inLine:
\r
1064 // modelName will be null, as will fullPathName.
\r
1066 // the rest of this routine ignores the arguments, and simply interrogates
\r
1067 // the Jmol view to find out what structures it contains, and adds them to
\r
1068 // the structure selection manager.
\r
1069 fileLoadingError = null;
\r
1070 String[] oldmodels = modelFileNames;
\r
1071 modelFileNames = null;
\r
1072 chainNames = new Vector();
\r
1073 chainFile = new Hashtable();
\r
1074 boolean notifyLoaded = false;
\r
1075 String[] modelfilenames = getPdbFile();
\r
1076 // first check if we've lost any structures
\r
1077 if (oldmodels != null && oldmodels.length > 0)
\r
1080 for (int i = 0; i < oldmodels.length; i++)
\r
1082 for (int n = 0; n < modelfilenames.length; n++)
\r
1084 if (modelfilenames[n] == oldmodels[i])
\r
1086 oldmodels[i] = null;
\r
1090 if (oldmodels[i] != null)
\r
1097 String[] oldmfn = new String[oldm];
\r
1099 for (int i = 0; i < oldmodels.length; i++)
\r
1101 if (oldmodels[i] != null)
\r
1103 oldmfn[oldm++] = oldmodels[i];
\r
1106 // deregister the Jmol instance for these structures - we'll add
\r
1107 // ourselves again at the end for the current structure set.
\r
1108 ssm.removeStructureViewerListener(this, oldmfn);
\r
1111 refreshPdbEntries();
\r
1112 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
\r
1114 String fileName = modelfilenames[modelnum];
\r
1115 boolean foundEntry = false;
\r
1116 MCview.PDBfile pdb = null;
\r
1117 String pdbfile = null, pdbfhash = null;
\r
1118 // model was probably loaded inline - so check the pdb file hashcode
\r
1121 // calculate essential attributes for the pdb data imported inline.
\r
1122 // prolly need to resolve modelnumber properly - for now just use our
\r
1124 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
\r
1126 pdbfhash = "" + pdbfile.hashCode();
\r
1128 if (pdbentry != null)
\r
1130 // search pdbentries and sequences to find correct pdbentry for this
\r
1132 for (int pe = 0; pe < pdbentry.length; pe++)
\r
1134 boolean matches = false;
\r
1135 if (fileName == null)
\r
1138 // see JAL-623 - need method of matching pasted data up
\r
1140 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
\r
1141 AppletFormatAdapter.PASTE);
\r
1142 pdbentry[modelnum].setFile("INLINE" + pdb.id);
\r
1144 foundEntry = true;
\r
1150 if (matches = (fl=new File(pdbentry[pe].getFile())).equals(new File(fileName)))
\r
1152 foundEntry = true;
\r
1153 // TODO: Jmol can in principle retrieve from CLASSLOADER but
\r
1156 // to be tested. See mantis bug
\r
1157 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
\r
1158 String protocol = AppletFormatAdapter.URL;
\r
1163 protocol = AppletFormatAdapter.FILE;
\r
1165 } catch (Exception e)
\r
1170 //Explicitly map to the filename used by Jmol ;
\r
1171 pdb = ssm.setMapping(sequence[pe], chains[pe],
\r
1172 fileName, protocol);
\r
1173 //pdbentry[pe].getFile(), protocol);
\r
1179 // add an entry for every chain in the model
\r
1180 for (int i = 0; i < pdb.chains.size(); i++)
\r
1182 String chid = new String(pdb.id + ":"
\r
1183 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
\r
1184 chainFile.put(chid, fileName);
\r
1185 chainNames.addElement(chid);
\r
1187 notifyLoaded = true;
\r
1191 if (!foundEntry && associateNewStructs)
\r
1193 // this is a foreign pdb file that jalview doesn't know about - add
\r
1194 // it to the dataset and try to find a home - either on a matching
\r
1195 // sequence or as a new sequence.
\r
1196 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
\r
1198 // parse pdb file into a chain, etc.
\r
1199 // locate best match for pdb in associated views and add mapping to
\r
1201 // if properly registered then
\r
1202 notifyLoaded = true;
\r
1207 // so finally, update the jmol bits and pieces
\r
1208 if (jmolpopup != null)
\r
1210 // potential for deadlock here:
\r
1211 // jmolpopup.updateComputedMenus();
\r
1213 if (!isLoadingFromArchive())
\r
1215 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
\r
1217 // register ourselves as a listener and notify the gui that it needs to
\r
1219 ssm.addStructureViewerListener(this);
\r
1222 FeatureRenderer fr = getFeatureRenderer(null);
\r
1225 fr.featuresAdded();
\r
1228 loadNotifiesHandled++;
\r
1230 setLoadingFromArchive(false);
\r
1233 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
\r
1235 notifyAtomPicked(iatom, strMeasure, null);
\r
1238 public abstract void notifyScriptTermination(String strStatus,
\r
1242 * display a message echoed from the jmol viewer
\r
1246 public abstract void sendConsoleEcho(String strEcho); /*
\r
1247 * { showConsole(true);
\r
1249 * history.append("\n" +
\r
1253 // /End JmolStatusListener
\r
1254 // /////////////////////////////
\r
1257 * @param strStatus
\r
1258 * status message - usually the response received after a script
\r
1261 public abstract void sendConsoleMessage(String strStatus);
\r
1263 public void setCallbackFunction(String callbackType,
\r
1264 String callbackFunction)
\r
1266 System.err.println("Ignoring set-callback request to associate "
\r
1267 + callbackType + " with function " + callbackFunction);
\r
1271 public void setJalviewColourScheme(ColourSchemeI cs)
\r
1273 colourBySequence = false;
\r
1281 jmolHistory(false);
\r
1282 // TODO: Switch between nucleotide or aa selection expressions
\r
1283 Enumeration en = ResidueProperties.aa3Hash.keys();
\r
1284 StringBuffer command = new StringBuffer("select *;color white;");
\r
1285 while (en.hasMoreElements())
\r
1287 res = en.nextElement().toString();
\r
1288 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
\r
1292 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
\r
1294 command.append("select " + res + ";color[" + col.getRed() + ","
\r
1295 + col.getGreen() + "," + col.getBlue() + "];");
\r
1298 evalStateCommand(command.toString());
\r
1299 jmolHistory(true);
\r
1302 public void showHelp()
\r
1304 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
\r
1308 * open the URL somehow
\r
1312 public abstract void showUrl(String url, String target);
\r
1315 * called when the binding thinks the UI needs to be refreshed after a Jmol
\r
1316 * state change. this could be because structures were loaded, or because an
\r
1317 * error has occured.
\r
1319 public abstract void refreshGUI();
\r
1322 * called to show or hide the associated console window container.
\r
1326 public abstract void showConsole(boolean show);
\r
1329 * @param renderPanel
\r
1330 * @param jmolfileio
\r
1331 * - when true will initialise jmol's file IO system (should be false
\r
1332 * in applet context)
\r
1334 * @param documentBase
\r
1336 * @param commandOptions
\r
1338 public void allocateViewer(Container renderPanel, boolean jmolfileio,
\r
1339 String htmlName, URL documentBase, URL codeBase,
\r
1340 String commandOptions)
\r
1342 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
\r
1343 codeBase, commandOptions, null, null);
\r
1348 * @param renderPanel
\r
1349 * @param jmolfileio
\r
1350 * - when true will initialise jmol's file IO system (should be false
\r
1351 * in applet context)
\r
1353 * @param documentBase
\r
1355 * @param commandOptions
\r
1356 * @param consolePanel
\r
1357 * - panel to contain Jmol console
\r
1358 * @param buttonsToShow
\r
1359 * - buttons to show on the console, in ordr
\r
1361 public void allocateViewer(Container renderPanel, boolean jmolfileio,
\r
1362 String htmlName, URL documentBase, URL codeBase,
\r
1363 String commandOptions, final Container consolePanel,
\r
1364 String buttonsToShow)
\r
1366 if (commandOptions==null) {
1369 viewer = JmolViewer.allocateViewer(renderPanel,
\r
1370 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
\r
1371 + ((Object) this).toString(), documentBase, codeBase,
\r
1372 commandOptions, this);
\r
1374 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
\r
1375 if (consolePanel != null)
\r
1377 consolePanel.addComponentListener(this);
\r
1383 protected abstract JmolAppConsoleInterface createJmolConsole(
\r
1384 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
\r
1386 protected org.jmol.api.JmolAppConsoleInterface console = null;
\r
1388 public void componentResized(ComponentEvent e)
\r
1393 public void componentMoved(ComponentEvent e)
\r
1398 public void componentShown(ComponentEvent e)
\r
1400 showConsole(true);
\r
1403 public void componentHidden(ComponentEvent e)
\r
1405 showConsole(false);
\r
1408 public void setLoadingFromArchive(boolean loadingFromArchive)
\r
1410 this.loadingFromArchive = loadingFromArchive;
\r
1413 public boolean isLoadingFromArchive()
\r
1415 return loadingFromArchive;
\r
1418 public void setBackgroundColour(java.awt.Color col)
\r
1420 jmolHistory(false);
\r
1421 viewer.evalStringQuiet("background [" + col.getRed() + ","
\r
1422 + col.getGreen() + "," + col.getBlue() + "];");
\r
1423 jmolHistory(true);
\r
1427 * add structures and any known sequence associations
\r
1429 * @returns the pdb entries added to the current set.
\r
1431 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
\r
1432 SequenceI[][] seq, String[][] chns)
\r
1435 Vector v = new Vector();
\r
1436 Vector rtn = new Vector();
\r
1437 for (int i = 0; i < pdbentry.length; i++)
\r
1439 v.addElement(pdbentry[i]);
\r
1441 for (int i = 0; i < pdbe.length; i++)
\r
1443 int r = v.indexOf(pdbe[i]);
\r
1444 if (r == -1 || r >= pdbentry.length)
\r
1446 rtn.addElement(new int[]
\r
1448 v.addElement(pdbe[i]);
\r
1452 // just make sure the sequence/chain entries are all up to date
\r
1453 addSequenceAndChain(r, seq[i], chns[i]);
\r
1456 pdbe = new PDBEntry[v.size()];
\r
1459 if (rtn.size() > 0)
\r
1461 // expand the tied seuqence[] and string[] arrays
\r
1462 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
\r
1463 String[][] sch = new String[pdbentry.length][];
\r
1464 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
\r
1465 System.arraycopy(chains, 0, sch, 0, this.chains.length);
\r
1468 pdbe = new PDBEntry[rtn.size()];
\r
1469 for (int r = 0; r < pdbe.length; r++)
\r
1471 int[] stri = ((int[]) rtn.elementAt(r));
\r
1472 // record the pdb file as a new addition
\r
1473 pdbe[r] = pdbentry[stri[0]];
\r
1474 // and add the new sequence/chain entries
\r
1475 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
\r
1485 public void addSequence(int pe, SequenceI[] seq)
\r
1487 // add sequences to the pe'th pdbentry's seuqence set.
\r
1488 addSequenceAndChain(pe, seq, null);
\r
1491 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
\r
1493 if (pe < 0 || pe >= pdbentry.length)
\r
1496 "Implementation error - no corresponding pdbentry (for index "
\r
1497 + pe + ") to add sequences mappings to");
\r
1499 final String nullChain = "TheNullChain";
\r
1500 Vector s = new Vector();
\r
1501 Vector c = new Vector();
\r
1502 if (chains == null)
\r
1504 chains = new String[pdbentry.length][];
\r
1506 if (sequence[pe] != null)
\r
1508 for (int i = 0; i < sequence[pe].length; i++)
\r
1510 s.addElement(sequence[pe][i]);
\r
1511 if (chains[pe] != null)
\r
1513 if (i < chains[pe].length)
\r
1515 c.addElement(chains[pe][i]);
\r
1519 c.addElement(nullChain);
\r
1524 if (tchain != null && tchain.length > 0)
\r
1526 c.addElement(nullChain);
\r
1531 for (int i = 0; i < seq.length; i++)
\r
1533 if (!s.contains(seq[i]))
\r
1535 s.addElement(seq[i]);
\r
1536 if (tchain != null && i < tchain.length)
\r
1538 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
\r
1542 SequenceI[] tmp = new SequenceI[s.size()];
\r
1544 sequence[pe] = tmp;
\r
1547 String[] tch = new String[c.size()];
\r
1549 for (int i = 0; i < tch.length; i++)
\r
1551 if (tch[i] == nullChain)
\r
1560 chains[pe] = null;
\r
1566 * @return text report of alignment between pdbfile and any associated alignment sequences
\r
1568 public String printMapping(String pdbfile)
\r
1570 return ssm.printMapping(pdbfile);
\r
1573 public void resizeInnerPanel(String data)
\r
1575 // Jalview doesn't honour resize panel requests
\r