2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
\r
3 * Copyright (C) 2010 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 java.io.File;
\r
21 import java.net.URL;
\r
23 import java.applet.Applet;
\r
25 import java.awt.event.*;
\r
27 import javax.swing.JPanel;
\r
29 import jalview.api.AlignmentViewPanel;
\r
30 import jalview.api.FeatureRenderer;
\r
31 import jalview.api.SequenceRenderer;
\r
32 import jalview.api.SequenceStructureBinding;
\r
33 import jalview.datamodel.*;
\r
34 import jalview.structure.*;
\r
35 import jalview.io.*;
\r
37 import org.jmol.api.*;
\r
38 import org.jmol.adapter.smarter.SmarterJmolAdapter;
\r
40 import org.jmol.popup.*;
\r
41 import org.jmol.viewer.JmolConstants;
\r
42 import org.jmol.viewer.Viewer;
\r
44 import jalview.schemes.*;
\r
46 public abstract class JalviewJmolBinding implements StructureListener,
\r
47 JmolStatusListener, SequenceStructureBinding,
\r
48 JmolSelectionListener, ComponentListener
\r
52 * set if Jmol state is being restored from some source - instructs binding
\r
53 * not to apply default display style when structure set is updated for first
\r
56 private boolean loadingFromArchive = false;
\r
59 * state flag used to check if the Jmol viewer's paint method can be called
\r
61 private boolean finishedInit = false;
\r
63 public boolean isFinishedInit()
\r
65 return finishedInit;
\r
68 public void setFinishedInit(boolean finishedInit)
\r
70 this.finishedInit = finishedInit;
\r
73 boolean allChainsSelected = false;
\r
76 * when true, try to search the associated datamodel for sequences that are
\r
77 * associated with any unknown structures in the Jmol view.
\r
79 private boolean associateNewStructs = false;
\r
81 Vector atomsPicked = new Vector();
\r
83 public Vector chainNames;
\r
85 Hashtable chainFile;
\r
88 * array of target chains for seuqences - tied to pdbentry and sequence[]
\r
90 protected String[][] chains;
\r
92 boolean colourBySequence = true;
\r
94 StringBuffer eval = new StringBuffer();
\r
96 public String fileLoadingError;
\r
99 * the default or current model displayed if the model cannot be identified
\r
100 * from the selection message
\r
104 protected JmolPopup jmolpopup;
\r
106 String lastCommand;
\r
108 String lastMessage;
\r
110 boolean loadedInline;
\r
113 * current set of model filenames loaded in the Jmol instance
\r
115 String[] modelFileNames = null;
\r
117 public PDBEntry[] pdbentry;
\r
120 * datasource protocol for access to PDBEntrylatest
\r
122 String protocol = null;
\r
124 StringBuffer resetLastRes = new StringBuffer();
\r
127 * sequences mapped to each pdbentry
\r
129 public SequenceI[][] sequence;
\r
131 StructureSelectionManager ssm;
\r
133 public JmolViewer viewer;
\r
135 public JalviewJmolBinding(PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
\r
136 String[][] chains, String protocol)
\r
138 this.sequence = sequenceIs;
\r
139 this.chains = chains;
\r
140 this.pdbentry = pdbentry;
\r
141 this.protocol = protocol;
\r
142 if (chains == null)
\r
144 this.chains = new String[pdbentry.length][];
\r
147 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
\r
148 * "jalviewJmol", ap.av.applet .getDocumentBase(),
\r
149 * ap.av.applet.getCodeBase(), "", this);
\r
151 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
\r
155 public JalviewJmolBinding(JmolViewer viewer2)
\r
158 viewer.setJmolStatusListener(this);
\r
159 viewer.addSelectionListener(this);
\r
163 * construct a title string for the viewer window based on the data jalview
\r
168 public String getViewerTitle()
\r
170 if (sequence == null || pdbentry == null || sequence.length < 1
\r
171 || pdbentry.length < 1 || sequence[0].length < 1)
\r
173 return ("Jalview Jmol Window");
\r
175 // TODO: give a more informative title when multiple structures are
\r
177 StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
\r
178 + pdbentry[0].getId());
\r
180 if (pdbentry[0].getProperty() != null)
\r
182 if (pdbentry[0].getProperty().get("method") != null)
\r
184 title.append(" Method: ");
\r
185 title.append(pdbentry[0].getProperty().get("method"));
\r
187 if (pdbentry[0].getProperty().get("chains") != null)
\r
189 title.append(" Chain:");
\r
190 title.append(pdbentry[0].getProperty().get("chains"));
\r
193 return title.toString();
\r
197 * prepare the view for a given set of models/chains. chainList contains
\r
198 * strings of the form 'pdbfilename:Chaincode'
\r
201 * list of chains to make visible
\r
203 public void centerViewer(Vector chainList)
\r
205 StringBuffer cmd = new StringBuffer();
\r
208 for (int i = 0, iSize = chainList.size(); i < iSize; i++)
\r
211 lbl = (String) chainList.elementAt(i);
\r
215 mlength = lbl.indexOf(":", p);
\r
216 } while (p < mlength && mlength < (lbl.length() - 2));
\r
217 // TODO: lookup each pdb id and recover proper model number for it.
\r
218 cmd.append(":" + lbl.substring(mlength + 1) + " /"
\r
219 + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");
\r
221 if (cmd.length() > 0)
\r
222 cmd.setLength(cmd.length() - 4);
\r
223 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
\r
226 public void closeViewer()
\r
228 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
\r
229 // remove listeners for all structures in viewer
\r
230 StructureSelectionManager.getStructureSelectionManager()
\r
231 .removeStructureViewerListener(this, this.getPdbFile());
\r
232 // and shut down jmol
\r
233 viewer.evalStringQuiet("zap");
\r
234 viewer.setJmolStatusListener(null);
\r
235 lastCommand = null;
\r
237 releaseUIResources();
\r
241 * called by JalviewJmolbinding after closeViewer is called - release any
\r
242 * resources and references so they can be garbage collected.
\r
244 protected abstract void releaseUIResources();
\r
246 public void colourByChain()
\r
248 colourBySequence = false;
\r
249 // TODO: colour by chain should colour each chain distinctly across all
\r
251 // TODO: http://issues.jalview.org/browse/JAL-628
\r
252 evalStateCommand("select *;color chain");
\r
255 public void colourByCharge()
\r
257 colourBySequence = false;
\r
258 evalStateCommand("select *;color white;select ASP,GLU;color red;"
\r
259 + "select LYS,ARG;color blue;select CYS;color yellow");
\r
263 * superpose the structures associated with sequences in the alignment
\r
264 * according to their corresponding positions.
\r
266 public void superposeStructures(AlignmentI alignment)
\r
268 superposeStructures(alignment, -1, null);
\r
272 * superpose the structures associated with sequences in the alignment
\r
273 * according to their corresponding positions. ded)
\r
275 * @param refStructure
\r
276 * - select which pdb file to use as reference (default is -1 - the
\r
277 * first structure in the alignment)
\r
279 public void superposeStructures(AlignmentI alignment, int refStructure)
\r
281 superposeStructures(alignment, refStructure, null);
\r
285 * superpose the structures associated with sequences in the alignment
\r
286 * according to their corresponding positions. ded)
\r
288 * @param refStructure
\r
289 * - select which pdb file to use as reference (default is -1 - the
\r
290 * first structure in the alignment)
\r
291 * @param hiddenCols
\r
294 public void superposeStructures(AlignmentI alignment, int refStructure,
\r
295 ColumnSelection hiddenCols)
\r
297 superposeStructures(new AlignmentI[]
\r
298 { alignment }, new int[]
\r
299 { refStructure }, new ColumnSelection[]
\r
303 public void superposeStructures(AlignmentI[] _alignment,
\r
304 int[] _refStructure, ColumnSelection[] _hiddenCols)
\r
306 String[] files = getPdbFile();
\r
307 StringBuffer selectioncom = new StringBuffer();
\r
308 assert (_alignment.length == _refStructure.length && _alignment.length != _hiddenCols.length);
\r
309 // union of all aligned positions are collected together.
\r
310 for (int a = 0; a < _alignment.length; a++)
\r
312 int refStructure = _refStructure[a];
\r
313 AlignmentI alignment = _alignment[a];
\r
314 ColumnSelection hiddenCols = _hiddenCols[a];
\r
316 && selectioncom.length() > 0
\r
317 && !selectioncom.substring(selectioncom.length() - 1).equals(
\r
320 selectioncom.append("|");
\r
322 // process this alignment
\r
323 if (refStructure >= files.length)
\r
325 System.err.println("Invalid reference structure value "
\r
329 if (refStructure < -1)
\r
333 StringBuffer command = new StringBuffer();
\r
335 boolean matched[] = new boolean[alignment.getWidth()];
\r
336 for (int m = 0; m < matched.length; m++)
\r
339 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
\r
342 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
\r
343 String isel[] = new String[files.length];
\r
344 // reference structure - all others are superposed in it
\r
345 String[] targetC = new String[files.length];
\r
346 String[] chainNames = new String[files.length];
\r
347 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
\r
349 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
\r
351 if (mapping == null || mapping.length < 1)
\r
355 for (int s = 0; s < sequence[pdbfnum].length; s++)
\r
357 for (int sp, m = 0; m < mapping.length; m++)
\r
359 if (mapping[m].getSequence() == sequence[pdbfnum][s]
\r
360 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
\r
362 if (refStructure == -1)
\r
364 refStructure = pdbfnum;
\r
366 SequenceI asp = alignment.getSequenceAt(sp);
\r
367 for (int r = 0; r < matched.length; r++)
\r
373 matched[r] = false; // assume this is not a good site
\r
374 if (r >= asp.getLength())
\r
379 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
\r
381 // no mapping to gaps in sequence
\r
384 int t = asp.findPosition(r); // sequence position
\r
385 int apos = mapping[m].getAtomNum(t);
\r
386 int pos = mapping[m].getPDBResNum(t);
\r
388 if (pos < 1 || pos == lastPos)
\r
390 // can't align unmapped sequence
\r
393 matched[r] = true; // this is a good ite
\r
395 // just record this residue position
\r
396 commonrpositions[pdbfnum][r] = pos;
\r
398 // create model selection suffix
\r
399 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
\r
400 if (mapping[m].getChain() == null
\r
401 || mapping[m].getChain().trim().length() == 0)
\r
403 targetC[pdbfnum] = "";
\r
407 targetC[pdbfnum] = ":" + mapping[m].getChain();
\r
409 chainNames[pdbfnum] = mapping[m].getPdbId()
\r
410 + targetC[pdbfnum];
\r
411 // move on to next pdb file
\r
412 s = sequence[pdbfnum].length;
\r
418 String[] selcom = new String[files.length];
\r
420 // generate select statements to select regions to superimpose structures
\r
422 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
\r
424 String chainCd = targetC[pdbfnum];
\r
426 boolean run = false;
\r
427 StringBuffer molsel = new StringBuffer();
\r
428 molsel.append("{");
\r
429 for (int r = 0; r < matched.length; r++)
\r
437 if (lpos != commonrpositions[pdbfnum][r] - 1)
\r
442 molsel.append(lpos);
\r
443 molsel.append(chainCd);
\r
444 // molsel.append("} {");
\r
445 molsel.append("|");
\r
450 // continuous run - and lpos >-1
\r
453 // at the beginning, so add dash
\r
454 molsel.append(lpos);
\r
455 molsel.append("-");
\r
459 lpos = commonrpositions[pdbfnum][r];
\r
460 // molsel.append(lpos);
\r
463 // add final selection phrase
\r
466 molsel.append(lpos);
\r
467 molsel.append(chainCd);
\r
468 molsel.append("}");
\r
470 selcom[pdbfnum] = molsel.toString();
\r
471 selectioncom.append("((");
\r
472 selectioncom.append(selcom[pdbfnum].substring(1,
\r
473 selcom[pdbfnum].length() - 1));
\r
474 selectioncom.append(" )& ");
\r
475 selectioncom.append(pdbfnum + 1);
\r
476 selectioncom.append(".1)");
\r
477 if (pdbfnum < files.length - 1)
\r
479 selectioncom.append("|");
\r
483 // TODO: consider bailing if nmatched less than 4 because superposition
\r
486 // TODO: refactor superposable position search (above) from jmol selection
\r
487 // construction (below)
\r
488 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
\r
490 if (pdbfnum == refStructure)
\r
494 command.append("echo ");
\r
495 command.append("\"Superposing (");
\r
496 command.append(chainNames[pdbfnum]);
\r
497 command.append(") against reference (");
\r
498 command.append(chainNames[refStructure]);
\r
499 command.append(")\";\ncompare ");
\r
500 command.append("{");
\r
501 command.append(1 + pdbfnum);
\r
502 command.append(".1} {");
\r
503 command.append(1 + refStructure);
\r
504 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
\r
506 // form the matched pair strings
\r
508 for (int s = 0; s < 2; s++)
\r
510 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
\r
512 command.append(" ROTATE TRANSLATE;\n");
\r
514 System.out.println("Select regions:\n" + selectioncom.toString());
\r
515 evalStateCommand("select *; cartoons off; backbone; select ("
\r
516 + selectioncom.toString() + "); cartoons; ");
\r
517 // selcom.append("; ribbons; ");
\r
518 System.out.println("Superimpose command(s):\n" + command.toString());
\r
520 evalStateCommand(command.toString());
\r
522 if (selectioncom.length() > 0)
\r
523 {// finally, mark all regions that were superposed.
\r
524 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
\r
526 selectioncom.setLength(selectioncom.length() - 1);
\r
528 System.out.println("Select regions:\n" + selectioncom.toString());
\r
529 evalStateCommand("select *; cartoons off; backbone; select ("
\r
530 + selectioncom.toString() + "); cartoons; ");
\r
531 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
\r
535 public void evalStateCommand(String command)
\r
537 jmolHistory(false);
\r
538 if (lastCommand == null || !lastCommand.equals(command))
\r
540 viewer.evalStringQuiet(command + "\n");
\r
543 lastCommand = command;
\r
547 * colour any structures associated with sequences in the given alignment
\r
548 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
\r
549 * if colourBySequence is enabled.
\r
551 public void colourBySequence(boolean showFeatures,
\r
552 jalview.api.AlignmentViewPanel alignmentv)
\r
554 if (!colourBySequence)
\r
560 String[] files = getPdbFile();
\r
562 SequenceRenderer sr = getSequenceRenderer(alignmentv);
\r
564 FeatureRenderer fr = null;
\r
567 fr = getFeatureRenderer(alignmentv);
\r
569 AlignmentI alignment = alignmentv.getAlignment();
\r
571 for (String cbyseq : JmolCommands.getColourBySequenceCommand(ssm, files, sequence, sr, fr, alignment)) {
\r
572 evalStateCommand(cbyseq);
\r
576 public boolean isColourBySequence()
\r
578 return colourBySequence;
\r
581 public void setColourBySequence(boolean colourBySequence)
\r
583 this.colourBySequence = colourBySequence;
\r
586 public void createImage(String file, String type, int quality)
\r
588 System.out.println("JMOL CREATE IMAGE");
\r
591 public String createImage(String fileName, String type,
\r
592 Object textOrBytes, int quality)
\r
594 System.out.println("JMOL CREATE IMAGE");
\r
598 public String eval(String strEval)
\r
600 // System.out.println(strEval);
\r
601 // "# 'eval' is implemented only for the applet.";
\r
605 // End StructureListener
\r
606 // //////////////////////////
\r
608 public float[][] functionXY(String functionName, int x, int y)
\r
613 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
\r
615 // TODO Auto-generated method stub
\r
619 public Color getColour(int atomIndex, int pdbResNum, String chain,
\r
622 if (getModelNum(pdbfile) < 0)
\r
624 // TODO: verify atomIndex is selecting correct model.
\r
625 return new Color(viewer.getAtomArgb(atomIndex));
\r
629 * returns the current featureRenderer that should be used to colour the
\r
636 public abstract FeatureRenderer getFeatureRenderer(
\r
637 AlignmentViewPanel alignment);
\r
640 * instruct the Jalview binding to update the pdbentries vector if necessary
\r
641 * prior to matching the jmol view's contents to the list of structure files
\r
642 * Jalview knows about.
\r
644 public abstract void refreshPdbEntries();
\r
646 private int getModelNum(String modelFileName)
\r
648 String[] mfn = getPdbFile();
\r
653 for (int i = 0; i < mfn.length; i++)
\r
655 if (mfn[i].equalsIgnoreCase(modelFileName))
\r
662 * map between index of model filename returned from getPdbFile and the first
\r
663 * index of models from this file in the viewer. Note - this is not trimmed -
\r
664 * use getPdbFile to get number of unique models.
\r
666 private int _modelFileNameMap[];
\r
668 // ////////////////////////////////
\r
669 // /StructureListener
\r
670 public synchronized String[] getPdbFile()
\r
672 if (viewer == null)
\r
674 return new String[0];
\r
676 if (modelFileNames == null)
\r
679 String mset[] = new String[viewer.getModelCount()];
\r
680 _modelFileNameMap = new int[mset.length];
\r
682 mset[0] = viewer.getModelFileName(0);
\r
683 for (int i = 1; i < mset.length; i++)
\r
685 mset[j] = viewer.getModelFileName(i);
\r
686 _modelFileNameMap[j] = i; // record the model index for the filename
\r
687 // skip any additional models in the same file (NMR structures)
\r
688 if ((mset[j] == null ? mset[j] != mset[j - 1]
\r
689 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
\r
694 modelFileNames = new String[j];
\r
695 System.arraycopy(mset, 0, modelFileNames, 0, j);
\r
697 return modelFileNames;
\r
701 * map from string to applet
\r
703 public Map getRegistryInfo()
\r
705 // TODO Auto-generated method stub
\r
710 * returns the current sequenceRenderer that should be used to colour the
\r
717 public abstract SequenceRenderer getSequenceRenderer(
\r
718 AlignmentViewPanel alignment);
\r
720 // ///////////////////////////////
\r
721 // JmolStatusListener
\r
723 public void handlePopupMenu(int x, int y)
\r
725 jmolpopup.show(x, y);
\r
729 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
\r
732 if (modelFileNames == null)
\r
737 // look up file model number for this pdbfile
\r
740 // may need to adjust for URLencoding here - we don't worry about that yet.
\r
741 while (mdlNum < modelFileNames.length
\r
742 && !pdbfile.equals(modelFileNames[mdlNum]))
\r
744 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
\r
747 if (mdlNum == modelFileNames.length)
\r
752 jmolHistory(false);
\r
753 // if (!pdbfile.equals(pdbentry.getFile()))
\r
755 if (resetLastRes.length() > 0)
\r
757 viewer.evalStringQuiet(resetLastRes.toString());
\r
761 eval.append("select " + pdbResNum); // +modelNum
\r
763 resetLastRes.setLength(0);
\r
764 resetLastRes.append("select " + pdbResNum); // +modelNum
\r
767 resetLastRes.append(":");
\r
768 if (!chain.equals(" "))
\r
770 eval.append(chain);
\r
771 resetLastRes.append(chain);
\r
774 eval.append(" /" + (mdlNum + 1));
\r
775 resetLastRes.append("/" + (mdlNum + 1));
\r
777 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
\r
779 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
\r
780 + " and not hetero; spacefill 0;");
\r
782 eval.append("spacefill 200;select none");
\r
784 viewer.evalStringQuiet(eval.toString());
\r
789 boolean debug = true;
\r
791 private void jmolHistory(boolean enable)
\r
793 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
\r
796 public void loadInline(String string)
\r
798 loadedInline = true;
\r
799 // TODO: re JAL-623
\r
800 // viewer.loadInline(strModel, isAppend);
\r
802 // construct fake fullPathName and fileName so we can identify the file
\r
804 // Then, construct pass a reader for the string to Jmol.
\r
805 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
\r
806 // fileName, null, reader, false, null, null, 0);
\r
807 viewer.openStringInline(string);
\r
810 public void mouseOverStructure(int atomIndex, String strInfo)
\r
813 int alocsep = strInfo.indexOf("^");
\r
814 int mdlSep = strInfo.indexOf("/");
\r
815 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
\r
817 if (chainSeparator == -1)
\r
819 chainSeparator = strInfo.indexOf(".");
\r
820 if (mdlSep > -1 && mdlSep < chainSeparator)
\r
822 chainSeparator1 = chainSeparator;
\r
823 chainSeparator = mdlSep;
\r
826 // handle insertion codes
\r
829 pdbResNum = Integer.parseInt(strInfo.substring(
\r
830 strInfo.indexOf("]") + 1, alocsep));
\r
835 pdbResNum = Integer.parseInt(strInfo.substring(
\r
836 strInfo.indexOf("]") + 1, chainSeparator));
\r
840 if (strInfo.indexOf(":") > -1)
\r
841 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
\r
842 strInfo.indexOf("."));
\r
848 String pdbfilename = modelFileNames[frameNo]; // default is first or current
\r
852 if (chainSeparator1 == -1)
\r
854 chainSeparator1 = strInfo.indexOf(".", mdlSep);
\r
856 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
\r
857 chainSeparator1) : strInfo.substring(mdlSep + 1);
\r
860 // recover PDB filename for the model hovered over.
\r
861 pdbfilename = viewer
\r
862 .getModelFileName(new Integer(mdlId).intValue() - 1);
\r
863 } catch (Exception e)
\r
868 if (lastMessage == null || !lastMessage.equals(strInfo))
\r
869 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
\r
871 lastMessage = strInfo;
\r
874 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
\r
878 System.err.println("Ignoring additional hover info: " + data
\r
879 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
\r
881 mouseOverStructure(atomIndex, strInfo);
\r
885 * { if (history != null && strStatus != null &&
\r
886 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
\r
890 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
\r
893 * this implements the toggle label behaviour copied from the original
\r
894 * structure viewer, MCView
\r
896 if (strData != null)
\r
898 System.err.println("Ignoring additional pick data string " + strData);
\r
900 int chainSeparator = strInfo.indexOf(":");
\r
902 if (chainSeparator == -1)
\r
903 chainSeparator = strInfo.indexOf(".");
\r
905 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
\r
907 String mdlString = "";
\r
908 if ((p = strInfo.indexOf(":")) > -1)
\r
909 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
\r
911 if ((p = strInfo.indexOf("/")) > -1)
\r
913 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
\r
915 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
\r
916 + mdlString + "))";
\r
917 jmolHistory(false);
\r
919 if (!atomsPicked.contains(picked))
\r
921 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
\r
922 atomsPicked.addElement(picked);
\r
926 viewer.evalString("select " + picked + ";label off");
\r
927 atomsPicked.removeElement(picked);
\r
930 // TODO: in application this happens
\r
932 // if (scriptWindow != null)
\r
934 // scriptWindow.sendConsoleMessage(strInfo);
\r
935 // scriptWindow.sendConsoleMessage("\n");
\r
940 public void notifyCallback(int type, Object[] data)
\r
946 case JmolConstants.CALLBACK_LOADSTRUCT:
\r
947 notifyFileLoaded((String) data[1], (String) data[2],
\r
948 (String) data[3], (String) data[4],
\r
949 ((Integer) data[5]).intValue());
\r
952 case JmolConstants.CALLBACK_PICK:
\r
953 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
\r
955 // also highlight in alignment
\r
956 case JmolConstants.CALLBACK_HOVER:
\r
957 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
\r
960 case JmolConstants.CALLBACK_SCRIPT:
\r
961 notifyScriptTermination((String) data[2],
\r
962 ((Integer) data[3]).intValue());
\r
964 case JmolConstants.CALLBACK_ECHO:
\r
965 sendConsoleEcho((String) data[1]);
\r
967 case JmolConstants.CALLBACK_MESSAGE:
\r
968 sendConsoleMessage((data == null) ? ((String) null)
\r
969 : (String) data[1]);
\r
971 case JmolConstants.CALLBACK_ERROR:
\r
972 // System.err.println("Ignoring error callback.");
\r
974 case JmolConstants.CALLBACK_SYNC:
\r
975 case JmolConstants.CALLBACK_RESIZE:
\r
978 case JmolConstants.CALLBACK_MEASURE:
\r
980 case JmolConstants.CALLBACK_CLICK:
\r
982 System.err.println("Unhandled callback " + type + " "
\r
983 + data[1].toString());
\r
986 } catch (Exception e)
\r
988 System.err.println("Squashed Jmol callback handler error:");
\r
989 e.printStackTrace();
\r
993 public boolean notifyEnabled(int callbackPick)
\r
995 switch (callbackPick)
\r
997 case JmolConstants.CALLBACK_ECHO:
\r
998 case JmolConstants.CALLBACK_LOADSTRUCT:
\r
999 case JmolConstants.CALLBACK_MEASURE:
\r
1000 case JmolConstants.CALLBACK_MESSAGE:
\r
1001 case JmolConstants.CALLBACK_PICK:
\r
1002 case JmolConstants.CALLBACK_SCRIPT:
\r
1003 case JmolConstants.CALLBACK_HOVER:
\r
1004 case JmolConstants.CALLBACK_ERROR:
\r
1006 case JmolConstants.CALLBACK_RESIZE:
\r
1007 case JmolConstants.CALLBACK_SYNC:
\r
1008 case JmolConstants.CALLBACK_CLICK:
\r
1009 case JmolConstants.CALLBACK_ANIMFRAME:
\r
1010 case JmolConstants.CALLBACK_MINIMIZATION:
\r
1015 // incremented every time a load notification is successfully handled -
\r
1016 // lightweight mechanism for other threads to detect when they can start
\r
1017 // referrring to new structures.
\r
1018 private long loadNotifiesHandled = 0;
\r
1020 public long getLoadNotifiesHandled()
\r
1022 return loadNotifiesHandled;
\r
1025 public void notifyFileLoaded(String fullPathName, String fileName2,
\r
1026 String modelName, String errorMsg, int modelParts)
\r
1028 if (errorMsg != null)
\r
1030 fileLoadingError = errorMsg;
\r
1034 // TODO: deal sensibly with models loaded inLine:
\r
1035 // modelName will be null, as will fullPathName.
\r
1037 // the rest of this routine ignores the arguments, and simply interrogates
\r
1038 // the Jmol view to find out what structures it contains, and adds them to
\r
1039 // the structure selection manager.
\r
1040 fileLoadingError = null;
\r
1041 String[] oldmodels = modelFileNames;
\r
1042 modelFileNames = null;
\r
1043 chainNames = new Vector();
\r
1044 chainFile = new Hashtable();
\r
1045 boolean notifyLoaded = false;
\r
1046 String[] modelfilenames = getPdbFile();
\r
1047 ssm = StructureSelectionManager.getStructureSelectionManager();
\r
1048 // first check if we've lost any structures
\r
1049 if (oldmodels != null && oldmodels.length > 0)
\r
1052 for (int i = 0; i < oldmodels.length; i++)
\r
1054 for (int n = 0; n < modelfilenames.length; n++)
\r
1056 if (modelfilenames[n] == oldmodels[i])
\r
1058 oldmodels[i] = null;
\r
1062 if (oldmodels[i] != null)
\r
1069 String[] oldmfn = new String[oldm];
\r
1071 for (int i = 0; i < oldmodels.length; i++)
\r
1073 if (oldmodels[i] != null)
\r
1075 oldmfn[oldm++] = oldmodels[i];
\r
1078 // deregister the Jmol instance for these structures - we'll add
\r
1079 // ourselves again at the end for the current structure set.
\r
1080 ssm.removeStructureViewerListener(this, oldmfn);
\r
1083 refreshPdbEntries();
\r
1084 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
\r
1086 String fileName = modelfilenames[modelnum];
\r
1087 boolean foundEntry = false;
\r
1088 MCview.PDBfile pdb = null;
\r
1089 String pdbfile = null, pdbfhash = null;
\r
1090 // model was probably loaded inline - so check the pdb file hashcode
\r
1093 // calculate essential attributes for the pdb data imported inline.
\r
1094 // prolly need to resolve modelnumber properly - for now just use our
\r
1096 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
\r
1098 pdbfhash = "" + pdbfile.hashCode();
\r
1100 if (pdbentry != null)
\r
1102 // search pdbentries and sequences to find correct pdbentry for this
\r
1104 for (int pe = 0; pe < pdbentry.length; pe++)
\r
1106 boolean matches = false;
\r
1107 if (fileName == null)
\r
1110 // see JAL-623 - need method of matching pasted data up
\r
1112 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
\r
1113 AppletFormatAdapter.PASTE);
\r
1114 pdbentry[modelnum].setFile("INLINE" + pdb.id);
\r
1116 foundEntry = true;
\r
1121 if (matches = pdbentry[pe].getFile().equals(fileName))
\r
1123 foundEntry = true;
\r
1124 // TODO: Jmol can in principle retrieve from CLASSLOADER but
\r
1127 // to be tested. See mantis bug
\r
1128 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
\r
1129 String protocol = AppletFormatAdapter.URL;
\r
1132 File fl = new java.io.File(pdbentry[pe].getFile());
\r
1135 protocol = AppletFormatAdapter.FILE;
\r
1137 } catch (Exception e)
\r
1143 pdb = ssm.setMapping(sequence[pe], chains[pe],
\r
1144 pdbentry[pe].getFile(), protocol);
\r
1150 pdbentry[pe].setId(pdb.id);
\r
1151 // add an entry for every chain in the model
\r
1152 for (int i = 0; i < pdb.chains.size(); i++)
\r
1154 String chid = new String(pdb.id + ":"
\r
1155 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
\r
1156 chainFile.put(chid, pdbentry[pe].getFile());
\r
1157 chainNames.addElement(chid);
\r
1159 notifyLoaded = true;
\r
1163 if (!foundEntry && associateNewStructs)
\r
1165 // this is a foreign pdb file that jalview doesn't know about - add
\r
1166 // it to the dataset and try to find a home - either on a matching
\r
1167 // sequence or as a new sequence.
\r
1168 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
\r
1170 // parse pdb file into a chain, etc.
\r
1171 // locate best match for pdb in associated views and add mapping to
\r
1173 // if properly registered then
\r
1174 notifyLoaded = true;
\r
1179 // so finally, update the jmol bits and pieces
\r
1180 if (jmolpopup != null)
\r
1182 // potential for deadlock here:
\r
1183 // jmolpopup.updateComputedMenus();
\r
1185 if (!isLoadingFromArchive())
\r
1187 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
\r
1189 // register ourselves as a listener and notify the gui that it needs to
\r
1191 ssm.addStructureViewerListener(this);
\r
1194 FeatureRenderer fr = getFeatureRenderer(null);
\r
1197 fr.featuresAdded();
\r
1200 loadNotifiesHandled++;
\r
1202 setLoadingFromArchive(false);
\r
1205 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
\r
1207 notifyAtomPicked(iatom, strMeasure, null);
\r
1210 public abstract void notifyScriptTermination(String strStatus,
\r
1214 * display a message echoed from the jmol viewer
\r
1218 public abstract void sendConsoleEcho(String strEcho); /*
\r
1219 * { showConsole(true);
\r
1221 * history.append("\n" +
\r
1225 // /End JmolStatusListener
\r
1226 // /////////////////////////////
\r
1229 * @param strStatus
\r
1230 * status message - usually the response received after a script
\r
1233 public abstract void sendConsoleMessage(String strStatus);
\r
1235 public void setCallbackFunction(String callbackType,
\r
1236 String callbackFunction)
\r
1238 System.err.println("Ignoring set-callback request to associate "
\r
1239 + callbackType + " with function " + callbackFunction);
\r
1243 public void setJalviewColourScheme(ColourSchemeI cs)
\r
1245 colourBySequence = false;
\r
1253 jmolHistory(false);
\r
1254 // TODO: Switch between nucleotide or aa selection expressions
\r
1255 Enumeration en = ResidueProperties.aa3Hash.keys();
\r
1256 StringBuffer command = new StringBuffer("select *;color white;");
\r
1257 while (en.hasMoreElements())
\r
1259 res = en.nextElement().toString();
\r
1260 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
\r
1264 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
\r
1266 command.append("select " + res + ";color[" + col.getRed() + ","
\r
1267 + col.getGreen() + "," + col.getBlue() + "];");
\r
1270 evalStateCommand(command.toString());
\r
1271 jmolHistory(true);
\r
1274 public void showHelp()
\r
1276 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
\r
1280 * open the URL somehow
\r
1284 public abstract void showUrl(String url, String target);
\r
1287 * called when the binding thinks the UI needs to be refreshed after a Jmol
\r
1288 * state change. this could be because structures were loaded, or because an
\r
1289 * error has occured.
\r
1291 public abstract void refreshGUI();
\r
1294 * called to show or hide the associated console window container.
\r
1298 public abstract void showConsole(boolean show);
\r
1301 * @param renderPanel
\r
1302 * @param jmolfileio
\r
1303 * - when true will initialise jmol's file IO system (should be false
\r
1304 * in applet context)
\r
1306 * @param documentBase
\r
1308 * @param commandOptions
\r
1310 public void allocateViewer(Container renderPanel, boolean jmolfileio,
\r
1311 String htmlName, URL documentBase, URL codeBase,
\r
1312 String commandOptions)
\r
1314 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
\r
1315 codeBase, commandOptions, null, null);
\r
1320 * @param renderPanel
\r
1321 * @param jmolfileio
\r
1322 * - when true will initialise jmol's file IO system (should be false
\r
1323 * in applet context)
\r
1325 * @param documentBase
\r
1327 * @param commandOptions
\r
1328 * @param consolePanel
\r
1329 * - panel to contain Jmol console
\r
1330 * @param buttonsToShow
\r
1331 * - buttons to show on the console, in ordr
\r
1333 public void allocateViewer(Container renderPanel, boolean jmolfileio,
\r
1334 String htmlName, URL documentBase, URL codeBase,
\r
1335 String commandOptions, final Container consolePanel,
\r
1336 String buttonsToShow)
\r
1338 if (commandOptions==null) {
1341 viewer = JmolViewer.allocateViewer(renderPanel,
\r
1342 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
\r
1343 + ((Object) this).toString(), documentBase, codeBase,
\r
1344 commandOptions, this);
\r
1346 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
\r
1347 if (consolePanel != null)
\r
1349 consolePanel.addComponentListener(this);
\r
1355 protected abstract JmolAppConsoleInterface createJmolConsole(
\r
1356 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
\r
1358 protected org.jmol.api.JmolAppConsoleInterface console = null;
\r
1360 public void componentResized(ComponentEvent e)
\r
1365 public void componentMoved(ComponentEvent e)
\r
1370 public void componentShown(ComponentEvent e)
\r
1372 showConsole(true);
\r
1375 public void componentHidden(ComponentEvent e)
\r
1377 showConsole(false);
\r
1380 public void setLoadingFromArchive(boolean loadingFromArchive)
\r
1382 this.loadingFromArchive = loadingFromArchive;
\r
1385 public boolean isLoadingFromArchive()
\r
1387 return loadingFromArchive;
\r
1390 public void setBackgroundColour(java.awt.Color col)
\r
1392 jmolHistory(false);
\r
1393 viewer.evalStringQuiet("background [" + col.getRed() + ","
\r
1394 + col.getGreen() + "," + col.getBlue() + "];");
\r
1395 jmolHistory(true);
\r
1399 * add structures and any known sequence associations
\r
1401 * @returns the pdb entries added to the current set.
\r
1403 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
\r
1404 SequenceI[][] seq, String[][] chns)
\r
1407 Vector v = new Vector();
\r
1408 Vector rtn = new Vector();
\r
1409 for (int i = 0; i < pdbentry.length; i++)
\r
1411 v.addElement(pdbentry[i]);
\r
1413 for (int i = 0; i < pdbe.length; i++)
\r
1415 int r = v.indexOf(pdbe[i]);
\r
1416 if (r == -1 || r >= pdbentry.length)
\r
1418 rtn.addElement(new int[]
\r
1420 v.addElement(pdbe[i]);
\r
1424 // just make sure the sequence/chain entries are all up to date
\r
1425 addSequenceAndChain(r, seq[i], chns[i]);
\r
1428 pdbe = new PDBEntry[v.size()];
\r
1431 if (rtn.size() > 0)
\r
1433 // expand the tied seuqence[] and string[] arrays
\r
1434 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
\r
1435 String[][] sch = new String[pdbentry.length][];
\r
1436 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
\r
1437 System.arraycopy(chains, 0, sch, 0, this.chains.length);
\r
1440 pdbe = new PDBEntry[rtn.size()];
\r
1441 for (int r = 0; r < pdbe.length; r++)
\r
1443 int[] stri = ((int[]) rtn.elementAt(r));
\r
1444 // record the pdb file as a new addition
\r
1445 pdbe[r] = pdbentry[stri[0]];
\r
1446 // and add the new sequence/chain entries
\r
1447 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
\r
1457 public void addSequence(int pe, SequenceI[] seq)
\r
1459 // add sequences to the pe'th pdbentry's seuqence set.
\r
1460 addSequenceAndChain(pe, seq, null);
\r
1463 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
\r
1465 if (pe < 0 || pe >= pdbentry.length)
\r
1468 "Implementation error - no corresponding pdbentry (for index "
\r
1469 + pe + ") to add sequences mappings to");
\r
1471 final String nullChain = "TheNullChain";
\r
1472 Vector s = new Vector();
\r
1473 Vector c = new Vector();
\r
1474 if (chains == null)
\r
1476 chains = new String[pdbentry.length][];
\r
1478 if (sequence[pe] != null)
\r
1480 for (int i = 0; i < sequence[pe].length; i++)
\r
1482 s.addElement(sequence[pe][i]);
\r
1483 if (chains[pe] != null)
\r
1485 if (i < chains[pe].length)
\r
1487 c.addElement(chains[pe][i]);
\r
1491 c.addElement(nullChain);
\r
1496 if (tchain != null && tchain.length > 0)
\r
1498 c.addElement(nullChain);
\r
1503 for (int i = 0; i < seq.length; i++)
\r
1505 if (!s.contains(seq[i]))
\r
1507 s.addElement(seq[i]);
\r
1508 if (tchain != null && i < tchain.length)
\r
1510 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
\r
1514 SequenceI[] tmp = new SequenceI[s.size()];
\r
1516 sequence[pe] = tmp;
\r
1519 String[] tch = new String[c.size()];
\r
1521 for (int i = 0; i < tch.length; i++)
\r
1523 if (tch[i] == nullChain)
\r
1532 chains[pe] = null;
\r