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 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.api.StructureSelectionManagerProvider;
\r
34 import jalview.datamodel.*;
\r
35 import jalview.structure.*;
\r
36 import jalview.io.*;
\r
38 import org.jmol.api.*;
\r
39 import org.jmol.adapter.smarter.SmarterJmolAdapter;
\r
41 import org.jmol.popup.*;
\r
42 import org.jmol.viewer.JmolConstants;
\r
43 import org.jmol.viewer.Viewer;
\r
45 import jalview.schemes.*;
\r
47 public abstract class JalviewJmolBinding implements StructureListener,
\r
48 JmolStatusListener, SequenceStructureBinding,
\r
49 JmolSelectionListener, ComponentListener, StructureSelectionManagerProvider
\r
53 * set if Jmol state is being restored from some source - instructs binding
\r
54 * not to apply default display style when structure set is updated for first
\r
57 private boolean loadingFromArchive = false;
\r
60 * state flag used to check if the Jmol viewer's paint method can be called
\r
62 private boolean finishedInit = false;
\r
64 public boolean isFinishedInit()
\r
66 return finishedInit;
\r
69 public void setFinishedInit(boolean finishedInit)
\r
71 this.finishedInit = finishedInit;
\r
74 boolean allChainsSelected = false;
\r
77 * when true, try to search the associated datamodel for sequences that are
\r
78 * associated with any unknown structures in the Jmol view.
\r
80 private boolean associateNewStructs = false;
\r
82 Vector atomsPicked = new Vector();
\r
84 public Vector chainNames;
\r
86 Hashtable chainFile;
\r
89 * array of target chains for seuqences - tied to pdbentry and sequence[]
\r
91 protected String[][] chains;
\r
93 boolean colourBySequence = true;
\r
95 StringBuffer eval = new StringBuffer();
\r
97 public String fileLoadingError;
\r
100 * the default or current model displayed if the model cannot be identified
\r
101 * from the selection message
\r
105 protected JmolPopup jmolpopup;
\r
107 String lastCommand;
\r
109 String lastMessage;
\r
111 boolean loadedInline;
\r
114 * current set of model filenames loaded in the Jmol instance
\r
116 String[] modelFileNames = null;
\r
118 public PDBEntry[] pdbentry;
\r
121 * datasource protocol for access to PDBEntrylatest
\r
123 String protocol = null;
\r
125 StringBuffer resetLastRes = new StringBuffer();
\r
128 * sequences mapped to each pdbentry
\r
130 public SequenceI[][] sequence;
\r
132 public StructureSelectionManager ssm;
\r
134 public JmolViewer viewer;
\r
136 public JalviewJmolBinding(StructureSelectionManager ssm, PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
\r
137 String[][] chains, String protocol)
\r
140 this.sequence = sequenceIs;
\r
141 this.chains = chains;
\r
142 this.pdbentry = pdbentry;
\r
143 this.protocol = protocol;
\r
144 if (chains == null)
\r
146 this.chains = new String[pdbentry.length][];
\r
149 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
\r
150 * "jalviewJmol", ap.av.applet .getDocumentBase(),
\r
151 * ap.av.applet.getCodeBase(), "", this);
\r
153 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
\r
157 public JalviewJmolBinding(StructureSelectionManager ssm, JmolViewer viewer2)
\r
161 viewer.setJmolStatusListener(this);
\r
162 viewer.addSelectionListener(this);
\r
166 * construct a title string for the viewer window based on the data jalview
\r
171 public String getViewerTitle()
\r
173 if (sequence == null || pdbentry == null || sequence.length < 1
\r
174 || pdbentry.length < 1 || sequence[0].length < 1)
\r
176 return ("Jalview Jmol Window");
\r
178 // TODO: give a more informative title when multiple structures are
\r
180 StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
\r
181 + pdbentry[0].getId());
\r
183 if (pdbentry[0].getProperty() != null)
\r
185 if (pdbentry[0].getProperty().get("method") != null)
\r
187 title.append(" Method: ");
\r
188 title.append(pdbentry[0].getProperty().get("method"));
\r
190 if (pdbentry[0].getProperty().get("chains") != null)
\r
192 title.append(" Chain:");
\r
193 title.append(pdbentry[0].getProperty().get("chains"));
\r
196 return title.toString();
\r
200 * prepare the view for a given set of models/chains. chainList contains
\r
201 * strings of the form 'pdbfilename:Chaincode'
\r
204 * list of chains to make visible
\r
206 public void centerViewer(Vector chainList)
\r
208 StringBuffer cmd = new StringBuffer();
\r
211 for (int i = 0, iSize = chainList.size(); i < iSize; i++)
\r
214 lbl = (String) chainList.elementAt(i);
\r
218 mlength = lbl.indexOf(":", p);
\r
219 } while (p < mlength && mlength < (lbl.length() - 2));
\r
220 // TODO: lookup each pdb id and recover proper model number for it.
\r
221 cmd.append(":" + lbl.substring(mlength + 1) + " /"
\r
222 + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");
\r
224 if (cmd.length() > 0)
\r
225 cmd.setLength(cmd.length() - 4);
\r
226 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
\r
229 public void closeViewer()
\r
231 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
\r
232 // remove listeners for all structures in viewer
\r
233 ssm.removeStructureViewerListener(this, this.getPdbFile());
\r
234 // and shut down jmol
\r
235 viewer.evalStringQuiet("zap");
\r
236 viewer.setJmolStatusListener(null);
\r
237 lastCommand = null;
\r
239 releaseUIResources();
\r
243 * called by JalviewJmolbinding after closeViewer is called - release any
\r
244 * resources and references so they can be garbage collected.
\r
246 protected abstract void releaseUIResources();
\r
248 public void colourByChain()
\r
250 colourBySequence = false;
\r
251 // TODO: colour by chain should colour each chain distinctly across all
\r
253 // TODO: http://issues.jalview.org/browse/JAL-628
\r
254 evalStateCommand("select *;color chain");
\r
257 public void colourByCharge()
\r
259 colourBySequence = false;
\r
260 evalStateCommand("select *;color white;select ASP,GLU;color red;"
\r
261 + "select LYS,ARG;color blue;select CYS;color yellow");
\r
265 * superpose the structures associated with sequences in the alignment
\r
266 * according to their corresponding positions.
\r
268 public void superposeStructures(AlignmentI alignment)
\r
270 superposeStructures(alignment, -1, null);
\r
274 * superpose the structures associated with sequences in the alignment
\r
275 * according to their corresponding positions. ded)
\r
277 * @param refStructure
\r
278 * - select which pdb file to use as reference (default is -1 - the
\r
279 * first structure in the alignment)
\r
281 public void superposeStructures(AlignmentI alignment, int refStructure)
\r
283 superposeStructures(alignment, refStructure, null);
\r
287 * superpose the structures associated with sequences in the alignment
\r
288 * according to their corresponding positions. ded)
\r
290 * @param refStructure
\r
291 * - select which pdb file to use as reference (default is -1 - the
\r
292 * first structure in the alignment)
\r
293 * @param hiddenCols
\r
296 public void superposeStructures(AlignmentI alignment, int refStructure,
\r
297 ColumnSelection hiddenCols)
\r
299 superposeStructures(new AlignmentI[]
\r
300 { alignment }, new int[]
\r
301 { refStructure }, new ColumnSelection[]
\r
305 public void superposeStructures(AlignmentI[] _alignment,
\r
306 int[] _refStructure, ColumnSelection[] _hiddenCols)
\r
308 String[] files = getPdbFile();
\r
309 StringBuffer selectioncom = new StringBuffer();
\r
310 assert (_alignment.length == _refStructure.length && _alignment.length != _hiddenCols.length);
\r
311 // union of all aligned positions are collected together.
\r
312 for (int a = 0; a < _alignment.length; a++)
\r
314 int refStructure = _refStructure[a];
\r
315 AlignmentI alignment = _alignment[a];
\r
316 ColumnSelection hiddenCols = _hiddenCols[a];
\r
318 && selectioncom.length() > 0
\r
319 && !selectioncom.substring(selectioncom.length() - 1).equals(
\r
322 selectioncom.append("|");
\r
324 // process this alignment
\r
325 if (refStructure >= files.length)
\r
327 System.err.println("Invalid reference structure value "
\r
331 if (refStructure < -1)
\r
335 StringBuffer command = new StringBuffer();
\r
337 boolean matched[] = new boolean[alignment.getWidth()];
\r
338 for (int m = 0; m < matched.length; m++)
\r
341 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
\r
344 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
\r
345 String isel[] = new String[files.length];
\r
346 // reference structure - all others are superposed in it
\r
347 String[] targetC = new String[files.length];
\r
348 String[] chainNames = new String[files.length];
\r
349 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
\r
351 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
\r
353 if (mapping == null || mapping.length < 1)
\r
357 for (int s = 0; s < sequence[pdbfnum].length; s++)
\r
359 for (int sp, m = 0; m < mapping.length; m++)
\r
361 if (mapping[m].getSequence() == sequence[pdbfnum][s]
\r
362 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
\r
364 if (refStructure == -1)
\r
366 refStructure = pdbfnum;
\r
368 SequenceI asp = alignment.getSequenceAt(sp);
\r
369 for (int r = 0; r < matched.length; r++)
\r
375 matched[r] = false; // assume this is not a good site
\r
376 if (r >= asp.getLength())
\r
381 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
\r
383 // no mapping to gaps in sequence
\r
386 int t = asp.findPosition(r); // sequence position
\r
387 int apos = mapping[m].getAtomNum(t);
\r
388 int pos = mapping[m].getPDBResNum(t);
\r
390 if (pos < 1 || pos == lastPos)
\r
392 // can't align unmapped sequence
\r
395 matched[r] = true; // this is a good ite
\r
397 // just record this residue position
\r
398 commonrpositions[pdbfnum][r] = pos;
\r
400 // create model selection suffix
\r
401 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
\r
402 if (mapping[m].getChain() == null
\r
403 || mapping[m].getChain().trim().length() == 0)
\r
405 targetC[pdbfnum] = "";
\r
409 targetC[pdbfnum] = ":" + mapping[m].getChain();
\r
411 chainNames[pdbfnum] = mapping[m].getPdbId()
\r
412 + targetC[pdbfnum];
\r
413 // move on to next pdb file
\r
414 s = sequence[pdbfnum].length;
\r
420 String[] selcom = new String[files.length];
\r
422 // generate select statements to select regions to superimpose structures
\r
424 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
\r
426 String chainCd = targetC[pdbfnum];
\r
428 boolean run = false;
\r
429 StringBuffer molsel = new StringBuffer();
\r
430 molsel.append("{");
\r
431 for (int r = 0; r < matched.length; r++)
\r
439 if (lpos != commonrpositions[pdbfnum][r] - 1)
\r
444 molsel.append(lpos);
\r
445 molsel.append(chainCd);
\r
446 // molsel.append("} {");
\r
447 molsel.append("|");
\r
452 // continuous run - and lpos >-1
\r
455 // at the beginning, so add dash
\r
456 molsel.append(lpos);
\r
457 molsel.append("-");
\r
461 lpos = commonrpositions[pdbfnum][r];
\r
462 // molsel.append(lpos);
\r
465 // add final selection phrase
\r
468 molsel.append(lpos);
\r
469 molsel.append(chainCd);
\r
470 molsel.append("}");
\r
472 selcom[pdbfnum] = molsel.toString();
\r
473 selectioncom.append("((");
\r
474 selectioncom.append(selcom[pdbfnum].substring(1,
\r
475 selcom[pdbfnum].length() - 1));
\r
476 selectioncom.append(" )& ");
\r
477 selectioncom.append(pdbfnum + 1);
\r
478 selectioncom.append(".1)");
\r
479 if (pdbfnum < files.length - 1)
\r
481 selectioncom.append("|");
\r
485 // TODO: consider bailing if nmatched less than 4 because superposition
\r
488 // TODO: refactor superposable position search (above) from jmol selection
\r
489 // construction (below)
\r
490 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
\r
492 if (pdbfnum == refStructure)
\r
496 command.append("echo ");
\r
497 command.append("\"Superposing (");
\r
498 command.append(chainNames[pdbfnum]);
\r
499 command.append(") against reference (");
\r
500 command.append(chainNames[refStructure]);
\r
501 command.append(")\";\ncompare ");
\r
502 command.append("{");
\r
503 command.append(1 + pdbfnum);
\r
504 command.append(".1} {");
\r
505 command.append(1 + refStructure);
\r
506 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
\r
508 // form the matched pair strings
\r
510 for (int s = 0; s < 2; s++)
\r
512 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
\r
514 command.append(" ROTATE TRANSLATE;\n");
\r
516 System.out.println("Select regions:\n" + selectioncom.toString());
\r
517 evalStateCommand("select *; cartoons off; backbone; select ("
\r
518 + selectioncom.toString() + "); cartoons; ");
\r
519 // selcom.append("; ribbons; ");
\r
520 System.out.println("Superimpose command(s):\n" + command.toString());
\r
522 evalStateCommand(command.toString());
\r
524 if (selectioncom.length() > 0)
\r
525 {// finally, mark all regions that were superposed.
\r
526 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
\r
528 selectioncom.setLength(selectioncom.length() - 1);
\r
530 System.out.println("Select regions:\n" + selectioncom.toString());
\r
531 evalStateCommand("select *; cartoons off; backbone; select ("
\r
532 + selectioncom.toString() + "); cartoons; ");
\r
533 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
\r
537 public void evalStateCommand(String command)
\r
539 jmolHistory(false);
\r
540 if (lastCommand == null || !lastCommand.equals(command))
\r
542 viewer.evalStringQuiet(command + "\n");
\r
545 lastCommand = command;
\r
549 * colour any structures associated with sequences in the given alignment
\r
550 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
\r
551 * if colourBySequence is enabled.
\r
553 public void colourBySequence(boolean showFeatures,
\r
554 jalview.api.AlignmentViewPanel alignmentv)
\r
556 if (!colourBySequence)
\r
562 String[] files = getPdbFile();
\r
564 SequenceRenderer sr = getSequenceRenderer(alignmentv);
\r
566 FeatureRenderer fr = null;
\r
569 fr = getFeatureRenderer(alignmentv);
\r
571 AlignmentI alignment = alignmentv.getAlignment();
\r
573 for (jalview.structure.StructureMappingcommandSet cpdbbyseq: JmolCommands.getColourBySequenceCommand(ssm, files, sequence, sr, fr, alignment))
\r
574 for (String cbyseq : cpdbbyseq.commands) {
\r
575 evalStateCommand(cbyseq);
\r
579 public boolean isColourBySequence()
\r
581 return colourBySequence;
\r
584 public void setColourBySequence(boolean colourBySequence)
\r
586 this.colourBySequence = colourBySequence;
\r
589 public void createImage(String file, String type, int quality)
\r
591 System.out.println("JMOL CREATE IMAGE");
\r
594 public String createImage(String fileName, String type,
\r
595 Object textOrBytes, int quality)
\r
597 System.out.println("JMOL CREATE IMAGE");
\r
601 public String eval(String strEval)
\r
603 // System.out.println(strEval);
\r
604 // "# 'eval' is implemented only for the applet.";
\r
608 // End StructureListener
\r
609 // //////////////////////////
\r
611 public float[][] functionXY(String functionName, int x, int y)
\r
616 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
\r
618 // TODO Auto-generated method stub
\r
622 public Color getColour(int atomIndex, int pdbResNum, String chain,
\r
625 if (getModelNum(pdbfile) < 0)
\r
627 // TODO: verify atomIndex is selecting correct model.
\r
628 return new Color(viewer.getAtomArgb(atomIndex));
\r
632 * returns the current featureRenderer that should be used to colour the
\r
639 public abstract FeatureRenderer getFeatureRenderer(
\r
640 AlignmentViewPanel alignment);
\r
643 * instruct the Jalview binding to update the pdbentries vector if necessary
\r
644 * prior to matching the jmol view's contents to the list of structure files
\r
645 * Jalview knows about.
\r
647 public abstract void refreshPdbEntries();
\r
649 private int getModelNum(String modelFileName)
\r
651 String[] mfn = getPdbFile();
\r
656 for (int i = 0; i < mfn.length; i++)
\r
658 if (mfn[i].equalsIgnoreCase(modelFileName))
\r
665 * map between index of model filename returned from getPdbFile and the first
\r
666 * index of models from this file in the viewer. Note - this is not trimmed -
\r
667 * use getPdbFile to get number of unique models.
\r
669 private int _modelFileNameMap[];
\r
671 // ////////////////////////////////
\r
672 // /StructureListener
\r
673 public synchronized String[] getPdbFile()
\r
675 if (viewer == null)
\r
677 return new String[0];
\r
679 if (modelFileNames == null)
\r
682 String mset[] = new String[viewer.getModelCount()];
\r
683 _modelFileNameMap = new int[mset.length];
\r
685 mset[0] = viewer.getModelFileName(0);
\r
686 for (int i = 1; i < mset.length; i++)
\r
688 mset[j] = viewer.getModelFileName(i);
\r
689 _modelFileNameMap[j] = i; // record the model index for the filename
\r
690 // skip any additional models in the same file (NMR structures)
\r
691 if ((mset[j] == null ? mset[j] != mset[j - 1]
\r
692 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
\r
697 modelFileNames = new String[j];
\r
698 System.arraycopy(mset, 0, modelFileNames, 0, j);
\r
700 return modelFileNames;
\r
704 * map from string to applet
\r
706 public Map getRegistryInfo()
\r
708 // TODO Auto-generated method stub
\r
713 * returns the current sequenceRenderer that should be used to colour the
\r
720 public abstract SequenceRenderer getSequenceRenderer(
\r
721 AlignmentViewPanel alignment);
\r
723 // ///////////////////////////////
\r
724 // JmolStatusListener
\r
726 public void handlePopupMenu(int x, int y)
\r
728 jmolpopup.show(x, y);
\r
732 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
\r
735 if (modelFileNames == null)
\r
740 // look up file model number for this pdbfile
\r
743 // may need to adjust for URLencoding here - we don't worry about that yet.
\r
744 while (mdlNum < modelFileNames.length
\r
745 && !pdbfile.equals(modelFileNames[mdlNum]))
\r
747 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
\r
750 if (mdlNum == modelFileNames.length)
\r
755 jmolHistory(false);
\r
756 // if (!pdbfile.equals(pdbentry.getFile()))
\r
758 if (resetLastRes.length() > 0)
\r
760 viewer.evalStringQuiet(resetLastRes.toString());
\r
764 eval.append("select " + pdbResNum); // +modelNum
\r
766 resetLastRes.setLength(0);
\r
767 resetLastRes.append("select " + pdbResNum); // +modelNum
\r
770 resetLastRes.append(":");
\r
771 if (!chain.equals(" "))
\r
773 eval.append(chain);
\r
774 resetLastRes.append(chain);
\r
777 eval.append(" /" + (mdlNum + 1));
\r
778 resetLastRes.append("/" + (mdlNum + 1));
\r
780 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
\r
782 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
\r
783 + " and not hetero; spacefill 0;");
\r
785 eval.append("spacefill 200;select none");
\r
787 viewer.evalStringQuiet(eval.toString());
\r
792 boolean debug = true;
\r
794 private void jmolHistory(boolean enable)
\r
796 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
\r
799 public void loadInline(String string)
\r
801 loadedInline = true;
\r
802 // TODO: re JAL-623
\r
803 // viewer.loadInline(strModel, isAppend);
\r
805 // construct fake fullPathName and fileName so we can identify the file
\r
807 // Then, construct pass a reader for the string to Jmol.
\r
808 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
\r
809 // fileName, null, reader, false, null, null, 0);
\r
810 viewer.openStringInline(string);
\r
813 public void mouseOverStructure(int atomIndex, String strInfo)
\r
816 int alocsep = strInfo.indexOf("^");
\r
817 int mdlSep = strInfo.indexOf("/");
\r
818 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
\r
820 if (chainSeparator == -1)
\r
822 chainSeparator = strInfo.indexOf(".");
\r
823 if (mdlSep > -1 && mdlSep < chainSeparator)
\r
825 chainSeparator1 = chainSeparator;
\r
826 chainSeparator = mdlSep;
\r
829 // handle insertion codes
\r
832 pdbResNum = Integer.parseInt(strInfo.substring(
\r
833 strInfo.indexOf("]") + 1, alocsep));
\r
838 pdbResNum = Integer.parseInt(strInfo.substring(
\r
839 strInfo.indexOf("]") + 1, chainSeparator));
\r
843 if (strInfo.indexOf(":") > -1)
\r
844 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
\r
845 strInfo.indexOf("."));
\r
851 String pdbfilename = modelFileNames[frameNo]; // default is first or current
\r
855 if (chainSeparator1 == -1)
\r
857 chainSeparator1 = strInfo.indexOf(".", mdlSep);
\r
859 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
\r
860 chainSeparator1) : strInfo.substring(mdlSep + 1);
\r
863 // recover PDB filename for the model hovered over.
\r
864 pdbfilename = viewer
\r
865 .getModelFileName(new Integer(mdlId).intValue() - 1);
\r
866 } catch (Exception e)
\r
871 if (lastMessage == null || !lastMessage.equals(strInfo))
\r
872 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
\r
874 lastMessage = strInfo;
\r
877 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
\r
881 System.err.println("Ignoring additional hover info: " + data
\r
882 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
\r
884 mouseOverStructure(atomIndex, strInfo);
\r
888 * { if (history != null && strStatus != null &&
\r
889 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
\r
893 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
\r
896 * this implements the toggle label behaviour copied from the original
\r
897 * structure viewer, MCView
\r
899 if (strData != null)
\r
901 System.err.println("Ignoring additional pick data string " + strData);
\r
903 int chainSeparator = strInfo.indexOf(":");
\r
905 if (chainSeparator == -1)
\r
906 chainSeparator = strInfo.indexOf(".");
\r
908 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
\r
910 String mdlString = "";
\r
911 if ((p = strInfo.indexOf(":")) > -1)
\r
912 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
\r
914 if ((p = strInfo.indexOf("/")) > -1)
\r
916 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
\r
918 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
\r
919 + mdlString + "))";
\r
920 jmolHistory(false);
\r
922 if (!atomsPicked.contains(picked))
\r
924 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
\r
925 atomsPicked.addElement(picked);
\r
929 viewer.evalString("select " + picked + ";label off");
\r
930 atomsPicked.removeElement(picked);
\r
933 // TODO: in application this happens
\r
935 // if (scriptWindow != null)
\r
937 // scriptWindow.sendConsoleMessage(strInfo);
\r
938 // scriptWindow.sendConsoleMessage("\n");
\r
943 public void notifyCallback(int type, Object[] data)
\r
949 case JmolConstants.CALLBACK_LOADSTRUCT:
\r
950 notifyFileLoaded((String) data[1], (String) data[2],
\r
951 (String) data[3], (String) data[4],
\r
952 ((Integer) data[5]).intValue());
\r
955 case JmolConstants.CALLBACK_PICK:
\r
956 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
\r
958 // also highlight in alignment
\r
959 case JmolConstants.CALLBACK_HOVER:
\r
960 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
\r
963 case JmolConstants.CALLBACK_SCRIPT:
\r
964 notifyScriptTermination((String) data[2],
\r
965 ((Integer) data[3]).intValue());
\r
967 case JmolConstants.CALLBACK_ECHO:
\r
968 sendConsoleEcho((String) data[1]);
\r
970 case JmolConstants.CALLBACK_MESSAGE:
\r
971 sendConsoleMessage((data == null) ? ((String) null)
\r
972 : (String) data[1]);
\r
974 case JmolConstants.CALLBACK_ERROR:
\r
975 // System.err.println("Ignoring error callback.");
\r
977 case JmolConstants.CALLBACK_SYNC:
\r
978 case JmolConstants.CALLBACK_RESIZE:
\r
981 case JmolConstants.CALLBACK_MEASURE:
\r
983 case JmolConstants.CALLBACK_CLICK:
\r
985 System.err.println("Unhandled callback " + type + " "
\r
986 + data[1].toString());
\r
989 } catch (Exception e)
\r
991 System.err.println("Squashed Jmol callback handler error:");
\r
992 e.printStackTrace();
\r
996 public boolean notifyEnabled(int callbackPick)
\r
998 switch (callbackPick)
\r
1000 case JmolConstants.CALLBACK_ECHO:
\r
1001 case JmolConstants.CALLBACK_LOADSTRUCT:
\r
1002 case JmolConstants.CALLBACK_MEASURE:
\r
1003 case JmolConstants.CALLBACK_MESSAGE:
\r
1004 case JmolConstants.CALLBACK_PICK:
\r
1005 case JmolConstants.CALLBACK_SCRIPT:
\r
1006 case JmolConstants.CALLBACK_HOVER:
\r
1007 case JmolConstants.CALLBACK_ERROR:
\r
1009 case JmolConstants.CALLBACK_RESIZE:
\r
1010 case JmolConstants.CALLBACK_SYNC:
\r
1011 case JmolConstants.CALLBACK_CLICK:
\r
1012 case JmolConstants.CALLBACK_ANIMFRAME:
\r
1013 case JmolConstants.CALLBACK_MINIMIZATION:
\r
1018 // incremented every time a load notification is successfully handled -
\r
1019 // lightweight mechanism for other threads to detect when they can start
\r
1020 // referrring to new structures.
\r
1021 private long loadNotifiesHandled = 0;
\r
1023 public long getLoadNotifiesHandled()
\r
1025 return loadNotifiesHandled;
\r
1028 public void notifyFileLoaded(String fullPathName, String fileName2,
\r
1029 String modelName, String errorMsg, int modelParts)
\r
1031 if (errorMsg != null)
\r
1033 fileLoadingError = errorMsg;
\r
1037 // TODO: deal sensibly with models loaded inLine:
\r
1038 // modelName will be null, as will fullPathName.
\r
1040 // the rest of this routine ignores the arguments, and simply interrogates
\r
1041 // the Jmol view to find out what structures it contains, and adds them to
\r
1042 // the structure selection manager.
\r
1043 fileLoadingError = null;
\r
1044 String[] oldmodels = modelFileNames;
\r
1045 modelFileNames = null;
\r
1046 chainNames = new Vector();
\r
1047 chainFile = new Hashtable();
\r
1048 boolean notifyLoaded = false;
\r
1049 String[] modelfilenames = getPdbFile();
\r
1050 // first check if we've lost any structures
\r
1051 if (oldmodels != null && oldmodels.length > 0)
\r
1054 for (int i = 0; i < oldmodels.length; i++)
\r
1056 for (int n = 0; n < modelfilenames.length; n++)
\r
1058 if (modelfilenames[n] == oldmodels[i])
\r
1060 oldmodels[i] = null;
\r
1064 if (oldmodels[i] != null)
\r
1071 String[] oldmfn = new String[oldm];
\r
1073 for (int i = 0; i < oldmodels.length; i++)
\r
1075 if (oldmodels[i] != null)
\r
1077 oldmfn[oldm++] = oldmodels[i];
\r
1080 // deregister the Jmol instance for these structures - we'll add
\r
1081 // ourselves again at the end for the current structure set.
\r
1082 ssm.removeStructureViewerListener(this, oldmfn);
\r
1085 refreshPdbEntries();
\r
1086 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
\r
1088 String fileName = modelfilenames[modelnum];
\r
1089 boolean foundEntry = false;
\r
1090 MCview.PDBfile pdb = null;
\r
1091 String pdbfile = null, pdbfhash = null;
\r
1092 // model was probably loaded inline - so check the pdb file hashcode
\r
1095 // calculate essential attributes for the pdb data imported inline.
\r
1096 // prolly need to resolve modelnumber properly - for now just use our
\r
1098 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
\r
1100 pdbfhash = "" + pdbfile.hashCode();
\r
1102 if (pdbentry != null)
\r
1104 // search pdbentries and sequences to find correct pdbentry for this
\r
1106 for (int pe = 0; pe < pdbentry.length; pe++)
\r
1108 boolean matches = false;
\r
1109 if (fileName == null)
\r
1112 // see JAL-623 - need method of matching pasted data up
\r
1114 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
\r
1115 AppletFormatAdapter.PASTE);
\r
1116 pdbentry[modelnum].setFile("INLINE" + pdb.id);
\r
1118 foundEntry = true;
\r
1123 if (matches = pdbentry[pe].getFile().equals(fileName))
\r
1125 foundEntry = true;
\r
1126 // TODO: Jmol can in principle retrieve from CLASSLOADER but
\r
1129 // to be tested. See mantis bug
\r
1130 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
\r
1131 String protocol = AppletFormatAdapter.URL;
\r
1134 File fl = new java.io.File(pdbentry[pe].getFile());
\r
1137 protocol = AppletFormatAdapter.FILE;
\r
1139 } catch (Exception e)
\r
1145 pdb = ssm.setMapping(sequence[pe], chains[pe],
\r
1146 pdbentry[pe].getFile(), protocol);
\r
1152 // add an entry for every chain in the model
\r
1153 for (int i = 0; i < pdb.chains.size(); i++)
\r
1155 String chid = new String(pdb.id + ":"
\r
1156 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
\r
1157 chainFile.put(chid, pdbentry[pe].getFile());
\r
1158 chainNames.addElement(chid);
\r
1160 notifyLoaded = true;
\r
1164 if (!foundEntry && associateNewStructs)
\r
1166 // this is a foreign pdb file that jalview doesn't know about - add
\r
1167 // it to the dataset and try to find a home - either on a matching
\r
1168 // sequence or as a new sequence.
\r
1169 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
\r
1171 // parse pdb file into a chain, etc.
\r
1172 // locate best match for pdb in associated views and add mapping to
\r
1174 // if properly registered then
\r
1175 notifyLoaded = true;
\r
1180 // so finally, update the jmol bits and pieces
\r
1181 if (jmolpopup != null)
\r
1183 // potential for deadlock here:
\r
1184 // jmolpopup.updateComputedMenus();
\r
1186 if (!isLoadingFromArchive())
\r
1188 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
\r
1190 // register ourselves as a listener and notify the gui that it needs to
\r
1192 ssm.addStructureViewerListener(this);
\r
1195 FeatureRenderer fr = getFeatureRenderer(null);
\r
1198 fr.featuresAdded();
\r
1201 loadNotifiesHandled++;
\r
1203 setLoadingFromArchive(false);
\r
1206 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
\r
1208 notifyAtomPicked(iatom, strMeasure, null);
\r
1211 public abstract void notifyScriptTermination(String strStatus,
\r
1215 * display a message echoed from the jmol viewer
\r
1219 public abstract void sendConsoleEcho(String strEcho); /*
\r
1220 * { showConsole(true);
\r
1222 * history.append("\n" +
\r
1226 // /End JmolStatusListener
\r
1227 // /////////////////////////////
\r
1230 * @param strStatus
\r
1231 * status message - usually the response received after a script
\r
1234 public abstract void sendConsoleMessage(String strStatus);
\r
1236 public void setCallbackFunction(String callbackType,
\r
1237 String callbackFunction)
\r
1239 System.err.println("Ignoring set-callback request to associate "
\r
1240 + callbackType + " with function " + callbackFunction);
\r
1244 public void setJalviewColourScheme(ColourSchemeI cs)
\r
1246 colourBySequence = false;
\r
1254 jmolHistory(false);
\r
1255 // TODO: Switch between nucleotide or aa selection expressions
\r
1256 Enumeration en = ResidueProperties.aa3Hash.keys();
\r
1257 StringBuffer command = new StringBuffer("select *;color white;");
\r
1258 while (en.hasMoreElements())
\r
1260 res = en.nextElement().toString();
\r
1261 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
\r
1265 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
\r
1267 command.append("select " + res + ";color[" + col.getRed() + ","
\r
1268 + col.getGreen() + "," + col.getBlue() + "];");
\r
1271 evalStateCommand(command.toString());
\r
1272 jmolHistory(true);
\r
1275 public void showHelp()
\r
1277 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
\r
1281 * open the URL somehow
\r
1285 public abstract void showUrl(String url, String target);
\r
1288 * called when the binding thinks the UI needs to be refreshed after a Jmol
\r
1289 * state change. this could be because structures were loaded, or because an
\r
1290 * error has occured.
\r
1292 public abstract void refreshGUI();
\r
1295 * called to show or hide the associated console window container.
\r
1299 public abstract void showConsole(boolean show);
\r
1302 * @param renderPanel
\r
1303 * @param jmolfileio
\r
1304 * - when true will initialise jmol's file IO system (should be false
\r
1305 * in applet context)
\r
1307 * @param documentBase
\r
1309 * @param commandOptions
\r
1311 public void allocateViewer(Container renderPanel, boolean jmolfileio,
\r
1312 String htmlName, URL documentBase, URL codeBase,
\r
1313 String commandOptions)
\r
1315 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
\r
1316 codeBase, commandOptions, null, null);
\r
1321 * @param renderPanel
\r
1322 * @param jmolfileio
\r
1323 * - when true will initialise jmol's file IO system (should be false
\r
1324 * in applet context)
\r
1326 * @param documentBase
\r
1328 * @param commandOptions
\r
1329 * @param consolePanel
\r
1330 * - panel to contain Jmol console
\r
1331 * @param buttonsToShow
\r
1332 * - buttons to show on the console, in ordr
\r
1334 public void allocateViewer(Container renderPanel, boolean jmolfileio,
\r
1335 String htmlName, URL documentBase, URL codeBase,
\r
1336 String commandOptions, final Container consolePanel,
\r
1337 String buttonsToShow)
\r
1339 if (commandOptions==null) {
1342 viewer = JmolViewer.allocateViewer(renderPanel,
\r
1343 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
\r
1344 + ((Object) this).toString(), documentBase, codeBase,
\r
1345 commandOptions, this);
\r
1347 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
\r
1348 if (consolePanel != null)
\r
1350 consolePanel.addComponentListener(this);
\r
1356 protected abstract JmolAppConsoleInterface createJmolConsole(
\r
1357 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
\r
1359 protected org.jmol.api.JmolAppConsoleInterface console = null;
\r
1361 public void componentResized(ComponentEvent e)
\r
1366 public void componentMoved(ComponentEvent e)
\r
1371 public void componentShown(ComponentEvent e)
\r
1373 showConsole(true);
\r
1376 public void componentHidden(ComponentEvent e)
\r
1378 showConsole(false);
\r
1381 public void setLoadingFromArchive(boolean loadingFromArchive)
\r
1383 this.loadingFromArchive = loadingFromArchive;
\r
1386 public boolean isLoadingFromArchive()
\r
1388 return loadingFromArchive;
\r
1391 public void setBackgroundColour(java.awt.Color col)
\r
1393 jmolHistory(false);
\r
1394 viewer.evalStringQuiet("background [" + col.getRed() + ","
\r
1395 + col.getGreen() + "," + col.getBlue() + "];");
\r
1396 jmolHistory(true);
\r
1400 * add structures and any known sequence associations
\r
1402 * @returns the pdb entries added to the current set.
\r
1404 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
\r
1405 SequenceI[][] seq, String[][] chns)
\r
1408 Vector v = new Vector();
\r
1409 Vector rtn = new Vector();
\r
1410 for (int i = 0; i < pdbentry.length; i++)
\r
1412 v.addElement(pdbentry[i]);
\r
1414 for (int i = 0; i < pdbe.length; i++)
\r
1416 int r = v.indexOf(pdbe[i]);
\r
1417 if (r == -1 || r >= pdbentry.length)
\r
1419 rtn.addElement(new int[]
\r
1421 v.addElement(pdbe[i]);
\r
1425 // just make sure the sequence/chain entries are all up to date
\r
1426 addSequenceAndChain(r, seq[i], chns[i]);
\r
1429 pdbe = new PDBEntry[v.size()];
\r
1432 if (rtn.size() > 0)
\r
1434 // expand the tied seuqence[] and string[] arrays
\r
1435 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
\r
1436 String[][] sch = new String[pdbentry.length][];
\r
1437 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
\r
1438 System.arraycopy(chains, 0, sch, 0, this.chains.length);
\r
1441 pdbe = new PDBEntry[rtn.size()];
\r
1442 for (int r = 0; r < pdbe.length; r++)
\r
1444 int[] stri = ((int[]) rtn.elementAt(r));
\r
1445 // record the pdb file as a new addition
\r
1446 pdbe[r] = pdbentry[stri[0]];
\r
1447 // and add the new sequence/chain entries
\r
1448 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
\r
1458 public void addSequence(int pe, SequenceI[] seq)
\r
1460 // add sequences to the pe'th pdbentry's seuqence set.
\r
1461 addSequenceAndChain(pe, seq, null);
\r
1464 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
\r
1466 if (pe < 0 || pe >= pdbentry.length)
\r
1469 "Implementation error - no corresponding pdbentry (for index "
\r
1470 + pe + ") to add sequences mappings to");
\r
1472 final String nullChain = "TheNullChain";
\r
1473 Vector s = new Vector();
\r
1474 Vector c = new Vector();
\r
1475 if (chains == null)
\r
1477 chains = new String[pdbentry.length][];
\r
1479 if (sequence[pe] != null)
\r
1481 for (int i = 0; i < sequence[pe].length; i++)
\r
1483 s.addElement(sequence[pe][i]);
\r
1484 if (chains[pe] != null)
\r
1486 if (i < chains[pe].length)
\r
1488 c.addElement(chains[pe][i]);
\r
1492 c.addElement(nullChain);
\r
1497 if (tchain != null && tchain.length > 0)
\r
1499 c.addElement(nullChain);
\r
1504 for (int i = 0; i < seq.length; i++)
\r
1506 if (!s.contains(seq[i]))
\r
1508 s.addElement(seq[i]);
\r
1509 if (tchain != null && i < tchain.length)
\r
1511 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
\r
1515 SequenceI[] tmp = new SequenceI[s.size()];
\r
1517 sequence[pe] = tmp;
\r
1520 String[] tch = new String[c.size()];
\r
1522 for (int i = 0; i < tch.length; i++)
\r
1524 if (tch[i] == nullChain)
\r
1533 chains[pe] = null;
\r
1539 * @return text report of alignment between pdbfile and any associated alignment sequences
\r
1541 public String printMapping(String pdbfile)
\r
1543 return ssm.printMapping(pdbfile);
\r