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.varna;
\r
20 import java.io.File;
\r
22 import java.net.URL;
\r
24 import java.applet.Applet;
\r
26 import java.awt.event.*;
\r
28 import javax.swing.JPanel;
\r
30 import jalview.api.AlignmentViewPanel;
\r
31 import jalview.api.FeatureRenderer;
\r
32 import jalview.api.SequenceRenderer;
\r
33 import jalview.api.SequenceStructureBinding;
\r
34 import jalview.api.StructureSelectionManagerProvider;
\r
35 import jalview.datamodel.*;
\r
36 import jalview.structure.*;
\r
37 import jalview.io.*;
\r
39 import org.jmol.api.*;
\r
40 import org.jmol.adapter.smarter.SmarterJmolAdapter;
\r
42 import org.jmol.popup.*;
\r
43 import org.jmol.viewer.JmolConstants;
\r
44 import org.jmol.viewer.Viewer;
\r
46 import jalview.schemes.*;
\r
48 import fr.orsay.lri.varna.applications.*;
\r
51 public abstract class JalviewVarnaBinding implements StructureListener,
\r
52 JmolStatusListener, SequenceStructureBinding,
\r
53 JmolSelectionListener, ComponentListener, StructureSelectionManagerProvider
\r
57 * set if Jmol state is being restored from some source - instructs binding
\r
58 * not to apply default display style when structure set is updated for first
\r
61 private boolean loadingFromArchive = false;
\r
64 * state flag used to check if the Jmol viewer's paint method can be called
\r
66 private boolean finishedInit = false;
\r
68 public boolean isFinishedInit()
\r
70 return finishedInit;
\r
73 public void setFinishedInit(boolean finishedInit)
\r
75 this.finishedInit = finishedInit;
\r
78 boolean allChainsSelected = false;
\r
81 * when true, try to search the associated datamodel for sequences that are
\r
82 * associated with any unknown structures in the Jmol view.
\r
84 private boolean associateNewStructs = false;
\r
86 Vector atomsPicked = new Vector();
\r
88 public Vector chainNames;
\r
90 Hashtable chainFile;
\r
93 * array of target chains for seuqences - tied to pdbentry and sequence[]
\r
95 protected String[][] chains;
\r
97 boolean colourBySequence = true;
\r
99 StringBuffer eval = new StringBuffer();
\r
101 public String fileLoadingError;
\r
104 * the default or current model displayed if the model cannot be identified
\r
105 * from the selection message
\r
109 protected JmolPopup jmolpopup;
\r
111 protected VARNAGUI varnagui;
\r
113 String lastCommand;
\r
115 String lastMessage;
\r
117 boolean loadedInline;
\r
120 * current set of model filenames loaded in the Jmol instance
\r
122 String[] modelFileNames = null;
\r
124 public PDBEntry[] pdbentry;
\r
127 * datasource protocol for access to PDBEntrylatest
\r
129 String protocol = null;
\r
131 StringBuffer resetLastRes = new StringBuffer();
\r
134 * sequences mapped to each pdbentry
\r
136 public SequenceI[][] sequence;
\r
138 public StructureSelectionManager ssm;
\r
140 public JmolViewer viewer;
\r
142 public JalviewVarnaBinding(StructureSelectionManager ssm, PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
\r
143 String[][] chains, String protocol)
\r
146 this.sequence = sequenceIs;
\r
147 this.chains = chains;
\r
148 this.pdbentry = pdbentry;
\r
149 this.protocol = protocol;
\r
150 if (chains == null)
\r
152 this.chains = new String[pdbentry.length][];
\r
155 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
\r
156 * "jalviewJmol", ap.av.applet .getDocumentBase(),
\r
157 * ap.av.applet.getCodeBase(), "", this);
\r
159 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
\r
163 public JalviewVarnaBinding(StructureSelectionManager ssm, JmolViewer viewer2)
\r
167 viewer.setJmolStatusListener(this);
\r
168 viewer.addSelectionListener(this);
\r
172 * construct a title string for the viewer window based on the data jalview
\r
177 public String getViewerTitle()
\r
179 if (sequence == null || pdbentry == null || sequence.length < 1
\r
180 || pdbentry.length < 1 || sequence[0].length < 1)
\r
182 return ("Jalview Jmol Window");
\r
184 // TODO: give a more informative title when multiple structures are
\r
186 StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
\r
187 + pdbentry[0].getId());
\r
189 if (pdbentry[0].getProperty() != null)
\r
191 if (pdbentry[0].getProperty().get("method") != null)
\r
193 title.append(" Method: ");
\r
194 title.append(pdbentry[0].getProperty().get("method"));
\r
196 if (pdbentry[0].getProperty().get("chains") != null)
\r
198 title.append(" Chain:");
\r
199 title.append(pdbentry[0].getProperty().get("chains"));
\r
202 return title.toString();
\r
206 * prepare the view for a given set of models/chains. chainList contains
\r
207 * strings of the form 'pdbfilename:Chaincode'
\r
210 * list of chains to make visible
\r
212 public void centerViewer(Vector chainList)
\r
214 StringBuffer cmd = new StringBuffer();
\r
217 for (int i = 0, iSize = chainList.size(); i < iSize; i++)
\r
220 lbl = (String) chainList.elementAt(i);
\r
224 mlength = lbl.indexOf(":", p);
\r
225 } while (p < mlength && mlength < (lbl.length() - 2));
\r
226 // TODO: lookup each pdb id and recover proper model number for it.
\r
227 cmd.append(":" + lbl.substring(mlength + 1) + " /"
\r
228 + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");
\r
230 if (cmd.length() > 0)
\r
231 cmd.setLength(cmd.length() - 4);
\r
232 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
\r
235 public void closeViewer()
\r
237 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
\r
238 // remove listeners for all structures in viewer
\r
239 ssm.removeStructureViewerListener(this, this.getPdbFile());
\r
240 // and shut down jmol
\r
241 viewer.evalStringQuiet("zap");
\r
242 viewer.setJmolStatusListener(null);
\r
243 lastCommand = null;
\r
245 releaseUIResources();
\r
249 * called by JalviewJmolbinding after closeViewer is called - release any
\r
250 * resources and references so they can be garbage collected.
\r
252 protected abstract void releaseUIResources();
\r
254 public void colourByChain()
\r
256 colourBySequence = false;
\r
257 // TODO: colour by chain should colour each chain distinctly across all
\r
259 // TODO: http://issues.jalview.org/browse/JAL-628
\r
260 evalStateCommand("select *;color chain");
\r
263 public void colourByCharge()
\r
265 colourBySequence = false;
\r
266 evalStateCommand("select *;color white;select ASP,GLU;color red;"
\r
267 + "select LYS,ARG;color blue;select CYS;color yellow");
\r
271 * superpose the structures associated with sequences in the alignment
\r
272 * according to their corresponding positions.
\r
274 public void superposeStructures(AlignmentI alignment)
\r
276 superposeStructures(alignment, -1, null);
\r
280 * superpose the structures associated with sequences in the alignment
\r
281 * according to their corresponding positions. ded)
\r
283 * @param refStructure
\r
284 * - select which pdb file to use as reference (default is -1 - the
\r
285 * first structure in the alignment)
\r
287 public void superposeStructures(AlignmentI alignment, int refStructure)
\r
289 superposeStructures(alignment, refStructure, null);
\r
293 * superpose the structures associated with sequences in the alignment
\r
294 * according to their corresponding positions. ded)
\r
296 * @param refStructure
\r
297 * - select which pdb file to use as reference (default is -1 - the
\r
298 * first structure in the alignment)
\r
299 * @param hiddenCols
\r
302 public void superposeStructures(AlignmentI alignment, int refStructure,
\r
303 ColumnSelection hiddenCols)
\r
305 superposeStructures(new AlignmentI[]
\r
306 { alignment }, new int[]
\r
307 { refStructure }, new ColumnSelection[]
\r
311 public void superposeStructures(AlignmentI[] _alignment,
\r
312 int[] _refStructure, ColumnSelection[] _hiddenCols)
\r
314 String[] files = getPdbFile();
\r
315 StringBuffer selectioncom = new StringBuffer();
\r
316 assert (_alignment.length == _refStructure.length && _alignment.length != _hiddenCols.length);
\r
317 // union of all aligned positions are collected together.
\r
318 for (int a = 0; a < _alignment.length; a++)
\r
320 int refStructure = _refStructure[a];
\r
321 AlignmentI alignment = _alignment[a];
\r
322 ColumnSelection hiddenCols = _hiddenCols[a];
\r
324 && selectioncom.length() > 0
\r
325 && !selectioncom.substring(selectioncom.length() - 1).equals(
\r
328 selectioncom.append("|");
\r
330 // process this alignment
\r
331 if (refStructure >= files.length)
\r
333 System.err.println("Invalid reference structure value "
\r
337 if (refStructure < -1)
\r
341 StringBuffer command = new StringBuffer();
\r
343 boolean matched[] = new boolean[alignment.getWidth()];
\r
344 for (int m = 0; m < matched.length; m++)
\r
347 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
\r
350 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
\r
351 String isel[] = new String[files.length];
\r
352 // reference structure - all others are superposed in it
\r
353 String[] targetC = new String[files.length];
\r
354 String[] chainNames = new String[files.length];
\r
355 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
\r
357 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
\r
359 if (mapping == null || mapping.length < 1)
\r
363 for (int s = 0; s < sequence[pdbfnum].length; s++)
\r
365 for (int sp, m = 0; m < mapping.length; m++)
\r
367 if (mapping[m].getSequence() == sequence[pdbfnum][s]
\r
368 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
\r
370 if (refStructure == -1)
\r
372 refStructure = pdbfnum;
\r
374 SequenceI asp = alignment.getSequenceAt(sp);
\r
375 for (int r = 0; r < matched.length; r++)
\r
381 matched[r] = false; // assume this is not a good site
\r
382 if (r >= asp.getLength())
\r
387 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
\r
389 // no mapping to gaps in sequence
\r
392 int t = asp.findPosition(r); // sequence position
\r
393 int apos = mapping[m].getAtomNum(t);
\r
394 int pos = mapping[m].getPDBResNum(t);
\r
396 if (pos < 1 || pos == lastPos)
\r
398 // can't align unmapped sequence
\r
401 matched[r] = true; // this is a good ite
\r
403 // just record this residue position
\r
404 commonrpositions[pdbfnum][r] = pos;
\r
406 // create model selection suffix
\r
407 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
\r
408 if (mapping[m].getChain() == null
\r
409 || mapping[m].getChain().trim().length() == 0)
\r
411 targetC[pdbfnum] = "";
\r
415 targetC[pdbfnum] = ":" + mapping[m].getChain();
\r
417 chainNames[pdbfnum] = mapping[m].getPdbId()
\r
418 + targetC[pdbfnum];
\r
419 // move on to next pdb file
\r
420 s = sequence[pdbfnum].length;
\r
426 String[] selcom = new String[files.length];
\r
428 // generate select statements to select regions to superimpose structures
\r
430 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
\r
432 String chainCd = targetC[pdbfnum];
\r
434 boolean run = false;
\r
435 StringBuffer molsel = new StringBuffer();
\r
436 molsel.append("{");
\r
437 for (int r = 0; r < matched.length; r++)
\r
445 if (lpos != commonrpositions[pdbfnum][r] - 1)
\r
450 molsel.append(lpos);
\r
451 molsel.append(chainCd);
\r
452 // molsel.append("} {");
\r
453 molsel.append("|");
\r
458 // continuous run - and lpos >-1
\r
461 // at the beginning, so add dash
\r
462 molsel.append(lpos);
\r
463 molsel.append("-");
\r
467 lpos = commonrpositions[pdbfnum][r];
\r
468 // molsel.append(lpos);
\r
471 // add final selection phrase
\r
474 molsel.append(lpos);
\r
475 molsel.append(chainCd);
\r
476 molsel.append("}");
\r
478 selcom[pdbfnum] = molsel.toString();
\r
479 selectioncom.append("((");
\r
480 selectioncom.append(selcom[pdbfnum].substring(1,
\r
481 selcom[pdbfnum].length() - 1));
\r
482 selectioncom.append(" )& ");
\r
483 selectioncom.append(pdbfnum + 1);
\r
484 selectioncom.append(".1)");
\r
485 if (pdbfnum < files.length - 1)
\r
487 selectioncom.append("|");
\r
491 // TODO: consider bailing if nmatched less than 4 because superposition
\r
494 // TODO: refactor superposable position search (above) from jmol selection
\r
495 // construction (below)
\r
496 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
\r
498 if (pdbfnum == refStructure)
\r
502 command.append("echo ");
\r
503 command.append("\"Superposing (");
\r
504 command.append(chainNames[pdbfnum]);
\r
505 command.append(") against reference (");
\r
506 command.append(chainNames[refStructure]);
\r
507 command.append(")\";\ncompare ");
\r
508 command.append("{");
\r
509 command.append(1 + pdbfnum);
\r
510 command.append(".1} {");
\r
511 command.append(1 + refStructure);
\r
512 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
\r
514 // form the matched pair strings
\r
516 for (int s = 0; s < 2; s++)
\r
518 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
\r
520 command.append(" ROTATE TRANSLATE;\n");
\r
522 System.out.println("Select regions:\n" + selectioncom.toString());
\r
523 evalStateCommand("select *; cartoons off; backbone; select ("
\r
524 + selectioncom.toString() + "); cartoons; ");
\r
525 // selcom.append("; ribbons; ");
\r
526 System.out.println("Superimpose command(s):\n" + command.toString());
\r
528 evalStateCommand(command.toString());
\r
530 if (selectioncom.length() > 0)
\r
531 {// finally, mark all regions that were superposed.
\r
532 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
\r
534 selectioncom.setLength(selectioncom.length() - 1);
\r
536 System.out.println("Select regions:\n" + selectioncom.toString());
\r
537 evalStateCommand("select *; cartoons off; backbone; select ("
\r
538 + selectioncom.toString() + "); cartoons; ");
\r
539 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
\r
543 public void evalStateCommand(String command)
\r
545 jmolHistory(false);
\r
546 if (lastCommand == null || !lastCommand.equals(command))
\r
548 viewer.evalStringQuiet(command + "\n");
\r
551 lastCommand = command;
\r
555 * colour any structures associated with sequences in the given alignment
\r
556 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
\r
557 * if colourBySequence is enabled.
\r
559 public void colourBySequence(boolean showFeatures,
\r
560 jalview.api.AlignmentViewPanel alignmentv)
\r
562 if (!colourBySequence)
\r
568 String[] files = getPdbFile();
\r
570 SequenceRenderer sr = getSequenceRenderer(alignmentv);
\r
572 FeatureRenderer fr = null;
\r
575 fr = getFeatureRenderer(alignmentv);
\r
577 AlignmentI alignment = alignmentv.getAlignment();
\r
579 for (String cbyseq : VarnaCommands.getColourBySequenceCommand(ssm, files, sequence, sr, fr, alignment)) {
\r
580 evalStateCommand(cbyseq);
\r
584 public boolean isColourBySequence()
\r
586 return colourBySequence;
\r
589 public void setColourBySequence(boolean colourBySequence)
\r
591 this.colourBySequence = colourBySequence;
\r
594 public void createImage(String file, String type, int quality)
\r
596 System.out.println("JMOL CREATE IMAGE");
\r
599 public String createImage(String fileName, String type,
\r
600 Object textOrBytes, int quality)
\r
602 System.out.println("JMOL CREATE IMAGE");
\r
606 public String eval(String strEval)
\r
608 // System.out.println(strEval);
\r
609 // "# 'eval' is implemented only for the applet.";
\r
613 // End StructureListener
\r
614 // //////////////////////////
\r
616 public float[][] functionXY(String functionName, int x, int y)
\r
621 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
\r
623 // TODO Auto-generated method stub
\r
627 public Color getColour(int atomIndex, int pdbResNum, String chain,
\r
630 if (getModelNum(pdbfile) < 0)
\r
632 // TODO: verify atomIndex is selecting correct model.
\r
633 return new Color(viewer.getAtomArgb(atomIndex));
\r
637 * returns the current featureRenderer that should be used to colour the
\r
644 public abstract FeatureRenderer getFeatureRenderer(
\r
645 AlignmentViewPanel alignment);
\r
648 * instruct the Jalview binding to update the pdbentries vector if necessary
\r
649 * prior to matching the jmol view's contents to the list of structure files
\r
650 * Jalview knows about.
\r
652 public abstract void refreshPdbEntries();
\r
654 private int getModelNum(String modelFileName)
\r
656 String[] mfn = getPdbFile();
\r
661 for (int i = 0; i < mfn.length; i++)
\r
663 if (mfn[i].equalsIgnoreCase(modelFileName))
\r
670 * map between index of model filename returned from getPdbFile and the first
\r
671 * index of models from this file in the viewer. Note - this is not trimmed -
\r
672 * use getPdbFile to get number of unique models.
\r
674 private int _modelFileNameMap[];
\r
676 // ////////////////////////////////
\r
677 // /StructureListener
\r
678 public synchronized String[] getPdbFile()
\r
680 if (viewer == null)
\r
682 return new String[0];
\r
684 if (modelFileNames == null)
\r
687 String mset[] = new String[viewer.getModelCount()];
\r
688 _modelFileNameMap = new int[mset.length];
\r
690 mset[0] = viewer.getModelFileName(0);
\r
691 for (int i = 1; i < mset.length; i++)
\r
693 mset[j] = viewer.getModelFileName(i);
\r
694 _modelFileNameMap[j] = i; // record the model index for the filename
\r
695 // skip any additional models in the same file (NMR structures)
\r
696 if ((mset[j] == null ? mset[j] != mset[j - 1]
\r
697 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
\r
702 modelFileNames = new String[j];
\r
703 System.arraycopy(mset, 0, modelFileNames, 0, j);
\r
705 return modelFileNames;
\r
709 * map from string to applet
\r
711 public Map getRegistryInfo()
\r
713 // TODO Auto-generated method stub
\r
718 * returns the current sequenceRenderer that should be used to colour the
\r
725 public abstract SequenceRenderer getSequenceRenderer(
\r
726 AlignmentViewPanel alignment);
\r
728 // ///////////////////////////////
\r
729 // JmolStatusListener
\r
731 public void handlePopupMenu(int x, int y)
\r
733 jmolpopup.show(x, y);
\r
737 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
\r
740 if (modelFileNames == null)
\r
745 // look up file model number for this pdbfile
\r
748 // may need to adjust for URLencoding here - we don't worry about that yet.
\r
749 while (mdlNum < modelFileNames.length
\r
750 && !pdbfile.equals(modelFileNames[mdlNum]))
\r
752 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
\r
755 if (mdlNum == modelFileNames.length)
\r
760 jmolHistory(false);
\r
761 // if (!pdbfile.equals(pdbentry.getFile()))
\r
763 if (resetLastRes.length() > 0)
\r
765 viewer.evalStringQuiet(resetLastRes.toString());
\r
769 eval.append("select " + pdbResNum); // +modelNum
\r
771 resetLastRes.setLength(0);
\r
772 resetLastRes.append("select " + pdbResNum); // +modelNum
\r
775 resetLastRes.append(":");
\r
776 if (!chain.equals(" "))
\r
778 eval.append(chain);
\r
779 resetLastRes.append(chain);
\r
782 eval.append(" /" + (mdlNum + 1));
\r
783 resetLastRes.append("/" + (mdlNum + 1));
\r
785 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
\r
787 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
\r
788 + " and not hetero; spacefill 0;");
\r
790 eval.append("spacefill 200;select none");
\r
792 viewer.evalStringQuiet(eval.toString());
\r
797 boolean debug = true;
\r
799 private void jmolHistory(boolean enable)
\r
801 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
\r
804 public void loadInline(String string)
\r
806 loadedInline = true;
\r
807 // TODO: re JAL-623
\r
808 // viewer.loadInline(strModel, isAppend);
\r
810 // construct fake fullPathName and fileName so we can identify the file
\r
812 // Then, construct pass a reader for the string to Jmol.
\r
813 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
\r
814 // fileName, null, reader, false, null, null, 0);
\r
815 viewer.openStringInline(string);
\r
818 public void mouseOverStructure(int atomIndex, String strInfo)
\r
821 int alocsep = strInfo.indexOf("^");
\r
822 int mdlSep = strInfo.indexOf("/");
\r
823 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
\r
825 if (chainSeparator == -1)
\r
827 chainSeparator = strInfo.indexOf(".");
\r
828 if (mdlSep > -1 && mdlSep < chainSeparator)
\r
830 chainSeparator1 = chainSeparator;
\r
831 chainSeparator = mdlSep;
\r
834 // handle insertion codes
\r
837 pdbResNum = Integer.parseInt(strInfo.substring(
\r
838 strInfo.indexOf("]") + 1, alocsep));
\r
843 pdbResNum = Integer.parseInt(strInfo.substring(
\r
844 strInfo.indexOf("]") + 1, chainSeparator));
\r
848 if (strInfo.indexOf(":") > -1)
\r
849 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
\r
850 strInfo.indexOf("."));
\r
856 String pdbfilename = modelFileNames[frameNo]; // default is first or current
\r
860 if (chainSeparator1 == -1)
\r
862 chainSeparator1 = strInfo.indexOf(".", mdlSep);
\r
864 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
\r
865 chainSeparator1) : strInfo.substring(mdlSep + 1);
\r
868 // recover PDB filename for the model hovered over.
\r
869 pdbfilename = viewer
\r
870 .getModelFileName(new Integer(mdlId).intValue() - 1);
\r
871 } catch (Exception e)
\r
876 if (lastMessage == null || !lastMessage.equals(strInfo))
\r
877 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
\r
879 lastMessage = strInfo;
\r
882 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
\r
886 System.err.println("Ignoring additional hover info: " + data
\r
887 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
\r
889 mouseOverStructure(atomIndex, strInfo);
\r
893 * { if (history != null && strStatus != null &&
\r
894 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
\r
898 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
\r
901 * this implements the toggle label behaviour copied from the original
\r
902 * structure viewer, MCView
\r
904 if (strData != null)
\r
906 System.err.println("Ignoring additional pick data string " + strData);
\r
908 int chainSeparator = strInfo.indexOf(":");
\r
910 if (chainSeparator == -1)
\r
911 chainSeparator = strInfo.indexOf(".");
\r
913 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
\r
915 String mdlString = "";
\r
916 if ((p = strInfo.indexOf(":")) > -1)
\r
917 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
\r
919 if ((p = strInfo.indexOf("/")) > -1)
\r
921 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
\r
923 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
\r
924 + mdlString + "))";
\r
925 jmolHistory(false);
\r
927 if (!atomsPicked.contains(picked))
\r
929 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
\r
930 atomsPicked.addElement(picked);
\r
934 viewer.evalString("select " + picked + ";label off");
\r
935 atomsPicked.removeElement(picked);
\r
938 // TODO: in application this happens
\r
940 // if (scriptWindow != null)
\r
942 // scriptWindow.sendConsoleMessage(strInfo);
\r
943 // scriptWindow.sendConsoleMessage("\n");
\r
948 public void notifyCallback(int type, Object[] data)
\r
954 case JmolConstants.CALLBACK_LOADSTRUCT:
\r
955 notifyFileLoaded((String) data[1], (String) data[2],
\r
956 (String) data[3], (String) data[4],
\r
957 ((Integer) data[5]).intValue());
\r
960 case JmolConstants.CALLBACK_PICK:
\r
961 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
\r
963 // also highlight in alignment
\r
964 case JmolConstants.CALLBACK_HOVER:
\r
965 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
\r
968 case JmolConstants.CALLBACK_SCRIPT:
\r
969 notifyScriptTermination((String) data[2],
\r
970 ((Integer) data[3]).intValue());
\r
972 case JmolConstants.CALLBACK_ECHO:
\r
973 sendConsoleEcho((String) data[1]);
\r
975 case JmolConstants.CALLBACK_MESSAGE:
\r
976 sendConsoleMessage((data == null) ? ((String) null)
\r
977 : (String) data[1]);
\r
979 case JmolConstants.CALLBACK_ERROR:
\r
980 // System.err.println("Ignoring error callback.");
\r
982 case JmolConstants.CALLBACK_SYNC:
\r
983 case JmolConstants.CALLBACK_RESIZE:
\r
986 case JmolConstants.CALLBACK_MEASURE:
\r
988 case JmolConstants.CALLBACK_CLICK:
\r
990 System.err.println("Unhandled callback " + type + " "
\r
991 + data[1].toString());
\r
994 } catch (Exception e)
\r
996 System.err.println("Squashed Jmol callback handler error:");
\r
997 e.printStackTrace();
\r
1001 public boolean notifyEnabled(int callbackPick)
\r
1003 switch (callbackPick)
\r
1005 case JmolConstants.CALLBACK_ECHO:
\r
1006 case JmolConstants.CALLBACK_LOADSTRUCT:
\r
1007 case JmolConstants.CALLBACK_MEASURE:
\r
1008 case JmolConstants.CALLBACK_MESSAGE:
\r
1009 case JmolConstants.CALLBACK_PICK:
\r
1010 case JmolConstants.CALLBACK_SCRIPT:
\r
1011 case JmolConstants.CALLBACK_HOVER:
\r
1012 case JmolConstants.CALLBACK_ERROR:
\r
1014 case JmolConstants.CALLBACK_RESIZE:
\r
1015 case JmolConstants.CALLBACK_SYNC:
\r
1016 case JmolConstants.CALLBACK_CLICK:
\r
1017 case JmolConstants.CALLBACK_ANIMFRAME:
\r
1018 case JmolConstants.CALLBACK_MINIMIZATION:
\r
1023 // incremented every time a load notification is successfully handled -
\r
1024 // lightweight mechanism for other threads to detect when they can start
\r
1025 // referrring to new structures.
\r
1026 private long loadNotifiesHandled = 0;
\r
1028 public long getLoadNotifiesHandled()
\r
1030 return loadNotifiesHandled;
\r
1033 public void notifyFileLoaded(String fullPathName, String fileName2,
\r
1034 String modelName, String errorMsg, int modelParts)
\r
1036 if (errorMsg != null)
\r
1038 fileLoadingError = errorMsg;
\r
1042 // TODO: deal sensibly with models loaded inLine:
\r
1043 // modelName will be null, as will fullPathName.
\r
1045 // the rest of this routine ignores the arguments, and simply interrogates
\r
1046 // the Jmol view to find out what structures it contains, and adds them to
\r
1047 // the structure selection manager.
\r
1048 fileLoadingError = null;
\r
1049 String[] oldmodels = modelFileNames;
\r
1050 modelFileNames = null;
\r
1051 chainNames = new Vector();
\r
1052 chainFile = new Hashtable();
\r
1053 boolean notifyLoaded = false;
\r
1054 String[] modelfilenames = getPdbFile();
\r
1055 // first check if we've lost any structures
\r
1056 if (oldmodels != null && oldmodels.length > 0)
\r
1059 for (int i = 0; i < oldmodels.length; i++)
\r
1061 for (int n = 0; n < modelfilenames.length; n++)
\r
1063 if (modelfilenames[n] == oldmodels[i])
\r
1065 oldmodels[i] = null;
\r
1069 if (oldmodels[i] != null)
\r
1076 String[] oldmfn = new String[oldm];
\r
1078 for (int i = 0; i < oldmodels.length; i++)
\r
1080 if (oldmodels[i] != null)
\r
1082 oldmfn[oldm++] = oldmodels[i];
\r
1085 // deregister the Jmol instance for these structures - we'll add
\r
1086 // ourselves again at the end for the current structure set.
\r
1087 ssm.removeStructureViewerListener(this, oldmfn);
\r
1090 refreshPdbEntries();
\r
1091 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
\r
1093 String fileName = modelfilenames[modelnum];
\r
1094 boolean foundEntry = false;
\r
1095 MCview.PDBfile pdb = null;
\r
1096 String pdbfile = null, pdbfhash = null;
\r
1097 // model was probably loaded inline - so check the pdb file hashcode
\r
1100 // calculate essential attributes for the pdb data imported inline.
\r
1101 // prolly need to resolve modelnumber properly - for now just use our
\r
1103 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
\r
1105 pdbfhash = "" + pdbfile.hashCode();
\r
1107 if (pdbentry != null)
\r
1109 // search pdbentries and sequences to find correct pdbentry for this
\r
1111 for (int pe = 0; pe < pdbentry.length; pe++)
\r
1113 boolean matches = false;
\r
1114 if (fileName == null)
\r
1117 // see JAL-623 - need method of matching pasted data up
\r
1119 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
\r
1120 AppletFormatAdapter.PASTE);
\r
1121 pdbentry[modelnum].setFile("INLINE" + pdb.id);
\r
1123 foundEntry = true;
\r
1128 if (matches = pdbentry[pe].getFile().equals(fileName))
\r
1130 foundEntry = true;
\r
1131 // TODO: Jmol can in principle retrieve from CLASSLOADER but
\r
1134 // to be tested. See mantis bug
\r
1135 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
\r
1136 String protocol = AppletFormatAdapter.URL;
\r
1139 File fl = new java.io.File(pdbentry[pe].getFile());
\r
1142 protocol = AppletFormatAdapter.FILE;
\r
1144 } catch (Exception e)
\r
1150 pdb = ssm.setMapping(sequence[pe], chains[pe],
\r
1151 pdbentry[pe].getFile(), protocol);
\r
1157 pdbentry[pe].setId(pdb.id);
\r
1158 // add an entry for every chain in the model
\r
1159 for (int i = 0; i < pdb.chains.size(); i++)
\r
1161 String chid = new String(pdb.id + ":"
\r
1162 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
\r
1163 chainFile.put(chid, pdbentry[pe].getFile());
\r
1164 chainNames.addElement(chid);
\r
1166 notifyLoaded = true;
\r
1170 if (!foundEntry && associateNewStructs)
\r
1172 // this is a foreign pdb file that jalview doesn't know about - add
\r
1173 // it to the dataset and try to find a home - either on a matching
\r
1174 // sequence or as a new sequence.
\r
1175 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
\r
1177 // parse pdb file into a chain, etc.
\r
1178 // locate best match for pdb in associated views and add mapping to
\r
1180 // if properly registered then
\r
1181 notifyLoaded = true;
\r
1186 // so finally, update the jmol bits and pieces
\r
1187 if (jmolpopup != null)
\r
1189 // potential for deadlock here:
\r
1190 // jmolpopup.updateComputedMenus();
\r
1192 if (!isLoadingFromArchive())
\r
1194 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
\r
1196 // register ourselves as a listener and notify the gui that it needs to
\r
1198 ssm.addStructureViewerListener(this);
\r
1201 FeatureRenderer fr = getFeatureRenderer(null);
\r
1204 fr.featuresAdded();
\r
1207 loadNotifiesHandled++;
\r
1209 setLoadingFromArchive(false);
\r
1212 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
\r
1214 notifyAtomPicked(iatom, strMeasure, null);
\r
1217 public abstract void notifyScriptTermination(String strStatus,
\r
1221 * display a message echoed from the jmol viewer
\r
1225 public abstract void sendConsoleEcho(String strEcho); /*
\r
1226 * { showConsole(true);
\r
1228 * history.append("\n" +
\r
1232 // /End JmolStatusListener
\r
1233 // /////////////////////////////
\r
1236 * @param strStatus
\r
1237 * status message - usually the response received after a script
\r
1240 public abstract void sendConsoleMessage(String strStatus);
\r
1242 public void setCallbackFunction(String callbackType,
\r
1243 String callbackFunction)
\r
1245 System.err.println("Ignoring set-callback request to associate "
\r
1246 + callbackType + " with function " + callbackFunction);
\r
1250 public void setJalviewColourScheme(ColourSchemeI cs)
\r
1252 colourBySequence = false;
\r
1260 jmolHistory(false);
\r
1261 // TODO: Switch between nucleotide or aa selection expressions
\r
1262 Enumeration en = ResidueProperties.aa3Hash.keys();
\r
1263 StringBuffer command = new StringBuffer("select *;color white;");
\r
1264 while (en.hasMoreElements())
\r
1266 res = en.nextElement().toString();
\r
1267 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
\r
1271 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
\r
1273 command.append("select " + res + ";color[" + col.getRed() + ","
\r
1274 + col.getGreen() + "," + col.getBlue() + "];");
\r
1277 evalStateCommand(command.toString());
\r
1278 jmolHistory(true);
\r
1281 public void showHelp()
\r
1283 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
\r
1287 * open the URL somehow
\r
1291 public abstract void showUrl(String url, String target);
\r
1294 * called when the binding thinks the UI needs to be refreshed after a Jmol
\r
1295 * state change. this could be because structures were loaded, or because an
\r
1296 * error has occured.
\r
1298 public abstract void refreshGUI();
\r
1301 * called to show or hide the associated console window container.
\r
1305 public abstract void showConsole(boolean show);
\r
1308 * @param renderPanel
\r
1309 * @param jmolfileio
\r
1310 * - when true will initialise jmol's file IO system (should be false
\r
1311 * in applet context)
\r
1313 * @param documentBase
\r
1315 * @param commandOptions
\r
1317 public void allocateViewer(Container renderPanel, boolean jmolfileio,
\r
1318 String htmlName, URL documentBase, URL codeBase,
\r
1319 String commandOptions)
\r
1321 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
\r
1322 codeBase, commandOptions, null, null);
\r
1327 * @param renderPanel
\r
1328 * @param jmolfileio
\r
1329 * - when true will initialise jmol's file IO system (should be false
\r
1330 * in applet context)
\r
1332 * @param documentBase
\r
1334 * @param commandOptions
\r
1335 * @param consolePanel
\r
1336 * - panel to contain Jmol console
\r
1337 * @param buttonsToShow
\r
1338 * - buttons to show on the console, in ordr
\r
1340 public void allocateViewer(Container renderPanel, boolean jmolfileio,
\r
1341 String htmlName, URL documentBase, URL codeBase,
\r
1342 String commandOptions, final Container consolePanel,
\r
1343 String buttonsToShow)
\r
1345 if (commandOptions==null) {
1348 viewer = JmolViewer.allocateViewer(renderPanel,
\r
1349 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
\r
1350 + ((Object) this).toString(), documentBase, codeBase,
\r
1351 commandOptions, this);
\r
1353 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
\r
1354 if (consolePanel != null)
\r
1356 consolePanel.addComponentListener(this);
\r
1362 protected abstract JmolAppConsoleInterface createJmolConsole(
\r
1363 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
\r
1365 protected org.jmol.api.JmolAppConsoleInterface console = null;
\r
1367 public void componentResized(ComponentEvent e)
\r
1372 public void componentMoved(ComponentEvent e)
\r
1377 public void componentShown(ComponentEvent e)
\r
1379 showConsole(true);
\r
1382 public void componentHidden(ComponentEvent e)
\r
1384 showConsole(false);
\r
1387 public void setLoadingFromArchive(boolean loadingFromArchive)
\r
1389 this.loadingFromArchive = loadingFromArchive;
\r
1392 public boolean isLoadingFromArchive()
\r
1394 return loadingFromArchive;
\r
1397 public void setBackgroundColour(java.awt.Color col)
\r
1399 jmolHistory(false);
\r
1400 viewer.evalStringQuiet("background [" + col.getRed() + ","
\r
1401 + col.getGreen() + "," + col.getBlue() + "];");
\r
1402 jmolHistory(true);
\r
1406 * add structures and any known sequence associations
\r
1408 * @returns the pdb entries added to the current set.
\r
1410 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
\r
1411 SequenceI[][] seq, String[][] chns)
\r
1414 Vector v = new Vector();
\r
1415 Vector rtn = new Vector();
\r
1416 for (int i = 0; i < pdbentry.length; i++)
\r
1418 v.addElement(pdbentry[i]);
\r
1420 for (int i = 0; i < pdbe.length; i++)
\r
1422 int r = v.indexOf(pdbe[i]);
\r
1423 if (r == -1 || r >= pdbentry.length)
\r
1425 rtn.addElement(new int[]
\r
1427 v.addElement(pdbe[i]);
\r
1431 // just make sure the sequence/chain entries are all up to date
\r
1432 addSequenceAndChain(r, seq[i], chns[i]);
\r
1435 pdbe = new PDBEntry[v.size()];
\r
1438 if (rtn.size() > 0)
\r
1440 // expand the tied seuqence[] and string[] arrays
\r
1441 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
\r
1442 String[][] sch = new String[pdbentry.length][];
\r
1443 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
\r
1444 System.arraycopy(chains, 0, sch, 0, this.chains.length);
\r
1447 pdbe = new PDBEntry[rtn.size()];
\r
1448 for (int r = 0; r < pdbe.length; r++)
\r
1450 int[] stri = ((int[]) rtn.elementAt(r));
\r
1451 // record the pdb file as a new addition
\r
1452 pdbe[r] = pdbentry[stri[0]];
\r
1453 // and add the new sequence/chain entries
\r
1454 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
\r
1464 public void addSequence(int pe, SequenceI[] seq)
\r
1466 // add sequences to the pe'th pdbentry's seuqence set.
\r
1467 addSequenceAndChain(pe, seq, null);
\r
1470 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
\r
1472 if (pe < 0 || pe >= pdbentry.length)
\r
1475 "Implementation error - no corresponding pdbentry (for index "
\r
1476 + pe + ") to add sequences mappings to");
\r
1478 final String nullChain = "TheNullChain";
\r
1479 Vector s = new Vector();
\r
1480 Vector c = new Vector();
\r
1481 if (chains == null)
\r
1483 chains = new String[pdbentry.length][];
\r
1485 if (sequence[pe] != null)
\r
1487 for (int i = 0; i < sequence[pe].length; i++)
\r
1489 s.addElement(sequence[pe][i]);
\r
1490 if (chains[pe] != null)
\r
1492 if (i < chains[pe].length)
\r
1494 c.addElement(chains[pe][i]);
\r
1498 c.addElement(nullChain);
\r
1503 if (tchain != null && tchain.length > 0)
\r
1505 c.addElement(nullChain);
\r
1510 for (int i = 0; i < seq.length; i++)
\r
1512 if (!s.contains(seq[i]))
\r
1514 s.addElement(seq[i]);
\r
1515 if (tchain != null && i < tchain.length)
\r
1517 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
\r
1521 SequenceI[] tmp = new SequenceI[s.size()];
\r
1523 sequence[pe] = tmp;
\r
1526 String[] tch = new String[c.size()];
\r
1528 for (int i = 0; i < tch.length; i++)
\r
1530 if (tch[i] == nullChain)
\r
1539 chains[pe] = null;
\r
1545 * @return text report of alignment between pdbfile and any associated alignment sequences
\r
1547 public String printMapping(String pdbfile)
\r
1549 return ssm.printMapping(pdbfile);
\r