2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.5)
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;
42 import org.openscience.jmol.app.jmolpanel.AppConsole;
44 import jalview.schemes.*;
46 public abstract class JalviewJmolBinding implements StructureListener,
47 JmolStatusListener, SequenceStructureBinding, JmolSelectionListener
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;
85 * array of target chains for seuqences - tied to pdbentry and sequence[]
87 protected String[][] chains;
89 boolean colourBySequence = true;
91 StringBuffer eval = new StringBuffer();
93 public String fileLoadingError;
96 * the default or current model displayed if the model cannot be identified
97 * from the selection message
101 protected JmolPopup jmolpopup;
107 boolean loadedInline;
110 * current set of model filenames loaded in the Jmol instance
112 String[] modelFileNames = null;
114 public PDBEntry[] pdbentry;
117 * datasource protocol for access to PDBEntry
119 String protocol = null;
121 StringBuffer resetLastRes = new StringBuffer();
124 * sequences mapped to each pdbentry
126 public SequenceI[][] sequence;
128 StructureSelectionManager ssm;
130 public JmolViewer viewer;
132 public JalviewJmolBinding(PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
133 String[][] chains, String protocol)
135 this.sequence = sequenceIs;
136 this.chains = chains;
137 this.pdbentry = pdbentry;
138 this.protocol = protocol;
141 this.chains = new String[pdbentry.length][];
144 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
145 * "jalviewJmol", ap.av.applet .getDocumentBase(),
146 * ap.av.applet.getCodeBase(), "", this);
148 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
152 public JalviewJmolBinding(JmolViewer viewer2)
155 viewer.setJmolStatusListener(this);
156 viewer.addSelectionListener(this);
160 * construct a title string for the viewer window based on the data jalview
165 public String getViewerTitle()
167 if (sequence == null || pdbentry == null || sequence.length < 1
168 || pdbentry.length < 1 || sequence[0].length < 1)
170 return ("Jalview Jmol Window");
172 // TODO: give a more informative title when multiple structures are
174 StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
175 + pdbentry[0].getId());
177 if (pdbentry[0].getProperty() != null)
179 if (pdbentry[0].getProperty().get("method") != null)
181 title.append(" Method: ");
182 title.append(pdbentry[0].getProperty().get("method"));
184 if (pdbentry[0].getProperty().get("chains") != null)
186 title.append(" Chain:");
187 title.append(pdbentry[0].getProperty().get("chains"));
190 return title.toString();
194 * prepare the view for a given set of models/chains. chainList contains
195 * strings of the form 'pdbfilename:Chaincode'
198 * list of chains to make visible
200 public void centerViewer(Vector chainList)
202 StringBuffer cmd = new StringBuffer();
205 for (int i = 0, iSize = chainList.size(); i < iSize; i++)
208 lbl = (String) chainList.elementAt(i);
212 mlength = lbl.indexOf(":", p);
213 } while (p < mlength && mlength < (lbl.length() - 2));
214 cmd.append(":" + lbl.substring(mlength + 1) + " /"
215 + getModelNum(lbl.substring(0, mlength)) + " or ");
217 if (cmd.length() > 0)
218 cmd.setLength(cmd.length() - 4);
219 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
222 public void closeViewer()
224 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
225 // remove listeners for all structures in viewer
226 StructureSelectionManager.getStructureSelectionManager()
227 .removeStructureViewerListener(this, this.getPdbFile());
228 // and shut down jmol
229 viewer.evalStringQuiet("zap");
230 viewer.setJmolStatusListener(null);
235 public void colourByChain()
237 colourBySequence = false;
238 // TODO: colour by chain should colour each chain distinctly across all
240 // TODO: http://issues.jalview.org/browse/JAL-628
241 evalStateCommand("select *;color chain");
244 public void colourByCharge()
246 colourBySequence = false;
247 evalStateCommand("select *;color white;select ASP,GLU;color red;"
248 + "select LYS,ARG;color blue;select CYS;color yellow");
252 * superpose the structures associated with sequences in the alignment
253 * according to their corresponding positions.
255 public void superposeStructures(AlignmentI alignment)
257 superposeStructures(alignment, -1, null);
261 * superpose the structures associated with sequences in the alignment
262 * according to their corresponding positions. ded)
264 * @param refStructure
265 * - select which pdb file to use as reference (default is -1 - the
266 * first structure in the alignment)
268 public void superposeStructures(AlignmentI alignment, int refStructure)
270 superposeStructures(alignment, refStructure, null);
274 * superpose the structures associated with sequences in the alignment
275 * according to their corresponding positions. ded)
277 * @param refStructure
278 * - select which pdb file to use as reference (default is -1 - the
279 * first structure in the alignment)
283 public void superposeStructures(AlignmentI alignment, int refStructure,
284 ColumnSelection hiddenCols)
286 String[] files = getPdbFile();
287 if (refStructure >= files.length)
289 System.err.println("Invalid reference structure value "
293 if (refStructure < -1)
297 StringBuffer command = new StringBuffer(), selectioncom = new StringBuffer();
299 boolean matched[] = new boolean[alignment.getWidth()];
300 for (int m = 0; m < matched.length; m++)
303 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
306 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
307 String isel[] = new String[files.length];
308 // reference structure - all others are superposed in it
309 String[] targetC = new String[files.length];
310 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
312 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
314 if (mapping == null || mapping.length < 1)
318 for (int s = 0; s < sequence[pdbfnum].length; s++)
320 for (int sp, m = 0; m < mapping.length; m++)
322 if (mapping[m].getSequence() == sequence[pdbfnum][s]
323 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
325 if (refStructure == -1)
327 refStructure = pdbfnum;
329 SequenceI asp = alignment.getSequenceAt(sp);
330 for (int r = 0; r < matched.length; r++)
336 matched[r] = false; // assume this is not a good site
337 if (r >= asp.getLength())
342 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
344 // no mapping to gaps in sequence
347 int t = asp.findPosition(r); // sequence position
348 int apos = mapping[m].getAtomNum(t);
349 int pos = mapping[m].getPDBResNum(t);
351 if (pos < 1 || pos == lastPos)
353 // can't align unmapped sequence
356 matched[r] = true; // this is a good ite
358 // just record this residue position
359 commonrpositions[pdbfnum][r] = pos;
361 // create model selection suffix
362 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
363 if (mapping[m].getChain() == null
364 || mapping[m].getChain().trim().length() == 0)
366 targetC[pdbfnum] = "";
370 targetC[pdbfnum] = ":" + mapping[m].getChain();
372 // move on to next pdb file
373 s = sequence[pdbfnum].length;
379 String[] selcom = new String[files.length];
381 // generate select statements to select regions to superimpose structures
383 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
385 String chainCd = targetC[pdbfnum];
388 StringBuffer molsel = new StringBuffer();
390 for (int r = 0; r < matched.length; r++)
397 if (lpos != commonrpositions[pdbfnum][r] - 1)
403 molsel.append(chainCd);
404 // molsel.append("} {");
410 // continuous run - and lpos >-1
413 // at the beginning, so add dash
419 lpos = commonrpositions[pdbfnum][r];
420 // molsel.append(lpos);
423 // add final selection phrase
427 molsel.append(chainCd);
430 selcom[pdbfnum] = molsel.toString();
431 selectioncom.append("((");
432 selectioncom.append(selcom[pdbfnum].substring(1,
433 selcom[pdbfnum].length() - 1));
434 selectioncom.append(" )& ");
435 selectioncom.append(pdbfnum + 1);
436 selectioncom.append(".1)");
437 if (pdbfnum < files.length - 1)
439 selectioncom.append("|");
443 // TODO: consider bailing if nmatched less than 4 because superposition not well defined.
444 // TODO: refactor superposable position search (above) from jmol selection construction (below)
445 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
447 if (pdbfnum == refStructure)
451 command.append("compare ");
453 command.append(1 + pdbfnum);
454 command.append(".1} {");
455 command.append(1 + refStructure);
456 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
458 // form the matched pair strings
460 for (int s = 0; s < 2; s++)
462 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
464 command.append(" ROTATE TRANSLATE;\n");
466 System.out.println("Select regions:\n" + selectioncom.toString());
467 evalStateCommand("select *; cartoons off; backbone; select ("
468 + selectioncom.toString() + "); cartoons; ");
469 // selcom.append("; ribbons; ");
470 System.out.println("Superimpose command(s):\n" + command.toString());
472 evalStateCommand(command.toString());
474 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
477 public void evalStateCommand(String command)
480 if (lastCommand == null || !lastCommand.equals(command))
482 viewer.evalStringQuiet(command + "\n");
485 lastCommand = command;
489 * colour any structures associated with sequences in the given alignment
490 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
491 * if colourBySequence is enabled.
493 public void colourBySequence(boolean showFeatures, AlignmentI alignment)
495 if (!colourBySequence)
501 String[] files = getPdbFile();
502 SequenceRenderer sr = getSequenceRenderer();
504 FeatureRenderer fr = null;
507 fr = getFeatureRenderer();
510 StringBuffer command = new StringBuffer();
512 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
514 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
516 if (mapping == null || mapping.length < 1)
520 for (int s = 0; s < sequence[pdbfnum].length; s++)
522 for (int sp, m = 0; m < mapping.length; m++)
524 if (mapping[m].getSequence() == sequence[pdbfnum][s]
525 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
527 SequenceI asp = alignment.getSequenceAt(sp);
528 for (int r = 0; r < asp.getLength(); r++)
530 // no mapping to gaps in sequence
531 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
535 int pos = mapping[m].getPDBResNum(asp.findPosition(r));
537 if (pos < 1 || pos == lastPos)
542 Color col = sr.getResidueBoxColour(sequence[pdbfnum][s], r);
545 col = fr.findFeatureColour(col, sequence[pdbfnum][s], r);
546 String newSelcom = (mapping[m].getChain() != " " ? ":"
547 + mapping[m].getChain() : "")
556 + col.getBlue() + "]";
557 if (command.toString().endsWith(newSelcom))
559 command = condenseCommand(command.toString(), pos);
562 // TODO: deal with case when buffer is too large for Jmol to parse
563 // - execute command and flush
565 command.append(";select " + pos);
566 command.append(newSelcom);
573 evalStateCommand(command.toString());
576 public boolean isColourBySequence()
578 return colourBySequence;
581 public void setColourBySequence(boolean colourBySequence)
583 this.colourBySequence = colourBySequence;
586 StringBuffer condenseCommand(String command, int pos)
589 StringBuffer sb = new StringBuffer(command.substring(0,
590 command.lastIndexOf("select") + 7));
592 command = command.substring(sb.length());
596 if (command.indexOf("-") > -1)
598 start = command.substring(0, command.indexOf("-"));
602 start = command.substring(0, command.indexOf(":"));
605 sb.append(start + "-" + pos + command.substring(command.indexOf(":")));
610 public void createImage(String file, String type, int quality)
612 System.out.println("JMOL CREATE IMAGE");
615 public String createImage(String fileName, String type,
616 Object textOrBytes, int quality)
618 System.out.println("JMOL CREATE IMAGE");
622 public String eval(String strEval)
624 // System.out.println(strEval);
625 // "# 'eval' is implemented only for the applet.";
629 // End StructureListener
630 // //////////////////////////
632 public float[][] functionXY(String functionName, int x, int y)
637 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
639 // TODO Auto-generated method stub
643 public Color getColour(int atomIndex, int pdbResNum, String chain,
646 if (getModelNum(pdbfile) < 0)
648 // TODO: verify atomIndex is selecting correct model.
649 return new Color(viewer.getAtomArgb(atomIndex));
653 * returns the current featureRenderer that should be used to colour the
658 public abstract FeatureRenderer getFeatureRenderer();
661 * instruct the Jalview binding to update the pdbentries vector if necessary
662 * prior to matching the jmol view's contents to the list of structure files
663 * Jalview knows about.
665 public abstract void refreshPdbEntries();
667 private int getModelNum(String modelFileName)
669 String[] mfn = getPdbFile();
674 for (int i = 0; i < mfn.length; i++)
676 if (mfn[i].equalsIgnoreCase(modelFileName))
683 * map between index of model filename returned from getPdbFile and the first
684 * index of models from this file in the viewer. Note - this is not trimmed -
685 * use getPdbFile to get number of unique models.
687 private int _modelFileNameMap[];
689 // ////////////////////////////////
690 // /StructureListener
691 public synchronized String[] getPdbFile()
695 return new String[0];
697 if (modelFileNames == null)
700 String mset[] = new String[viewer.getModelCount()];
701 _modelFileNameMap = new int[mset.length];
703 mset[0] = viewer.getModelFileName(0);
704 for (int i = 1; i < mset.length; i++)
706 mset[j] = viewer.getModelFileName(i);
707 _modelFileNameMap[j] = i; // record the model index for the filename
708 // skip any additional models in the same file (NMR structures)
709 if ((mset[j] == null ? mset[j] != mset[j - 1] : (mset[j - 1] == null
710 || !mset[j].equals(mset[j - 1]))))
715 modelFileNames = new String[j];
716 System.arraycopy(mset, 0, modelFileNames, 0, j);
718 return modelFileNames;
722 * map from string to applet
724 public Map getRegistryInfo()
726 // TODO Auto-generated method stub
731 * returns the current sequenceRenderer that should be used to colour the
736 public abstract SequenceRenderer getSequenceRenderer();
738 // ///////////////////////////////
739 // JmolStatusListener
741 public void handlePopupMenu(int x, int y)
743 jmolpopup.show(x, y);
747 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
750 if (modelFileNames == null)
755 // look up file model number for this pdbfile
758 // may need to adjust for URLencoding here - we don't worry about that yet.
759 while (mdlNum < modelFileNames.length
760 && !pdbfile.equals(modelFileNames[mdlNum]))
762 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
765 if (mdlNum == modelFileNames.length)
771 // if (!pdbfile.equals(pdbentry.getFile()))
773 if (resetLastRes.length() > 0)
775 viewer.evalStringQuiet(resetLastRes.toString());
779 eval.append("select " + pdbResNum); // +modelNum
781 resetLastRes.setLength(0);
782 resetLastRes.append("select " + pdbResNum); // +modelNum
785 resetLastRes.append(":");
786 if (!chain.equals(" "))
789 resetLastRes.append(chain);
792 eval.append(" /" + (mdlNum + 1));
793 resetLastRes.append("/" + (mdlNum + 1));
795 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
797 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
798 + " and not hetero; spacefill 0;");
800 eval.append("spacefill 200;select none");
802 viewer.evalStringQuiet(eval.toString());
807 boolean debug = true;
809 private void jmolHistory(boolean enable)
811 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
814 public void loadInline(String string)
818 // viewer.loadInline(strModel, isAppend);
820 // construct fake fullPathName and fileName so we can identify the file
822 // Then, construct pass a reader for the string to Jmol.
823 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
824 // fileName, null, reader, false, null, null, 0);
825 viewer.openStringInline(string);
828 public void mouseOverStructure(int atomIndex, String strInfo)
831 int mdlSep = strInfo.indexOf("/");
832 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
834 if (chainSeparator == -1)
836 chainSeparator = strInfo.indexOf(".");
837 if (mdlSep > -1 && mdlSep < chainSeparator)
839 chainSeparator1 = chainSeparator;
840 chainSeparator = mdlSep;
843 pdbResNum = Integer.parseInt(strInfo.substring(
844 strInfo.indexOf("]") + 1, chainSeparator));
848 if (strInfo.indexOf(":") > -1)
849 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
850 strInfo.indexOf("."));
856 String pdbfilename = modelFileNames[frameNo]; // default is first or current
860 if (chainSeparator1 == -1)
862 chainSeparator1 = strInfo.indexOf(".", mdlSep);
864 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
865 chainSeparator1) : strInfo.substring(mdlSep + 1);
868 // recover PDB filename for the model hovered over.
870 .getModelFileName(new Integer(mdlId).intValue() - 1);
871 } catch (Exception e)
876 if (lastMessage == null || !lastMessage.equals(strInfo))
877 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
879 lastMessage = strInfo;
882 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
886 System.err.println("Ignoring additional hover info: " + data
887 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
889 mouseOverStructure(atomIndex, strInfo);
893 * { if (history != null && strStatus != null &&
894 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
898 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
901 * this implements the toggle label behaviour copied from the original
902 * structure viewer, MCView
906 System.err.println("Ignoring additional pick data string " + strData);
908 int chainSeparator = strInfo.indexOf(":");
910 if (chainSeparator == -1)
911 chainSeparator = strInfo.indexOf(".");
913 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
915 String mdlString = "";
916 if ((p = strInfo.indexOf(":")) > -1)
917 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
919 if ((p = strInfo.indexOf("/")) > -1)
921 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
923 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
927 if (!atomsPicked.contains(picked))
929 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
930 atomsPicked.addElement(picked);
934 viewer.evalString("select " + picked + ";label off");
935 atomsPicked.removeElement(picked);
938 // TODO: in application this happens
940 // if (scriptWindow != null)
942 // scriptWindow.sendConsoleMessage(strInfo);
943 // scriptWindow.sendConsoleMessage("\n");
948 public void notifyCallback(int type, Object[] data)
954 case JmolConstants.CALLBACK_LOADSTRUCT:
955 notifyFileLoaded((String) data[1], (String) data[2],
956 (String) data[3], (String) data[4],
957 ((Integer) data[5]).intValue());
960 case JmolConstants.CALLBACK_PICK:
961 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
963 // also highlight in alignment
964 case JmolConstants.CALLBACK_HOVER:
965 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
968 case JmolConstants.CALLBACK_SCRIPT:
969 notifyScriptTermination((String) data[2],
970 ((Integer) data[3]).intValue());
972 case JmolConstants.CALLBACK_ECHO:
973 sendConsoleEcho((String) data[1]);
975 case JmolConstants.CALLBACK_MESSAGE:
976 sendConsoleMessage((data == null) ? ((String) null)
979 case JmolConstants.CALLBACK_ERROR:
980 // System.err.println("Ignoring error callback.");
982 case JmolConstants.CALLBACK_SYNC:
983 case JmolConstants.CALLBACK_RESIZE:
986 case JmolConstants.CALLBACK_MEASURE:
988 case JmolConstants.CALLBACK_CLICK:
990 System.err.println("Unhandled callback " + type + " "
991 + data[1].toString());
994 } catch (Exception e)
996 System.err.println("Squashed Jmol callback handler error:");
1001 public boolean notifyEnabled(int callbackPick)
1003 switch (callbackPick)
1005 case JmolConstants.CALLBACK_ECHO:
1006 case JmolConstants.CALLBACK_LOADSTRUCT:
1007 case JmolConstants.CALLBACK_MEASURE:
1008 case JmolConstants.CALLBACK_MESSAGE:
1009 case JmolConstants.CALLBACK_PICK:
1010 case JmolConstants.CALLBACK_SCRIPT:
1011 case JmolConstants.CALLBACK_HOVER:
1012 case JmolConstants.CALLBACK_ERROR:
1014 case JmolConstants.CALLBACK_RESIZE:
1015 case JmolConstants.CALLBACK_SYNC:
1016 case JmolConstants.CALLBACK_CLICK:
1017 case JmolConstants.CALLBACK_ANIMFRAME:
1018 case JmolConstants.CALLBACK_MINIMIZATION:
1023 // incremented every time a load notification is successfully handled - lightweight mechanism for other threads to detect when they can start referrring to new structures.
1024 private long loadNotifiesHandled=0;
1025 public long getLoadNotifiesHandled()
1027 return loadNotifiesHandled;
1029 public void notifyFileLoaded(String fullPathName, String fileName2,
1030 String modelName, String errorMsg, int modelParts)
1032 if (errorMsg != null)
1034 fileLoadingError = errorMsg;
1038 // TODO: deal sensibly with models loaded inLine:
1039 // modelName will be null, as will fullPathName.
1041 // the rest of this routine ignores the arguments, and simply interrogates
1042 // the Jmol view to find out what structures it contains, and adds them to
1043 // the structure selection manager.
1044 fileLoadingError = null;
1045 String[] oldmodels = modelFileNames;
1046 modelFileNames = null;
1047 chainNames = new Vector();
1048 boolean notifyLoaded = false;
1049 String[] modelfilenames = getPdbFile();
1050 ssm = StructureSelectionManager.getStructureSelectionManager();
1051 // first check if we've lost any structures
1052 if (oldmodels != null && oldmodels.length > 0)
1055 for (int i = 0; i < oldmodels.length; i++)
1057 for (int n = 0; n < modelfilenames.length; n++)
1059 if (modelfilenames[n] == oldmodels[i])
1061 oldmodels[i] = null;
1065 if (oldmodels[i] != null)
1072 String[] oldmfn = new String[oldm];
1074 for (int i = 0; i < oldmodels.length; i++)
1076 if (oldmodels[i] != null)
1078 oldmfn[oldm++] = oldmodels[i];
1081 // deregister the Jmol instance for these structures - we'll add
1082 // ourselves again at the end for the current structure set.
1083 ssm.removeStructureViewerListener(this, oldmfn);
1086 refreshPdbEntries();
1087 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1089 String fileName = modelfilenames[modelnum];
1090 boolean foundEntry = false;
1091 MCview.PDBfile pdb = null;
1092 String pdbfile = null, pdbfhash = null;
1093 // model was probably loaded inline - so check the pdb file hashcode
1096 // calculate essential attributes for the pdb data imported inline.
1097 // prolly need to resolve modelnumber properly - for now just use our 'best guess'
1098 pdbfile = viewer.getData(""+(1+_modelFileNameMap[modelnum])+".0",
1100 pdbfhash = "" + pdbfile.hashCode();
1102 if (pdbentry != null)
1104 // search pdbentries and sequences to find correct pdbentry for this
1106 for (int pe = 0; pe < pdbentry.length; pe++)
1108 boolean matches = false;
1109 if (fileName == null)
1112 // see JAL-623 - need method of matching pasted data up
1114 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
1115 AppletFormatAdapter.PASTE);
1116 pdbentry[modelnum].setFile("INLINE" + pdb.id);
1123 if (matches = pdbentry[pe].getFile().equals(fileName))
1126 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1129 // to be tested. See mantis bug
1130 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1131 String protocol = AppletFormatAdapter.URL;
1134 File fl = new java.io.File(pdbentry[pe].getFile());
1137 protocol = AppletFormatAdapter.FILE;
1139 } catch (Exception e)
1145 pdb = ssm.setMapping(sequence[pe], chains[pe],
1146 pdbentry[pe].getFile(), protocol);
1153 pdbentry[pe].setId(pdb.id);
1154 // add an entry for every chain in the model
1155 for (int i = 0; i < pdb.chains.size(); i++)
1157 chainNames.addElement(new String(pdb.id + ":"
1158 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id));
1160 notifyLoaded = true;
1164 if (!foundEntry && associateNewStructs)
1166 // this is a foreign pdb file that jalview doesn't know about - add
1167 // it to the dataset and try to find a home - either on a matching
1168 // sequence or as a new sequence.
1169 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1171 // parse pdb file into a chain, etc.
1172 // locate best match for pdb in associated views and add mapping to
1174 // if properly registered then
1175 notifyLoaded = true;
1180 // so finally, update the jmol bits and pieces
1181 if (jmolpopup != null)
1183 // potential for deadlock here:
1184 // jmolpopup.updateComputedMenus();
1186 if (!isLoadingFromArchive())
1188 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1190 setLoadingFromArchive(false);
1191 // register ourselves as a listener and notify the gui that it needs to
1193 ssm.addStructureViewerListener(this);
1196 FeatureRenderer fr = getFeatureRenderer();
1202 loadNotifiesHandled++;
1206 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1208 notifyAtomPicked(iatom, strMeasure, null);
1211 public abstract void notifyScriptTermination(String strStatus,
1215 * display a message echoed from the jmol viewer
1219 public abstract void sendConsoleEcho(String strEcho); /*
1220 * { showConsole(true);
1222 * history.append("\n" +
1226 // /End JmolStatusListener
1227 // /////////////////////////////
1231 * status message - usually the response received after a script
1234 public abstract void sendConsoleMessage(String strStatus);
1236 public void setCallbackFunction(String callbackType,
1237 String callbackFunction)
1239 System.err.println("Ignoring set-callback request to associate "
1240 + callbackType + " with function " + callbackFunction);
1244 public void setJalviewColourScheme(ColourSchemeI cs)
1246 colourBySequence = false;
1255 // TODO: Switch between nucleotide or aa selection expressions
1256 Enumeration en = ResidueProperties.aa3Hash.keys();
1257 StringBuffer command = new StringBuffer("select *;color white;");
1258 while (en.hasMoreElements())
1260 res = en.nextElement().toString();
1261 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
1265 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
1267 command.append("select " + res + ";color[" + col.getRed() + ","
1268 + col.getGreen() + "," + col.getBlue() + "];");
1271 evalStateCommand(command.toString());
1275 public void showHelp()
1277 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1281 * open the URL somehow
1285 public abstract void showUrl(String url, String target);
1288 * called when the binding thinks the UI needs to be refreshed after a Jmol
1289 * state change. this could be because structures were loaded, or because an
1290 * error has occured.
1292 public abstract void refreshGUI();
1295 * called to show or hide the associated console window container.
1298 public abstract void showConsole(boolean show);
1300 * @param renderPanel
1302 * - when true will initialise jmol's file IO system (should be false
1303 * in applet context)
1305 * @param documentBase
1307 * @param commandOptions
1309 public void allocateViewer(Component renderPanel, boolean jmolfileio,
1310 String htmlName, URL documentBase, URL codeBase,
1311 String commandOptions)
1313 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase, codeBase, commandOptions, null,null);
1317 * @param renderPanel
1319 * - when true will initialise jmol's file IO system (should be false
1320 * in applet context)
1322 * @param documentBase
1324 * @param commandOptions
1325 * @param consolePanel - panel to contain Jmol console
1326 * @param buttonsToShow - buttons to show on the console, in ordr
1328 public void allocateViewer(Component renderPanel, boolean jmolfileio,
1329 String htmlName, URL documentBase, URL codeBase,
1330 String commandOptions, final Container consolePanel, String buttonsToShow)
1332 viewer = JmolViewer.allocateViewer(renderPanel,
1333 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1334 + ((Object) this).toString(), documentBase, codeBase,
1335 commandOptions, this);
1336 console = new AppConsole(viewer, null, consolePanel,
1338 viewer.setConsole(new JmolAppConsoleInterface() {
1341 public JmolScriptEditorInterface getScriptEditor()
1343 return console.getScriptEditor();
1347 public JmolAppConsoleInterface getAppConsole(Viewer viewer,
1353 public String getText()
1355 return console.getText();
1359 public Object getMyMenuBar()
1361 return console.getMyMenuBar();
1365 public void setVisible(boolean b)
1371 public void sendConsoleEcho(String strEcho)
1373 console.sendConsoleEcho(strEcho);
1378 public void sendConsoleMessage(String strInfo)
1380 console.sendConsoleMessage(strInfo);
1390 public void dispose()
1401 protected org.jmol.api.JmolAppConsoleInterface console = null;
1403 public void setLoadingFromArchive(boolean loadingFromArchive)
1405 this.loadingFromArchive = loadingFromArchive;
1408 public boolean isLoadingFromArchive()
1410 return loadingFromArchive;
1413 public void setBackgroundColour(java.awt.Color col)
1416 viewer.evalStringQuiet("background [" + col.getRed() + ","
1417 + col.getGreen() + "," + col.getBlue() + "];");
1422 * add structures and any known sequence associations
1424 * @returns the pdb entries added to the current set.
1426 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
1427 SequenceI[][] seq, String[][] chns)
1430 Vector v = new Vector();
1431 Vector rtn = new Vector();
1432 for (int i = 0; i < pdbentry.length; i++)
1434 v.addElement(pdbentry[i]);
1436 for (int i = 0; i < pdbe.length; i++)
1438 int r = v.indexOf(pdbe[i]);
1439 if (r == -1 || r >= pdbentry.length)
1441 rtn.addElement(new int[]
1443 v.addElement(pdbe[i]);
1447 // just make sure the sequence/chain entries are all up to date
1448 addSequenceAndChain(r, seq[i], chns[i]);
1451 pdbe = new PDBEntry[v.size()];
1456 // expand the tied seuqence[] and string[] arrays
1457 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
1458 String[][] sch = new String[pdbentry.length][];
1459 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
1460 System.arraycopy(chains, 0, sch, 0, this.chains.length);
1463 pdbe = new PDBEntry[rtn.size()];
1464 for (int r = 0; r < pdbe.length; r++)
1466 int[] stri = ((int[]) rtn.elementAt(r));
1467 // record the pdb file as a new addition
1468 pdbe[r] = pdbentry[stri[0]];
1469 // and add the new sequence/chain entries
1470 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
1480 public void addSequence(int pe, SequenceI[] seq)
1482 // add sequences to the pe'th pdbentry's seuqence set.
1483 addSequenceAndChain(pe, seq, null);
1486 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
1488 if (pe < 0 || pe >= pdbentry.length)
1491 "Implementation error - no corresponding pdbentry (for index "
1492 + pe + ") to add sequences mappings to");
1494 final String nullChain = "TheNullChain";
1495 Vector s = new Vector();
1496 Vector c = new Vector();
1499 chains = new String[pdbentry.length][];
1501 if (sequence[pe] != null)
1503 for (int i = 0; i < sequence[pe].length; i++)
1505 s.addElement(sequence[pe][i]);
1506 if (chains[pe] != null)
1508 if (i < chains[pe].length)
1510 c.addElement(chains[pe][i]);
1514 c.addElement(nullChain);
1519 if (tchain != null && tchain.length > 0)
1521 c.addElement(nullChain);
1526 for (int i = 0; i < seq.length; i++)
1528 if (!s.contains(seq[i]))
1530 s.addElement(seq[i]);
1531 if (tchain != null && i < tchain.length)
1533 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
1537 SequenceI[] tmp = new SequenceI[s.size()];
1542 String[] tch = new String[c.size()];
1544 for (int i = 0; i < tch.length; i++)
1546 if (tch[i] == nullChain)