2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
\r
3 * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle
\r
5 * This file is part of Jalview.
\r
7 * Jalview is free software: you can redistribute it and/or
\r
8 * modify it under the terms of the GNU General Public License
\r
9 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
\r
11 * Jalview is distributed in the hope that it will be useful, but
\r
12 * WITHOUT ANY WARRANTY; without even the implied warranty
\r
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
14 * PURPOSE. See the GNU General Public License for more details.
\r
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
\r
18 package jalview.ext.jmol;
\r
20 import jalview.api.AlignmentViewPanel;
\r
21 import jalview.api.FeatureRenderer;
\r
22 import jalview.api.SequenceRenderer;
\r
23 import jalview.api.SequenceStructureBinding;
\r
24 import jalview.api.StructureSelectionManagerProvider;
\r
25 import jalview.datamodel.AlignmentI;
\r
26 import jalview.datamodel.ColumnSelection;
\r
27 import jalview.datamodel.PDBEntry;
\r
28 import jalview.datamodel.SequenceI;
\r
29 import jalview.io.AppletFormatAdapter;
\r
30 import jalview.schemes.ColourSchemeI;
\r
31 import jalview.schemes.ResidueProperties;
\r
32 import jalview.structure.StructureListener;
\r
33 import jalview.structure.StructureMapping;
\r
34 import jalview.structure.StructureSelectionManager;
\r
36 import java.awt.Color;
\r
37 import java.awt.Container;
\r
38 import java.awt.event.ComponentEvent;
\r
39 import java.awt.event.ComponentListener;
\r
40 import java.io.File;
\r
41 import java.net.URL;
\r
42 import java.security.AccessControlException;
\r
43 import java.util.Enumeration;
\r
44 import java.util.Hashtable;
\r
45 import java.util.Map;
\r
46 import java.util.Vector;
\r
48 import org.jmol.adapter.smarter.SmarterJmolAdapter;
\r
49 import org.jmol.api.JmolAppConsoleInterface;
\r
50 import org.jmol.api.JmolSelectionListener;
\r
51 import org.jmol.api.JmolStatusListener;
\r
52 import org.jmol.api.JmolViewer;
\r
53 import org.jmol.constant.EnumCallback;
\r
54 import org.jmol.popup.JmolPopup;
\r
56 public abstract class JalviewJmolBinding implements StructureListener,
\r
57 JmolStatusListener, SequenceStructureBinding,
\r
58 JmolSelectionListener, ComponentListener,
\r
59 StructureSelectionManagerProvider
\r
63 * set if Jmol state is being restored from some source - instructs binding
\r
64 * not to apply default display style when structure set is updated for first
\r
67 private boolean loadingFromArchive = false;
\r
70 * state flag used to check if the Jmol viewer's paint method can be called
\r
72 private boolean finishedInit = false;
\r
74 public boolean isFinishedInit()
\r
76 return finishedInit;
\r
79 public void setFinishedInit(boolean finishedInit)
\r
81 this.finishedInit = finishedInit;
\r
84 boolean allChainsSelected = false;
\r
87 * when true, try to search the associated datamodel for sequences that are
\r
88 * associated with any unknown structures in the Jmol view.
\r
90 private boolean associateNewStructs = false;
\r
92 Vector atomsPicked = new Vector();
\r
94 public Vector chainNames;
\r
96 Hashtable chainFile;
\r
99 * array of target chains for seuqences - tied to pdbentry and sequence[]
\r
101 protected String[][] chains;
\r
103 boolean colourBySequence = true;
\r
105 StringBuffer eval = new StringBuffer();
\r
107 public String fileLoadingError;
\r
110 * the default or current model displayed if the model cannot be identified
\r
111 * from the selection message
\r
115 protected JmolPopup jmolpopup;
\r
117 String lastCommand;
\r
119 String lastMessage;
\r
121 boolean loadedInline;
\r
124 * current set of model filenames loaded in the Jmol instance
\r
126 String[] modelFileNames = null;
\r
128 public PDBEntry[] pdbentry;
\r
131 * datasource protocol for access to PDBEntrylatest
\r
133 String protocol = null;
\r
135 StringBuffer resetLastRes = new StringBuffer();
\r
138 * sequences mapped to each pdbentry
\r
140 public SequenceI[][] sequence;
\r
142 public StructureSelectionManager ssm;
\r
144 public JmolViewer viewer;
\r
146 public JalviewJmolBinding(StructureSelectionManager ssm,
\r
147 PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
\r
151 this.sequence = sequenceIs;
\r
152 this.chains = chains;
\r
153 this.pdbentry = pdbentry;
\r
154 this.protocol = protocol;
\r
155 if (chains == null)
\r
157 this.chains = new String[pdbentry.length][];
\r
160 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
\r
161 * "jalviewJmol", ap.av.applet .getDocumentBase(),
\r
162 * ap.av.applet.getCodeBase(), "", this);
\r
164 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
\r
168 public JalviewJmolBinding(StructureSelectionManager ssm,
\r
169 JmolViewer viewer2)
\r
173 viewer.setJmolStatusListener(this);
\r
174 viewer.addSelectionListener(this);
\r
178 * construct a title string for the viewer window based on the data jalview
\r
183 public String getViewerTitle()
\r
185 if (sequence == null || pdbentry == null || sequence.length < 1
\r
186 || pdbentry.length < 1 || sequence[0].length < 1)
\r
188 return ("Jalview Jmol Window");
\r
190 // TODO: give a more informative title when multiple structures are
\r
192 StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
\r
193 + pdbentry[0].getId());
\r
195 if (pdbentry[0].getProperty() != null)
\r
197 if (pdbentry[0].getProperty().get("method") != null)
\r
199 title.append(" Method: ");
\r
200 title.append(pdbentry[0].getProperty().get("method"));
\r
202 if (pdbentry[0].getProperty().get("chains") != null)
\r
204 title.append(" Chain:");
\r
205 title.append(pdbentry[0].getProperty().get("chains"));
\r
208 return title.toString();
\r
212 * prepare the view for a given set of models/chains. chainList contains
\r
213 * strings of the form 'pdbfilename:Chaincode'
\r
216 * list of chains to make visible
\r
218 public void centerViewer(Vector chainList)
\r
220 StringBuffer cmd = new StringBuffer();
\r
223 for (int i = 0, iSize = chainList.size(); i < iSize; i++)
\r
226 lbl = (String) chainList.elementAt(i);
\r
230 mlength = lbl.indexOf(":", p);
\r
231 } while (p < mlength && mlength < (lbl.length() - 2));
\r
232 // TODO: lookup each pdb id and recover proper model number for it.
\r
233 cmd.append(":" + lbl.substring(mlength + 1) + " /"
\r
234 + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");
\r
236 if (cmd.length() > 0)
\r
237 cmd.setLength(cmd.length() - 4);
\r
238 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
\r
241 public void closeViewer()
\r
243 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
\r
244 // remove listeners for all structures in viewer
\r
245 ssm.removeStructureViewerListener(this, this.getPdbFile());
\r
246 // and shut down jmol
\r
247 viewer.evalStringQuiet("zap");
\r
248 viewer.setJmolStatusListener(null);
\r
249 lastCommand = null;
\r
251 releaseUIResources();
\r
255 * called by JalviewJmolbinding after closeViewer is called - release any
\r
256 * resources and references so they can be garbage collected.
\r
258 protected abstract void releaseUIResources();
\r
260 public void colourByChain()
\r
262 colourBySequence = false;
\r
263 // TODO: colour by chain should colour each chain distinctly across all
\r
265 // TODO: http://issues.jalview.org/browse/JAL-628
\r
266 evalStateCommand("select *;color chain");
\r
269 public void colourByCharge()
\r
271 colourBySequence = false;
\r
272 evalStateCommand("select *;color white;select ASP,GLU;color red;"
\r
273 + "select LYS,ARG;color blue;select CYS;color yellow");
\r
277 * superpose the structures associated with sequences in the alignment
\r
278 * according to their corresponding positions.
\r
280 public void superposeStructures(AlignmentI alignment)
\r
282 superposeStructures(alignment, -1, null);
\r
286 * superpose the structures associated with sequences in the alignment
\r
287 * according to their corresponding positions. ded)
\r
289 * @param refStructure
\r
290 * - select which pdb file to use as reference (default is -1 - the
\r
291 * first structure in the alignment)
\r
293 public void superposeStructures(AlignmentI alignment, int refStructure)
\r
295 superposeStructures(alignment, refStructure, null);
\r
299 * superpose the structures associated with sequences in the alignment
\r
300 * according to their corresponding positions. ded)
\r
302 * @param refStructure
\r
303 * - select which pdb file to use as reference (default is -1 - the
\r
304 * first structure in the alignment)
\r
305 * @param hiddenCols
\r
308 public void superposeStructures(AlignmentI alignment, int refStructure,
\r
309 ColumnSelection hiddenCols)
\r
311 superposeStructures(new AlignmentI[]
\r
312 { alignment }, new int[]
\r
313 { refStructure }, new ColumnSelection[]
\r
317 public void superposeStructures(AlignmentI[] _alignment,
\r
318 int[] _refStructure, ColumnSelection[] _hiddenCols)
\r
320 String[] files = getPdbFile();
\r
321 StringBuffer selectioncom = new StringBuffer();
\r
322 assert (_alignment.length == _refStructure.length && _alignment.length != _hiddenCols.length);
\r
323 // union of all aligned positions are collected together.
\r
324 for (int a = 0; a < _alignment.length; a++)
\r
326 int refStructure = _refStructure[a];
\r
327 AlignmentI alignment = _alignment[a];
\r
328 ColumnSelection hiddenCols = _hiddenCols[a];
\r
330 && selectioncom.length() > 0
\r
331 && !selectioncom.substring(selectioncom.length() - 1).equals(
\r
334 selectioncom.append("|");
\r
336 // process this alignment
\r
337 if (refStructure >= files.length)
\r
339 System.err.println("Invalid reference structure value "
\r
343 if (refStructure < -1)
\r
347 StringBuffer command = new StringBuffer();
\r
349 boolean matched[] = new boolean[alignment.getWidth()];
\r
350 for (int m = 0; m < matched.length; m++)
\r
353 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
\r
356 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
\r
357 String isel[] = new String[files.length];
\r
358 // reference structure - all others are superposed in it
\r
359 String[] targetC = new String[files.length];
\r
360 String[] chainNames = new String[files.length];
\r
361 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
\r
363 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
\r
364 // RACE CONDITION - getMapping only returns Jmol loaded filenames once
\r
365 // Jmol callback has completed.
\r
366 if (mapping == null || mapping.length < 1)
\r
370 for (int s = 0; s < sequence[pdbfnum].length; s++)
\r
372 for (int sp, m = 0; m < mapping.length; m++)
\r
374 if (mapping[m].getSequence() == sequence[pdbfnum][s]
\r
375 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
\r
377 if (refStructure == -1)
\r
379 refStructure = pdbfnum;
\r
381 SequenceI asp = alignment.getSequenceAt(sp);
\r
382 for (int r = 0; r < matched.length; r++)
\r
388 matched[r] = false; // assume this is not a good site
\r
389 if (r >= asp.getLength())
\r
394 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
\r
396 // no mapping to gaps in sequence
\r
399 int t = asp.findPosition(r); // sequence position
\r
400 int apos = mapping[m].getAtomNum(t);
\r
401 int pos = mapping[m].getPDBResNum(t);
\r
403 if (pos < 1 || pos == lastPos)
\r
405 // can't align unmapped sequence
\r
408 matched[r] = true; // this is a good ite
\r
410 // just record this residue position
\r
411 commonrpositions[pdbfnum][r] = pos;
\r
413 // create model selection suffix
\r
414 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
\r
415 if (mapping[m].getChain() == null
\r
416 || mapping[m].getChain().trim().length() == 0)
\r
418 targetC[pdbfnum] = "";
\r
422 targetC[pdbfnum] = ":" + mapping[m].getChain();
\r
424 chainNames[pdbfnum] = mapping[m].getPdbId()
\r
425 + targetC[pdbfnum];
\r
426 // move on to next pdb file
\r
427 s = sequence[pdbfnum].length;
\r
433 String[] selcom = new String[files.length];
\r
435 // generate select statements to select regions to superimpose structures
\r
437 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
\r
439 String chainCd = targetC[pdbfnum];
\r
441 boolean run = false;
\r
442 StringBuffer molsel = new StringBuffer();
\r
443 molsel.append("{");
\r
444 for (int r = 0; r < matched.length; r++)
\r
452 if (lpos != commonrpositions[pdbfnum][r] - 1)
\r
457 molsel.append(lpos);
\r
458 molsel.append(chainCd);
\r
459 // molsel.append("} {");
\r
460 molsel.append("|");
\r
465 // continuous run - and lpos >-1
\r
468 // at the beginning, so add dash
\r
469 molsel.append(lpos);
\r
470 molsel.append("-");
\r
474 lpos = commonrpositions[pdbfnum][r];
\r
475 // molsel.append(lpos);
\r
478 // add final selection phrase
\r
481 molsel.append(lpos);
\r
482 molsel.append(chainCd);
\r
483 molsel.append("}");
\r
485 selcom[pdbfnum] = molsel.toString();
\r
486 selectioncom.append("((");
\r
487 selectioncom.append(selcom[pdbfnum].substring(1,
\r
488 selcom[pdbfnum].length() - 1));
\r
489 selectioncom.append(" )& ");
\r
490 selectioncom.append(pdbfnum + 1);
\r
491 selectioncom.append(".1)");
\r
492 if (pdbfnum < files.length - 1)
\r
494 selectioncom.append("|");
\r
498 // TODO: consider bailing if nmatched less than 4 because superposition
\r
501 // TODO: refactor superposable position search (above) from jmol selection
\r
502 // construction (below)
\r
503 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
\r
505 if (pdbfnum == refStructure)
\r
509 command.append("echo ");
\r
510 command.append("\"Superposing (");
\r
511 command.append(chainNames[pdbfnum]);
\r
512 command.append(") against reference (");
\r
513 command.append(chainNames[refStructure]);
\r
514 command.append(")\";\ncompare ");
\r
515 command.append("{");
\r
516 command.append(1 + pdbfnum);
\r
517 command.append(".1} {");
\r
518 command.append(1 + refStructure);
\r
519 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
\r
521 // form the matched pair strings
\r
523 for (int s = 0; s < 2; s++)
\r
525 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
\r
527 command.append(" ROTATE TRANSLATE;\n");
\r
529 System.out.println("Select regions:\n" + selectioncom.toString());
\r
530 evalStateCommand("select *; cartoons off; backbone; select ("
\r
531 + selectioncom.toString() + "); cartoons; ");
\r
532 // selcom.append("; ribbons; ");
\r
533 System.out.println("Superimpose command(s):\n" + command.toString());
\r
535 evalStateCommand(command.toString());
\r
537 if (selectioncom.length() > 0)
\r
538 {// finally, mark all regions that were superposed.
\r
539 if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
\r
541 selectioncom.setLength(selectioncom.length() - 1);
\r
543 System.out.println("Select regions:\n" + selectioncom.toString());
\r
544 evalStateCommand("select *; cartoons off; backbone; select ("
\r
545 + selectioncom.toString() + "); cartoons; ");
\r
546 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
\r
550 public void evalStateCommand(String command)
\r
552 jmolHistory(false);
\r
553 if (lastCommand == null || !lastCommand.equals(command))
\r
555 viewer.evalStringQuiet(command + "\n");
\r
558 lastCommand = command;
\r
562 * colour any structures associated with sequences in the given alignment
\r
563 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
\r
564 * if colourBySequence is enabled.
\r
566 public void colourBySequence(boolean showFeatures,
\r
567 jalview.api.AlignmentViewPanel alignmentv)
\r
569 if (!colourBySequence)
\r
575 String[] files = getPdbFile();
\r
577 SequenceRenderer sr = getSequenceRenderer(alignmentv);
\r
579 FeatureRenderer fr = null;
\r
582 fr = getFeatureRenderer(alignmentv);
\r
584 AlignmentI alignment = alignmentv.getAlignment();
\r
586 for (jalview.structure.StructureMappingcommandSet cpdbbyseq : JmolCommands
\r
587 .getColourBySequenceCommand(ssm, files, sequence, sr, fr,
\r
589 for (String cbyseq : cpdbbyseq.commands)
\r
591 evalStateCommand(cbyseq);
\r
595 public boolean isColourBySequence()
\r
597 return colourBySequence;
\r
600 public void setColourBySequence(boolean colourBySequence)
\r
602 this.colourBySequence = colourBySequence;
\r
605 public void createImage(String file, String type, int quality)
\r
607 System.out.println("JMOL CREATE IMAGE");
\r
610 public String createImage(String fileName, String type,
\r
611 Object textOrBytes, int quality)
\r
613 System.out.println("JMOL CREATE IMAGE");
\r
617 public String eval(String strEval)
\r
619 // System.out.println(strEval);
\r
620 // "# 'eval' is implemented only for the applet.";
\r
624 // End StructureListener
\r
625 // //////////////////////////
\r
627 public float[][] functionXY(String functionName, int x, int y)
\r
632 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
\r
634 // TODO Auto-generated method stub
\r
638 public Color getColour(int atomIndex, int pdbResNum, String chain,
\r
641 if (getModelNum(pdbfile) < 0)
\r
643 // TODO: verify atomIndex is selecting correct model.
\r
644 return new Color(viewer.getAtomArgb(atomIndex));
\r
648 * returns the current featureRenderer that should be used to colour the
\r
655 public abstract FeatureRenderer getFeatureRenderer(
\r
656 AlignmentViewPanel alignment);
\r
659 * instruct the Jalview binding to update the pdbentries vector if necessary
\r
660 * prior to matching the jmol view's contents to the list of structure files
\r
661 * Jalview knows about.
\r
663 public abstract void refreshPdbEntries();
\r
665 private int getModelNum(String modelFileName)
\r
667 String[] mfn = getPdbFile();
\r
672 for (int i = 0; i < mfn.length; i++)
\r
674 if (mfn[i].equalsIgnoreCase(modelFileName))
\r
681 * map between index of model filename returned from getPdbFile and the first
\r
682 * index of models from this file in the viewer. Note - this is not trimmed -
\r
683 * use getPdbFile to get number of unique models.
\r
685 private int _modelFileNameMap[];
\r
687 // ////////////////////////////////
\r
688 // /StructureListener
\r
689 public synchronized String[] getPdbFile()
\r
691 if (viewer == null)
\r
693 return new String[0];
\r
695 if (modelFileNames == null)
\r
698 String mset[] = new String[viewer.getModelCount()];
\r
699 _modelFileNameMap = new int[mset.length];
\r
701 String m = viewer.getModelFileName(0);
\r
706 mset[0] = new File(m).getAbsolutePath();
\r
707 } catch (AccessControlException x)
\r
709 // usually not allowed to do this in applet, so keep raw handle
\r
711 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
\r
714 for (int i = 1; i < mset.length; i++)
\r
716 m = viewer.getModelFileName(i);
\r
721 mset[j] = new File(m).getAbsolutePath();
\r
722 } catch (AccessControlException x)
\r
724 // usually not allowed to do this in applet, so keep raw handle
\r
726 // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
\r
729 _modelFileNameMap[j] = i; // record the model index for the filename
\r
730 // skip any additional models in the same file (NMR structures)
\r
731 if ((mset[j] == null ? mset[j] != mset[j - 1]
\r
732 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
\r
737 modelFileNames = new String[j];
\r
738 System.arraycopy(mset, 0, modelFileNames, 0, j);
\r
740 return modelFileNames;
\r
744 * map from string to applet
\r
746 public Map getRegistryInfo()
\r
748 // TODO Auto-generated method stub
\r
753 * returns the current sequenceRenderer that should be used to colour the
\r
760 public abstract SequenceRenderer getSequenceRenderer(
\r
761 AlignmentViewPanel alignment);
\r
763 // ///////////////////////////////
\r
764 // JmolStatusListener
\r
766 public void handlePopupMenu(int x, int y)
\r
768 jmolpopup.show(x, y);
\r
772 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
\r
775 if (modelFileNames == null)
\r
780 // look up file model number for this pdbfile
\r
783 // may need to adjust for URLencoding here - we don't worry about that yet.
\r
784 while (mdlNum < modelFileNames.length
\r
785 && !pdbfile.equals(modelFileNames[mdlNum]))
\r
787 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
\r
790 if (mdlNum == modelFileNames.length)
\r
795 jmolHistory(false);
\r
796 // if (!pdbfile.equals(pdbentry.getFile()))
\r
798 if (resetLastRes.length() > 0)
\r
800 viewer.evalStringQuiet(resetLastRes.toString());
\r
804 eval.append("select " + pdbResNum); // +modelNum
\r
806 resetLastRes.setLength(0);
\r
807 resetLastRes.append("select " + pdbResNum); // +modelNum
\r
810 resetLastRes.append(":");
\r
811 if (!chain.equals(" "))
\r
813 eval.append(chain);
\r
814 resetLastRes.append(chain);
\r
817 eval.append(" /" + (mdlNum + 1));
\r
818 resetLastRes.append("/" + (mdlNum + 1));
\r
820 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
\r
822 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
\r
823 + " and not hetero; spacefill 0;");
\r
825 eval.append("spacefill 200;select none");
\r
827 viewer.evalStringQuiet(eval.toString());
\r
832 boolean debug = true;
\r
834 private void jmolHistory(boolean enable)
\r
836 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
\r
839 public void loadInline(String string)
\r
841 loadedInline = true;
\r
842 // TODO: re JAL-623
\r
843 // viewer.loadInline(strModel, isAppend);
\r
845 // construct fake fullPathName and fileName so we can identify the file
\r
847 // Then, construct pass a reader for the string to Jmol.
\r
848 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
\r
849 // fileName, null, reader, false, null, null, 0);
\r
850 viewer.openStringInline(string);
\r
853 public void mouseOverStructure(int atomIndex, String strInfo)
\r
856 int alocsep = strInfo.indexOf("^");
\r
857 int mdlSep = strInfo.indexOf("/");
\r
858 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
\r
860 if (chainSeparator == -1)
\r
862 chainSeparator = strInfo.indexOf(".");
\r
863 if (mdlSep > -1 && mdlSep < chainSeparator)
\r
865 chainSeparator1 = chainSeparator;
\r
866 chainSeparator = mdlSep;
\r
869 // handle insertion codes
\r
872 pdbResNum = Integer.parseInt(strInfo.substring(
\r
873 strInfo.indexOf("]") + 1, alocsep));
\r
878 pdbResNum = Integer.parseInt(strInfo.substring(
\r
879 strInfo.indexOf("]") + 1, chainSeparator));
\r
883 if (strInfo.indexOf(":") > -1)
\r
884 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
\r
885 strInfo.indexOf("."));
\r
891 String pdbfilename = modelFileNames[frameNo]; // default is first or current
\r
895 if (chainSeparator1 == -1)
\r
897 chainSeparator1 = strInfo.indexOf(".", mdlSep);
\r
899 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
\r
900 chainSeparator1) : strInfo.substring(mdlSep + 1);
\r
903 // recover PDB filename for the model hovered over.
\r
904 int _mp = _modelFileNameMap.length - 1, mnumber = new Integer(mdlId)
\r
906 while (mnumber < _modelFileNameMap[_mp])
\r
910 pdbfilename = modelFileNames[_mp];
\r
911 if (pdbfilename == null)
\r
913 pdbfilename = new File(viewer.getModelFileName(mnumber))
\r
914 .getAbsolutePath();
\r
917 } catch (Exception e)
\r
922 if (lastMessage == null || !lastMessage.equals(strInfo))
\r
923 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
\r
925 lastMessage = strInfo;
\r
928 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
\r
932 System.err.println("Ignoring additional hover info: " + data
\r
933 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
\r
935 mouseOverStructure(atomIndex, strInfo);
\r
939 * { if (history != null && strStatus != null &&
\r
940 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
\r
944 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
\r
947 * this implements the toggle label behaviour copied from the original
\r
948 * structure viewer, MCView
\r
950 if (strData != null)
\r
952 System.err.println("Ignoring additional pick data string " + strData);
\r
954 int chainSeparator = strInfo.indexOf(":");
\r
956 if (chainSeparator == -1)
\r
957 chainSeparator = strInfo.indexOf(".");
\r
959 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
\r
961 String mdlString = "";
\r
962 if ((p = strInfo.indexOf(":")) > -1)
\r
963 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
\r
965 if ((p = strInfo.indexOf("/")) > -1)
\r
967 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
\r
969 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
\r
970 + mdlString + "))";
\r
971 jmolHistory(false);
\r
973 if (!atomsPicked.contains(picked))
\r
975 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
\r
976 atomsPicked.addElement(picked);
\r
980 viewer.evalString("select " + picked + ";label off");
\r
981 atomsPicked.removeElement(picked);
\r
984 // TODO: in application this happens
\r
986 // if (scriptWindow != null)
\r
988 // scriptWindow.sendConsoleMessage(strInfo);
\r
989 // scriptWindow.sendConsoleMessage("\n");
\r
995 public void notifyCallback(EnumCallback type, Object[] data)
\r
1002 notifyFileLoaded((String) data[1], (String) data[2],
\r
1003 (String) data[3], (String) data[4],
\r
1004 ((Integer) data[5]).intValue());
\r
1008 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
\r
1009 (String) data[0]);
\r
1010 // also highlight in alignment
\r
1012 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
\r
1013 (String) data[0]);
\r
1016 notifyScriptTermination((String) data[2],
\r
1017 ((Integer) data[3]).intValue());
\r
1020 sendConsoleEcho((String) data[1]);
\r
1023 sendConsoleMessage((data == null) ? ((String) null)
\r
1024 : (String) data[1]);
\r
1027 // System.err.println("Ignoring error callback.");
\r
1037 System.err.println("Unhandled callback " + type + " "
\r
1038 + data[1].toString());
\r
1041 } catch (Exception e)
\r
1043 System.err.println("Squashed Jmol callback handler error:");
\r
1044 e.printStackTrace();
\r
1049 public boolean notifyEnabled(EnumCallback callbackPick)
\r
1051 switch (callbackPick)
\r
1066 case MINIMIZATION:
\r
1071 // incremented every time a load notification is successfully handled -
\r
1072 // lightweight mechanism for other threads to detect when they can start
\r
1073 // referrring to new structures.
\r
1074 private long loadNotifiesHandled = 0;
\r
1076 public long getLoadNotifiesHandled()
\r
1078 return loadNotifiesHandled;
\r
1081 public void notifyFileLoaded(String fullPathName, String fileName2,
\r
1082 String modelName, String errorMsg, int modelParts)
\r
1084 if (errorMsg != null)
\r
1086 fileLoadingError = errorMsg;
\r
1090 // TODO: deal sensibly with models loaded inLine:
\r
1091 // modelName will be null, as will fullPathName.
\r
1093 // the rest of this routine ignores the arguments, and simply interrogates
\r
1094 // the Jmol view to find out what structures it contains, and adds them to
\r
1095 // the structure selection manager.
\r
1096 fileLoadingError = null;
\r
1097 String[] oldmodels = modelFileNames;
\r
1098 modelFileNames = null;
\r
1099 chainNames = new Vector();
\r
1100 chainFile = new Hashtable();
\r
1101 boolean notifyLoaded = false;
\r
1102 String[] modelfilenames = getPdbFile();
\r
1103 // first check if we've lost any structures
\r
1104 if (oldmodels != null && oldmodels.length > 0)
\r
1107 for (int i = 0; i < oldmodels.length; i++)
\r
1109 for (int n = 0; n < modelfilenames.length; n++)
\r
1111 if (modelfilenames[n] == oldmodels[i])
\r
1113 oldmodels[i] = null;
\r
1117 if (oldmodels[i] != null)
\r
1124 String[] oldmfn = new String[oldm];
\r
1126 for (int i = 0; i < oldmodels.length; i++)
\r
1128 if (oldmodels[i] != null)
\r
1130 oldmfn[oldm++] = oldmodels[i];
\r
1133 // deregister the Jmol instance for these structures - we'll add
\r
1134 // ourselves again at the end for the current structure set.
\r
1135 ssm.removeStructureViewerListener(this, oldmfn);
\r
1138 refreshPdbEntries();
\r
1139 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
\r
1141 String fileName = modelfilenames[modelnum];
\r
1142 boolean foundEntry = false;
\r
1143 MCview.PDBfile pdb = null;
\r
1144 String pdbfile = null, pdbfhash = null;
\r
1145 // model was probably loaded inline - so check the pdb file hashcode
\r
1148 // calculate essential attributes for the pdb data imported inline.
\r
1149 // prolly need to resolve modelnumber properly - for now just use our
\r
1151 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
\r
1153 pdbfhash = "" + pdbfile.hashCode();
\r
1155 if (pdbentry != null)
\r
1157 // search pdbentries and sequences to find correct pdbentry for this
\r
1159 for (int pe = 0; pe < pdbentry.length; pe++)
\r
1161 boolean matches = false;
\r
1162 if (fileName == null)
\r
1165 // see JAL-623 - need method of matching pasted data up
\r
1167 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
\r
1168 AppletFormatAdapter.PASTE);
\r
1169 pdbentry[modelnum].setFile("INLINE" + pdb.id);
\r
1171 foundEntry = true;
\r
1177 if (matches = (fl = new File(pdbentry[pe].getFile()))
\r
1178 .equals(new File(fileName)))
\r
1180 foundEntry = true;
\r
1181 // TODO: Jmol can in principle retrieve from CLASSLOADER but
\r
1184 // to be tested. See mantis bug
\r
1185 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
\r
1186 String protocol = AppletFormatAdapter.URL;
\r
1191 protocol = AppletFormatAdapter.FILE;
\r
1193 } catch (Exception e)
\r
1198 // Explicitly map to the filename used by Jmol ;
\r
1199 pdb = ssm.setMapping(sequence[pe], chains[pe], fileName,
\r
1201 // pdbentry[pe].getFile(), protocol);
\r
1207 // add an entry for every chain in the model
\r
1208 for (int i = 0; i < pdb.chains.size(); i++)
\r
1210 String chid = new String(pdb.id + ":"
\r
1211 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
\r
1212 chainFile.put(chid, fileName);
\r
1213 chainNames.addElement(chid);
\r
1215 notifyLoaded = true;
\r
1219 if (!foundEntry && associateNewStructs)
\r
1221 // this is a foreign pdb file that jalview doesn't know about - add
\r
1222 // it to the dataset and try to find a home - either on a matching
\r
1223 // sequence or as a new sequence.
\r
1224 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
\r
1226 // parse pdb file into a chain, etc.
\r
1227 // locate best match for pdb in associated views and add mapping to
\r
1229 // if properly registered then
\r
1230 notifyLoaded = true;
\r
1235 // so finally, update the jmol bits and pieces
\r
1236 if (jmolpopup != null)
\r
1238 // potential for deadlock here:
\r
1239 // jmolpopup.updateComputedMenus();
\r
1241 if (!isLoadingFromArchive())
\r
1243 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
\r
1245 // register ourselves as a listener and notify the gui that it needs to
\r
1247 ssm.addStructureViewerListener(this);
\r
1250 FeatureRenderer fr = getFeatureRenderer(null);
\r
1253 fr.featuresAdded();
\r
1256 loadNotifiesHandled++;
\r
1258 setLoadingFromArchive(false);
\r
1261 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
\r
1263 notifyAtomPicked(iatom, strMeasure, null);
\r
1266 public abstract void notifyScriptTermination(String strStatus,
\r
1270 * display a message echoed from the jmol viewer
\r
1274 public abstract void sendConsoleEcho(String strEcho); /*
\r
1275 * { showConsole(true);
\r
1277 * history.append("\n" +
\r
1281 // /End JmolStatusListener
\r
1282 // /////////////////////////////
\r
1285 * @param strStatus
\r
1286 * status message - usually the response received after a script
\r
1289 public abstract void sendConsoleMessage(String strStatus);
\r
1291 public void setCallbackFunction(String callbackType,
\r
1292 String callbackFunction)
\r
1294 System.err.println("Ignoring set-callback request to associate "
\r
1295 + callbackType + " with function " + callbackFunction);
\r
1299 public void setJalviewColourScheme(ColourSchemeI cs)
\r
1301 colourBySequence = false;
\r
1309 jmolHistory(false);
\r
1310 // TODO: Switch between nucleotide or aa selection expressions
\r
1311 Enumeration en = ResidueProperties.aa3Hash.keys();
\r
1312 StringBuffer command = new StringBuffer("select *;color white;");
\r
1313 while (en.hasMoreElements())
\r
1315 res = en.nextElement().toString();
\r
1316 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
\r
1320 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
\r
1322 command.append("select " + res + ";color[" + col.getRed() + ","
\r
1323 + col.getGreen() + "," + col.getBlue() + "];");
\r
1326 evalStateCommand(command.toString());
\r
1327 jmolHistory(true);
\r
1330 public void showHelp()
\r
1332 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
\r
1336 * open the URL somehow
\r
1340 public abstract void showUrl(String url, String target);
\r
1343 * called when the binding thinks the UI needs to be refreshed after a Jmol
\r
1344 * state change. this could be because structures were loaded, or because an
\r
1345 * error has occured.
\r
1347 public abstract void refreshGUI();
\r
1350 * called to show or hide the associated console window container.
\r
1354 public abstract void showConsole(boolean show);
\r
1357 * @param renderPanel
\r
1358 * @param jmolfileio
\r
1359 * - when true will initialise jmol's file IO system (should be false
\r
1360 * in applet context)
\r
1362 * @param documentBase
\r
1364 * @param commandOptions
\r
1366 public void allocateViewer(Container renderPanel, boolean jmolfileio,
\r
1367 String htmlName, URL documentBase, URL codeBase,
\r
1368 String commandOptions)
\r
1370 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
\r
1371 codeBase, commandOptions, null, null);
\r
1376 * @param renderPanel
\r
1377 * @param jmolfileio
\r
1378 * - when true will initialise jmol's file IO system (should be false
\r
1379 * in applet context)
\r
1381 * @param documentBase
\r
1383 * @param commandOptions
\r
1384 * @param consolePanel
\r
1385 * - panel to contain Jmol console
\r
1386 * @param buttonsToShow
\r
1387 * - buttons to show on the console, in ordr
\r
1389 public void allocateViewer(Container renderPanel, boolean jmolfileio,
\r
1390 String htmlName, URL documentBase, URL codeBase,
\r
1391 String commandOptions, final Container consolePanel,
\r
1392 String buttonsToShow)
\r
1394 if (commandOptions == null)
\r
1396 commandOptions = "";
\r
1398 viewer = JmolViewer.allocateViewer(renderPanel,
\r
1399 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
\r
1400 + ((Object) this).toString(), documentBase, codeBase,
\r
1401 commandOptions, this);
\r
1403 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
\r
1404 if (consolePanel != null)
\r
1406 consolePanel.addComponentListener(this);
\r
1412 protected abstract JmolAppConsoleInterface createJmolConsole(
\r
1413 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
\r
1415 protected org.jmol.api.JmolAppConsoleInterface console = null;
\r
1417 public void componentResized(ComponentEvent e)
\r
1422 public void componentMoved(ComponentEvent e)
\r
1427 public void componentShown(ComponentEvent e)
\r
1429 showConsole(true);
\r
1432 public void componentHidden(ComponentEvent e)
\r
1434 showConsole(false);
\r
1437 public void setLoadingFromArchive(boolean loadingFromArchive)
\r
1439 this.loadingFromArchive = loadingFromArchive;
\r
1442 public boolean isLoadingFromArchive()
\r
1444 return loadingFromArchive;
\r
1447 public void setBackgroundColour(java.awt.Color col)
\r
1449 jmolHistory(false);
\r
1450 viewer.evalStringQuiet("background [" + col.getRed() + ","
\r
1451 + col.getGreen() + "," + col.getBlue() + "];");
\r
1452 jmolHistory(true);
\r
1456 * add structures and any known sequence associations
\r
1458 * @returns the pdb entries added to the current set.
\r
1460 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
\r
1461 SequenceI[][] seq, String[][] chns)
\r
1464 Vector v = new Vector();
\r
1465 Vector rtn = new Vector();
\r
1466 for (int i = 0; i < pdbentry.length; i++)
\r
1468 v.addElement(pdbentry[i]);
\r
1470 for (int i = 0; i < pdbe.length; i++)
\r
1472 int r = v.indexOf(pdbe[i]);
\r
1473 if (r == -1 || r >= pdbentry.length)
\r
1475 rtn.addElement(new int[]
\r
1477 v.addElement(pdbe[i]);
\r
1481 // just make sure the sequence/chain entries are all up to date
\r
1482 addSequenceAndChain(r, seq[i], chns[i]);
\r
1485 pdbe = new PDBEntry[v.size()];
\r
1488 if (rtn.size() > 0)
\r
1490 // expand the tied seuqence[] and string[] arrays
\r
1491 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
\r
1492 String[][] sch = new String[pdbentry.length][];
\r
1493 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
\r
1494 System.arraycopy(chains, 0, sch, 0, this.chains.length);
\r
1497 pdbe = new PDBEntry[rtn.size()];
\r
1498 for (int r = 0; r < pdbe.length; r++)
\r
1500 int[] stri = ((int[]) rtn.elementAt(r));
\r
1501 // record the pdb file as a new addition
\r
1502 pdbe[r] = pdbentry[stri[0]];
\r
1503 // and add the new sequence/chain entries
\r
1504 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
\r
1514 public void addSequence(int pe, SequenceI[] seq)
\r
1516 // add sequences to the pe'th pdbentry's seuqence set.
\r
1517 addSequenceAndChain(pe, seq, null);
\r
1520 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
\r
1522 if (pe < 0 || pe >= pdbentry.length)
\r
1525 "Implementation error - no corresponding pdbentry (for index "
\r
1526 + pe + ") to add sequences mappings to");
\r
1528 final String nullChain = "TheNullChain";
\r
1529 Vector s = new Vector();
\r
1530 Vector c = new Vector();
\r
1531 if (chains == null)
\r
1533 chains = new String[pdbentry.length][];
\r
1535 if (sequence[pe] != null)
\r
1537 for (int i = 0; i < sequence[pe].length; i++)
\r
1539 s.addElement(sequence[pe][i]);
\r
1540 if (chains[pe] != null)
\r
1542 if (i < chains[pe].length)
\r
1544 c.addElement(chains[pe][i]);
\r
1548 c.addElement(nullChain);
\r
1553 if (tchain != null && tchain.length > 0)
\r
1555 c.addElement(nullChain);
\r
1560 for (int i = 0; i < seq.length; i++)
\r
1562 if (!s.contains(seq[i]))
\r
1564 s.addElement(seq[i]);
\r
1565 if (tchain != null && i < tchain.length)
\r
1567 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
\r
1571 SequenceI[] tmp = new SequenceI[s.size()];
\r
1573 sequence[pe] = tmp;
\r
1576 String[] tch = new String[c.size()];
\r
1578 for (int i = 0; i < tch.length; i++)
\r
1580 if (tch[i] == nullChain)
\r
1589 chains[pe] = null;
\r
1596 * @return text report of alignment between pdbfile and any associated
\r
1597 * alignment sequences
\r
1599 public String printMapping(String pdbfile)
\r
1601 return ssm.printMapping(pdbfile);
\r
1605 public void resizeInnerPanel(String data)
\r
1607 // Jalview doesn't honour resize panel requests
\r