2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
3 * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
18 package jalview.ext.jmol;
23 import java.applet.Applet;
25 import java.awt.event.*;
27 import javax.swing.JPanel;
29 import jalview.api.FeatureRenderer;
30 import jalview.api.SequenceRenderer;
31 import jalview.api.SequenceStructureBinding;
32 import jalview.datamodel.*;
33 import jalview.structure.*;
36 import org.jmol.api.*;
37 import org.jmol.adapter.smarter.SmarterJmolAdapter;
39 import org.jmol.popup.*;
40 import org.jmol.viewer.JmolConstants;
41 import org.jmol.viewer.Viewer;
43 import jalview.schemes.*;
45 public abstract class JalviewJmolBinding implements StructureListener,
46 JmolStatusListener, SequenceStructureBinding,
47 JmolSelectionListener, ComponentListener
51 * set if Jmol state is being restored from some source - instructs binding
52 * not to apply default display style when structure set is updated for first
55 private boolean loadingFromArchive = false;
58 * state flag used to check if the Jmol viewer's paint method can be called
60 private boolean finishedInit = false;
62 public boolean isFinishedInit()
67 public void setFinishedInit(boolean finishedInit)
69 this.finishedInit = finishedInit;
72 boolean allChainsSelected = false;
75 * when true, try to search the associated datamodel for sequences that are
76 * associated with any unknown structures in the Jmol view.
78 private boolean associateNewStructs = false;
80 Vector atomsPicked = new Vector();
82 public Vector chainNames;
87 * array of target chains for seuqences - tied to pdbentry and sequence[]
89 protected String[][] chains;
91 boolean colourBySequence = true;
93 StringBuffer eval = new StringBuffer();
95 public String fileLoadingError;
98 * the default or current model displayed if the model cannot be identified
99 * from the selection message
103 protected JmolPopup jmolpopup;
109 boolean loadedInline;
112 * current set of model filenames loaded in the Jmol instance
114 String[] modelFileNames = null;
116 public PDBEntry[] pdbentry;
119 * datasource protocol for access to PDBEntrylatest
121 String protocol = null;
123 StringBuffer resetLastRes = new StringBuffer();
126 * sequences mapped to each pdbentry
128 public SequenceI[][] sequence;
130 StructureSelectionManager ssm;
132 public JmolViewer viewer;
134 public JalviewJmolBinding(PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
135 String[][] chains, String protocol)
137 this.sequence = sequenceIs;
138 this.chains = chains;
139 this.pdbentry = pdbentry;
140 this.protocol = protocol;
143 this.chains = new String[pdbentry.length][];
146 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
147 * "jalviewJmol", ap.av.applet .getDocumentBase(),
148 * ap.av.applet.getCodeBase(), "", this);
150 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
154 public JalviewJmolBinding(JmolViewer viewer2)
157 viewer.setJmolStatusListener(this);
158 viewer.addSelectionListener(this);
162 * construct a title string for the viewer window based on the data jalview
167 public String getViewerTitle()
169 if (sequence == null || pdbentry == null || sequence.length < 1
170 || pdbentry.length < 1 || sequence[0].length < 1)
172 return ("Jalview Jmol Window");
174 // TODO: give a more informative title when multiple structures are
176 StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
177 + pdbentry[0].getId());
179 if (pdbentry[0].getProperty() != null)
181 if (pdbentry[0].getProperty().get("method") != null)
183 title.append(" Method: ");
184 title.append(pdbentry[0].getProperty().get("method"));
186 if (pdbentry[0].getProperty().get("chains") != null)
188 title.append(" Chain:");
189 title.append(pdbentry[0].getProperty().get("chains"));
192 return title.toString();
196 * prepare the view for a given set of models/chains. chainList contains
197 * strings of the form 'pdbfilename:Chaincode'
200 * list of chains to make visible
202 public void centerViewer(Vector chainList)
204 StringBuffer cmd = new StringBuffer();
207 for (int i = 0, iSize = chainList.size(); i < iSize; i++)
210 lbl = (String) chainList.elementAt(i);
214 mlength = lbl.indexOf(":", p);
215 } while (p < mlength && mlength < (lbl.length() - 2));
216 // TODO: lookup each pdb id and recover proper model number for it.
217 cmd.append(":" + lbl.substring(mlength + 1) + " /"
218 + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");
220 if (cmd.length() > 0)
221 cmd.setLength(cmd.length() - 4);
222 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
225 public void closeViewer()
227 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
228 // remove listeners for all structures in viewer
229 StructureSelectionManager.getStructureSelectionManager()
230 .removeStructureViewerListener(this, this.getPdbFile());
231 // and shut down jmol
232 viewer.evalStringQuiet("zap");
233 viewer.setJmolStatusListener(null);
236 releaseUIResources();
240 * called by JalviewJmolbinding after closeViewer is called - release any
241 * resources and references so they can be garbage collected.
243 protected abstract void releaseUIResources();
245 public void colourByChain()
247 colourBySequence = false;
248 // TODO: colour by chain should colour each chain distinctly across all
250 // TODO: http://issues.jalview.org/browse/JAL-628
251 evalStateCommand("select *;color chain");
254 public void colourByCharge()
256 colourBySequence = false;
257 evalStateCommand("select *;color white;select ASP,GLU;color red;"
258 + "select LYS,ARG;color blue;select CYS;color yellow");
262 * superpose the structures associated with sequences in the alignment
263 * according to their corresponding positions.
265 public void superposeStructures(AlignmentI alignment)
267 superposeStructures(alignment, -1, null);
271 * superpose the structures associated with sequences in the alignment
272 * according to their corresponding positions. ded)
274 * @param refStructure
275 * - select which pdb file to use as reference (default is -1 - the
276 * first structure in the alignment)
278 public void superposeStructures(AlignmentI alignment, int refStructure)
280 superposeStructures(alignment, refStructure, null);
284 * superpose the structures associated with sequences in the alignment
285 * according to their corresponding positions. ded)
287 * @param refStructure
288 * - select which pdb file to use as reference (default is -1 - the
289 * first structure in the alignment)
293 public void superposeStructures(AlignmentI alignment, int refStructure,
294 ColumnSelection hiddenCols)
296 String[] files = getPdbFile();
297 if (refStructure >= files.length)
299 System.err.println("Invalid reference structure value "
303 if (refStructure < -1)
307 StringBuffer command = new StringBuffer(), selectioncom = new StringBuffer();
309 boolean matched[] = new boolean[alignment.getWidth()];
310 for (int m = 0; m < matched.length; m++)
313 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
316 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
317 String isel[] = new String[files.length];
318 // reference structure - all others are superposed in it
319 String[] targetC = new String[files.length];
320 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
322 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
324 if (mapping == null || mapping.length < 1)
328 for (int s = 0; s < sequence[pdbfnum].length; s++)
330 for (int sp, m = 0; m < mapping.length; m++)
332 if (mapping[m].getSequence() == sequence[pdbfnum][s]
333 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
335 if (refStructure == -1)
337 refStructure = pdbfnum;
339 SequenceI asp = alignment.getSequenceAt(sp);
340 for (int r = 0; r < matched.length; r++)
346 matched[r] = false; // assume this is not a good site
347 if (r >= asp.getLength())
352 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
354 // no mapping to gaps in sequence
357 int t = asp.findPosition(r); // sequence position
358 int apos = mapping[m].getAtomNum(t);
359 int pos = mapping[m].getPDBResNum(t);
361 if (pos < 1 || pos == lastPos)
363 // can't align unmapped sequence
366 matched[r] = true; // this is a good ite
368 // just record this residue position
369 commonrpositions[pdbfnum][r] = pos;
371 // create model selection suffix
372 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
373 if (mapping[m].getChain() == null
374 || mapping[m].getChain().trim().length() == 0)
376 targetC[pdbfnum] = "";
380 targetC[pdbfnum] = ":" + mapping[m].getChain();
382 // move on to next pdb file
383 s = sequence[pdbfnum].length;
389 String[] selcom = new String[files.length];
391 // generate select statements to select regions to superimpose structures
393 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
395 String chainCd = targetC[pdbfnum];
398 StringBuffer molsel = new StringBuffer();
400 for (int r = 0; r < matched.length; r++)
408 if (lpos != commonrpositions[pdbfnum][r] - 1)
414 molsel.append(chainCd);
415 // molsel.append("} {");
421 // continuous run - and lpos >-1
424 // at the beginning, so add dash
430 lpos = commonrpositions[pdbfnum][r];
431 // molsel.append(lpos);
434 // add final selection phrase
438 molsel.append(chainCd);
441 selcom[pdbfnum] = molsel.toString();
442 selectioncom.append("((");
443 selectioncom.append(selcom[pdbfnum].substring(1,
444 selcom[pdbfnum].length() - 1));
445 selectioncom.append(" )& ");
446 selectioncom.append(pdbfnum + 1);
447 selectioncom.append(".1)");
448 if (pdbfnum < files.length - 1)
450 selectioncom.append("|");
454 // TODO: consider bailing if nmatched less than 4 because superposition not
456 // TODO: refactor superposable position search (above) from jmol selection
457 // construction (below)
458 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
460 if (pdbfnum == refStructure)
464 command.append("compare ");
466 command.append(1 + pdbfnum);
467 command.append(".1} {");
468 command.append(1 + refStructure);
469 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
471 // form the matched pair strings
473 for (int s = 0; s < 2; s++)
475 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
477 command.append(" ROTATE TRANSLATE;\n");
479 System.out.println("Select regions:\n" + selectioncom.toString());
480 evalStateCommand("select *; cartoons off; backbone; select ("
481 + selectioncom.toString() + "); cartoons; ");
482 // selcom.append("; ribbons; ");
483 System.out.println("Superimpose command(s):\n" + command.toString());
485 evalStateCommand(command.toString());
487 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
490 public void evalStateCommand(String command)
493 if (lastCommand == null || !lastCommand.equals(command))
495 viewer.evalStringQuiet(command + "\n");
498 lastCommand = command;
502 * colour any structures associated with sequences in the given alignment
503 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
504 * if colourBySequence is enabled.
506 public void colourBySequence(boolean showFeatures, AlignmentI alignment)
508 if (!colourBySequence)
514 String[] files = getPdbFile();
515 SequenceRenderer sr = getSequenceRenderer();
517 FeatureRenderer fr = null;
520 fr = getFeatureRenderer();
523 StringBuffer command = new StringBuffer();
525 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
527 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
529 if (mapping == null || mapping.length < 1)
533 for (int s = 0; s < sequence[pdbfnum].length; s++)
535 for (int sp, m = 0; m < mapping.length; m++)
537 if (mapping[m].getSequence() == sequence[pdbfnum][s]
538 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
540 SequenceI asp = alignment.getSequenceAt(sp);
541 for (int r = 0; r < asp.getLength(); r++)
543 // no mapping to gaps in sequence
544 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
548 int pos = mapping[m].getPDBResNum(asp.findPosition(r));
550 if (pos < 1 || pos == lastPos)
555 Color col = sr.getResidueBoxColour(sequence[pdbfnum][s], r);
557 if (showFeatures && fr != null)
558 col = fr.findFeatureColour(col, sequence[pdbfnum][s], r);
559 String newSelcom = (mapping[m].getChain() != " " ? ":"
560 + mapping[m].getChain() : "")
569 + col.getBlue() + "]";
570 if (command.toString().endsWith(newSelcom))
572 command = condenseCommand(command.toString(), pos);
575 // TODO: deal with case when buffer is too large for Jmol to parse
576 // - execute command and flush
578 command.append(";select " + pos);
579 command.append(newSelcom);
586 evalStateCommand(command.toString());
589 public boolean isColourBySequence()
591 return colourBySequence;
594 public void setColourBySequence(boolean colourBySequence)
596 this.colourBySequence = colourBySequence;
599 StringBuffer condenseCommand(String command, int pos)
602 StringBuffer sb = new StringBuffer(command.substring(0,
603 command.lastIndexOf("select") + 7));
605 command = command.substring(sb.length());
609 if (command.indexOf("-") > -1)
611 start = command.substring(0, command.indexOf("-"));
615 start = command.substring(0, command.indexOf(":"));
618 sb.append(start + "-" + pos + command.substring(command.indexOf(":")));
623 public void createImage(String file, String type, int quality)
625 System.out.println("JMOL CREATE IMAGE");
628 public String createImage(String fileName, String type,
629 Object textOrBytes, int quality)
631 System.out.println("JMOL CREATE IMAGE");
635 public String eval(String strEval)
637 // System.out.println(strEval);
638 // "# 'eval' is implemented only for the applet.";
642 // End StructureListener
643 // //////////////////////////
645 public float[][] functionXY(String functionName, int x, int y)
650 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
652 // TODO Auto-generated method stub
656 public Color getColour(int atomIndex, int pdbResNum, String chain,
659 if (getModelNum(pdbfile) < 0)
661 // TODO: verify atomIndex is selecting correct model.
662 return new Color(viewer.getAtomArgb(atomIndex));
666 * returns the current featureRenderer that should be used to colour the
671 public abstract FeatureRenderer getFeatureRenderer();
674 * instruct the Jalview binding to update the pdbentries vector if necessary
675 * prior to matching the jmol view's contents to the list of structure files
676 * Jalview knows about.
678 public abstract void refreshPdbEntries();
680 private int getModelNum(String modelFileName)
682 String[] mfn = getPdbFile();
687 for (int i = 0; i < mfn.length; i++)
689 if (mfn[i].equalsIgnoreCase(modelFileName))
696 * map between index of model filename returned from getPdbFile and the first
697 * index of models from this file in the viewer. Note - this is not trimmed -
698 * use getPdbFile to get number of unique models.
700 private int _modelFileNameMap[];
702 // ////////////////////////////////
703 // /StructureListener
704 public synchronized String[] getPdbFile()
708 return new String[0];
710 if (modelFileNames == null)
713 String mset[] = new String[viewer.getModelCount()];
714 _modelFileNameMap = new int[mset.length];
716 mset[0] = viewer.getModelFileName(0);
717 for (int i = 1; i < mset.length; i++)
719 mset[j] = viewer.getModelFileName(i);
720 _modelFileNameMap[j] = i; // record the model index for the filename
721 // skip any additional models in the same file (NMR structures)
722 if ((mset[j] == null ? mset[j] != mset[j - 1]
723 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
728 modelFileNames = new String[j];
729 System.arraycopy(mset, 0, modelFileNames, 0, j);
731 return modelFileNames;
735 * map from string to applet
737 public Map getRegistryInfo()
739 // TODO Auto-generated method stub
744 * returns the current sequenceRenderer that should be used to colour the
749 public abstract SequenceRenderer getSequenceRenderer();
751 // ///////////////////////////////
752 // JmolStatusListener
754 public void handlePopupMenu(int x, int y)
756 jmolpopup.show(x, y);
760 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
763 if (modelFileNames == null)
768 // look up file model number for this pdbfile
771 // may need to adjust for URLencoding here - we don't worry about that yet.
772 while (mdlNum < modelFileNames.length
773 && !pdbfile.equals(modelFileNames[mdlNum]))
775 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
778 if (mdlNum == modelFileNames.length)
784 // if (!pdbfile.equals(pdbentry.getFile()))
786 if (resetLastRes.length() > 0)
788 viewer.evalStringQuiet(resetLastRes.toString());
792 eval.append("select " + pdbResNum); // +modelNum
794 resetLastRes.setLength(0);
795 resetLastRes.append("select " + pdbResNum); // +modelNum
798 resetLastRes.append(":");
799 if (!chain.equals(" "))
802 resetLastRes.append(chain);
805 eval.append(" /" + (mdlNum + 1));
806 resetLastRes.append("/" + (mdlNum + 1));
808 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
810 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
811 + " and not hetero; spacefill 0;");
813 eval.append("spacefill 200;select none");
815 viewer.evalStringQuiet(eval.toString());
820 boolean debug = true;
822 private void jmolHistory(boolean enable)
824 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
827 public void loadInline(String string)
831 // viewer.loadInline(strModel, isAppend);
833 // construct fake fullPathName and fileName so we can identify the file
835 // Then, construct pass a reader for the string to Jmol.
836 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
837 // fileName, null, reader, false, null, null, 0);
838 viewer.openStringInline(string);
841 public void mouseOverStructure(int atomIndex, String strInfo)
844 int mdlSep = strInfo.indexOf("/");
845 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
847 if (chainSeparator == -1)
849 chainSeparator = strInfo.indexOf(".");
850 if (mdlSep > -1 && mdlSep < chainSeparator)
852 chainSeparator1 = chainSeparator;
853 chainSeparator = mdlSep;
856 pdbResNum = Integer.parseInt(strInfo.substring(
857 strInfo.indexOf("]") + 1, chainSeparator));
861 if (strInfo.indexOf(":") > -1)
862 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
863 strInfo.indexOf("."));
869 String pdbfilename = modelFileNames[frameNo]; // default is first or current
873 if (chainSeparator1 == -1)
875 chainSeparator1 = strInfo.indexOf(".", mdlSep);
877 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
878 chainSeparator1) : strInfo.substring(mdlSep + 1);
881 // recover PDB filename for the model hovered over.
883 .getModelFileName(new Integer(mdlId).intValue() - 1);
884 } catch (Exception e)
889 if (lastMessage == null || !lastMessage.equals(strInfo))
890 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
892 lastMessage = strInfo;
895 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
899 System.err.println("Ignoring additional hover info: " + data
900 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
902 mouseOverStructure(atomIndex, strInfo);
906 * { if (history != null && strStatus != null &&
907 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
911 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
914 * this implements the toggle label behaviour copied from the original
915 * structure viewer, MCView
919 System.err.println("Ignoring additional pick data string " + strData);
921 int chainSeparator = strInfo.indexOf(":");
923 if (chainSeparator == -1)
924 chainSeparator = strInfo.indexOf(".");
926 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
928 String mdlString = "";
929 if ((p = strInfo.indexOf(":")) > -1)
930 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
932 if ((p = strInfo.indexOf("/")) > -1)
934 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
936 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
940 if (!atomsPicked.contains(picked))
942 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
943 atomsPicked.addElement(picked);
947 viewer.evalString("select " + picked + ";label off");
948 atomsPicked.removeElement(picked);
951 // TODO: in application this happens
953 // if (scriptWindow != null)
955 // scriptWindow.sendConsoleMessage(strInfo);
956 // scriptWindow.sendConsoleMessage("\n");
961 public void notifyCallback(int type, Object[] data)
967 case JmolConstants.CALLBACK_LOADSTRUCT:
968 notifyFileLoaded((String) data[1], (String) data[2],
969 (String) data[3], (String) data[4],
970 ((Integer) data[5]).intValue());
973 case JmolConstants.CALLBACK_PICK:
974 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
976 // also highlight in alignment
977 case JmolConstants.CALLBACK_HOVER:
978 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
981 case JmolConstants.CALLBACK_SCRIPT:
982 notifyScriptTermination((String) data[2],
983 ((Integer) data[3]).intValue());
985 case JmolConstants.CALLBACK_ECHO:
986 sendConsoleEcho((String) data[1]);
988 case JmolConstants.CALLBACK_MESSAGE:
989 sendConsoleMessage((data == null) ? ((String) null)
992 case JmolConstants.CALLBACK_ERROR:
993 // System.err.println("Ignoring error callback.");
995 case JmolConstants.CALLBACK_SYNC:
996 case JmolConstants.CALLBACK_RESIZE:
999 case JmolConstants.CALLBACK_MEASURE:
1001 case JmolConstants.CALLBACK_CLICK:
1003 System.err.println("Unhandled callback " + type + " "
1004 + data[1].toString());
1007 } catch (Exception e)
1009 System.err.println("Squashed Jmol callback handler error:");
1010 e.printStackTrace();
1014 public boolean notifyEnabled(int callbackPick)
1016 switch (callbackPick)
1018 case JmolConstants.CALLBACK_ECHO:
1019 case JmolConstants.CALLBACK_LOADSTRUCT:
1020 case JmolConstants.CALLBACK_MEASURE:
1021 case JmolConstants.CALLBACK_MESSAGE:
1022 case JmolConstants.CALLBACK_PICK:
1023 case JmolConstants.CALLBACK_SCRIPT:
1024 case JmolConstants.CALLBACK_HOVER:
1025 case JmolConstants.CALLBACK_ERROR:
1027 case JmolConstants.CALLBACK_RESIZE:
1028 case JmolConstants.CALLBACK_SYNC:
1029 case JmolConstants.CALLBACK_CLICK:
1030 case JmolConstants.CALLBACK_ANIMFRAME:
1031 case JmolConstants.CALLBACK_MINIMIZATION:
1036 // incremented every time a load notification is successfully handled -
1037 // lightweight mechanism for other threads to detect when they can start
1038 // referrring to new structures.
1039 private long loadNotifiesHandled = 0;
1041 public long getLoadNotifiesHandled()
1043 return loadNotifiesHandled;
1046 public void notifyFileLoaded(String fullPathName, String fileName2,
1047 String modelName, String errorMsg, int modelParts)
1049 if (errorMsg != null)
1051 fileLoadingError = errorMsg;
1055 // TODO: deal sensibly with models loaded inLine:
1056 // modelName will be null, as will fullPathName.
1058 // the rest of this routine ignores the arguments, and simply interrogates
1059 // the Jmol view to find out what structures it contains, and adds them to
1060 // the structure selection manager.
1061 fileLoadingError = null;
1062 String[] oldmodels = modelFileNames;
1063 modelFileNames = null;
1064 chainNames = new Vector();
1065 chainFile = new Hashtable();
1066 boolean notifyLoaded = false;
1067 String[] modelfilenames = getPdbFile();
1068 ssm = StructureSelectionManager.getStructureSelectionManager();
1069 // first check if we've lost any structures
1070 if (oldmodels != null && oldmodels.length > 0)
1073 for (int i = 0; i < oldmodels.length; i++)
1075 for (int n = 0; n < modelfilenames.length; n++)
1077 if (modelfilenames[n] == oldmodels[i])
1079 oldmodels[i] = null;
1083 if (oldmodels[i] != null)
1090 String[] oldmfn = new String[oldm];
1092 for (int i = 0; i < oldmodels.length; i++)
1094 if (oldmodels[i] != null)
1096 oldmfn[oldm++] = oldmodels[i];
1099 // deregister the Jmol instance for these structures - we'll add
1100 // ourselves again at the end for the current structure set.
1101 ssm.removeStructureViewerListener(this, oldmfn);
1104 refreshPdbEntries();
1105 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1107 String fileName = modelfilenames[modelnum];
1108 boolean foundEntry = false;
1109 MCview.PDBfile pdb = null;
1110 String pdbfile = null, pdbfhash = null;
1111 // model was probably loaded inline - so check the pdb file hashcode
1114 // calculate essential attributes for the pdb data imported inline.
1115 // prolly need to resolve modelnumber properly - for now just use our
1117 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1119 pdbfhash = "" + pdbfile.hashCode();
1121 if (pdbentry != null)
1123 // search pdbentries and sequences to find correct pdbentry for this
1125 for (int pe = 0; pe < pdbentry.length; pe++)
1127 boolean matches = false;
1128 if (fileName == null)
1131 // see JAL-623 - need method of matching pasted data up
1133 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
1134 AppletFormatAdapter.PASTE);
1135 pdbentry[modelnum].setFile("INLINE" + pdb.id);
1142 if (matches = pdbentry[pe].getFile().equals(fileName))
1145 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1148 // to be tested. See mantis bug
1149 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1150 String protocol = AppletFormatAdapter.URL;
1153 File fl = new java.io.File(pdbentry[pe].getFile());
1156 protocol = AppletFormatAdapter.FILE;
1158 } catch (Exception e)
1164 pdb = ssm.setMapping(sequence[pe], chains[pe],
1165 pdbentry[pe].getFile(), protocol);
1171 pdbentry[pe].setId(pdb.id);
1172 // add an entry for every chain in the model
1173 for (int i = 0; i < pdb.chains.size(); i++)
1175 String chid = new String(pdb.id + ":"
1176 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
1177 chainFile.put(chid, pdbentry[pe].getFile());
1178 chainNames.addElement(chid);
1180 notifyLoaded = true;
1184 if (!foundEntry && associateNewStructs)
1186 // this is a foreign pdb file that jalview doesn't know about - add
1187 // it to the dataset and try to find a home - either on a matching
1188 // sequence or as a new sequence.
1189 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1191 // parse pdb file into a chain, etc.
1192 // locate best match for pdb in associated views and add mapping to
1194 // if properly registered then
1195 notifyLoaded = true;
1200 // so finally, update the jmol bits and pieces
1201 if (jmolpopup != null)
1203 // potential for deadlock here:
1204 // jmolpopup.updateComputedMenus();
1206 if (!isLoadingFromArchive())
1208 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1210 setLoadingFromArchive(false);
1211 // register ourselves as a listener and notify the gui that it needs to
1213 ssm.addStructureViewerListener(this);
1216 FeatureRenderer fr = getFeatureRenderer();
1222 loadNotifiesHandled++;
1226 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1228 notifyAtomPicked(iatom, strMeasure, null);
1231 public abstract void notifyScriptTermination(String strStatus,
1235 * display a message echoed from the jmol viewer
1239 public abstract void sendConsoleEcho(String strEcho); /*
1240 * { showConsole(true);
1242 * history.append("\n" +
1246 // /End JmolStatusListener
1247 // /////////////////////////////
1251 * status message - usually the response received after a script
1254 public abstract void sendConsoleMessage(String strStatus);
1256 public void setCallbackFunction(String callbackType,
1257 String callbackFunction)
1259 System.err.println("Ignoring set-callback request to associate "
1260 + callbackType + " with function " + callbackFunction);
1264 public void setJalviewColourScheme(ColourSchemeI cs)
1266 colourBySequence = false;
1275 // TODO: Switch between nucleotide or aa selection expressions
1276 Enumeration en = ResidueProperties.aa3Hash.keys();
1277 StringBuffer command = new StringBuffer("select *;color white;");
1278 while (en.hasMoreElements())
1280 res = en.nextElement().toString();
1281 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
1285 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
1287 command.append("select " + res + ";color[" + col.getRed() + ","
1288 + col.getGreen() + "," + col.getBlue() + "];");
1291 evalStateCommand(command.toString());
1295 public void showHelp()
1297 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1301 * open the URL somehow
1305 public abstract void showUrl(String url, String target);
1308 * called when the binding thinks the UI needs to be refreshed after a Jmol
1309 * state change. this could be because structures were loaded, or because an
1310 * error has occured.
1312 public abstract void refreshGUI();
1315 * called to show or hide the associated console window container.
1319 public abstract void showConsole(boolean show);
1322 * @param renderPanel
1324 * - when true will initialise jmol's file IO system (should be false
1325 * in applet context)
1327 * @param documentBase
1329 * @param commandOptions
1331 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1332 String htmlName, URL documentBase, URL codeBase,
1333 String commandOptions)
1335 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1336 codeBase, commandOptions, null, null);
1341 * @param renderPanel
1343 * - when true will initialise jmol's file IO system (should be false
1344 * in applet context)
1346 * @param documentBase
1348 * @param commandOptions
1349 * @param consolePanel
1350 * - panel to contain Jmol console
1351 * @param buttonsToShow
1352 * - buttons to show on the console, in ordr
1354 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1355 String htmlName, URL documentBase, URL codeBase,
1356 String commandOptions, final Container consolePanel,
1357 String buttonsToShow)
1359 viewer = JmolViewer.allocateViewer(renderPanel,
1360 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1361 + ((Object) this).toString(), documentBase, codeBase,
1362 commandOptions, this);
1364 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
1365 if (consolePanel != null)
1367 consolePanel.addComponentListener(this);
1373 protected abstract JmolAppConsoleInterface createJmolConsole(
1374 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
1376 protected org.jmol.api.JmolAppConsoleInterface console = null;
1378 public void componentResized(ComponentEvent e)
1383 public void componentMoved(ComponentEvent e)
1388 public void componentShown(ComponentEvent e)
1393 public void componentHidden(ComponentEvent e)
1398 public void setLoadingFromArchive(boolean loadingFromArchive)
1400 this.loadingFromArchive = loadingFromArchive;
1403 public boolean isLoadingFromArchive()
1405 return loadingFromArchive;
1408 public void setBackgroundColour(java.awt.Color col)
1411 viewer.evalStringQuiet("background [" + col.getRed() + ","
1412 + col.getGreen() + "," + col.getBlue() + "];");
1417 * add structures and any known sequence associations
1419 * @returns the pdb entries added to the current set.
1421 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
1422 SequenceI[][] seq, String[][] chns)
1425 Vector v = new Vector();
1426 Vector rtn = new Vector();
1427 for (int i = 0; i < pdbentry.length; i++)
1429 v.addElement(pdbentry[i]);
1431 for (int i = 0; i < pdbe.length; i++)
1433 int r = v.indexOf(pdbe[i]);
1434 if (r == -1 || r >= pdbentry.length)
1436 rtn.addElement(new int[]
1438 v.addElement(pdbe[i]);
1442 // just make sure the sequence/chain entries are all up to date
1443 addSequenceAndChain(r, seq[i], chns[i]);
1446 pdbe = new PDBEntry[v.size()];
1451 // expand the tied seuqence[] and string[] arrays
1452 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
1453 String[][] sch = new String[pdbentry.length][];
1454 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
1455 System.arraycopy(chains, 0, sch, 0, this.chains.length);
1458 pdbe = new PDBEntry[rtn.size()];
1459 for (int r = 0; r < pdbe.length; r++)
1461 int[] stri = ((int[]) rtn.elementAt(r));
1462 // record the pdb file as a new addition
1463 pdbe[r] = pdbentry[stri[0]];
1464 // and add the new sequence/chain entries
1465 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
1475 public void addSequence(int pe, SequenceI[] seq)
1477 // add sequences to the pe'th pdbentry's seuqence set.
1478 addSequenceAndChain(pe, seq, null);
1481 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
1483 if (pe < 0 || pe >= pdbentry.length)
1486 "Implementation error - no corresponding pdbentry (for index "
1487 + pe + ") to add sequences mappings to");
1489 final String nullChain = "TheNullChain";
1490 Vector s = new Vector();
1491 Vector c = new Vector();
1494 chains = new String[pdbentry.length][];
1496 if (sequence[pe] != null)
1498 for (int i = 0; i < sequence[pe].length; i++)
1500 s.addElement(sequence[pe][i]);
1501 if (chains[pe] != null)
1503 if (i < chains[pe].length)
1505 c.addElement(chains[pe][i]);
1509 c.addElement(nullChain);
1514 if (tchain != null && tchain.length > 0)
1516 c.addElement(nullChain);
1521 for (int i = 0; i < seq.length; i++)
1523 if (!s.contains(seq[i]))
1525 s.addElement(seq[i]);
1526 if (tchain != null && i < tchain.length)
1528 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
1532 SequenceI[] tmp = new SequenceI[s.size()];
1537 String[] tch = new String[c.size()];
1539 for (int i = 0; i < tch.length; i++)
1541 if (tch[i] == nullChain)