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;
43 import jalview.schemes.*;
45 public abstract class JalviewJmolBinding implements StructureListener,
46 JmolStatusListener, SequenceStructureBinding, JmolSelectionListener
50 * set if Jmol state is being restored from some source - instructs binding
51 * not to apply default display style when structure set is updated for first
54 private boolean loadingFromArchive = false;
57 * state flag used to check if the Jmol viewer's paint method can be called
59 private boolean finishedInit = false;
61 public boolean isFinishedInit()
66 public void setFinishedInit(boolean finishedInit)
68 this.finishedInit = finishedInit;
71 boolean allChainsSelected = false;
74 * when true, try to search the associated datamodel for sequences that are
75 * associated with any unknown structures in the Jmol view.
77 private boolean associateNewStructs = false;
79 Vector atomsPicked = new Vector();
81 public Vector chainNames;
84 * array of target chains for seuqences - tied to pdbentry and sequence[]
86 protected String[][] chains;
88 boolean colourBySequence = true;
90 StringBuffer eval = new StringBuffer();
92 public String fileLoadingError;
95 * the default or current model displayed if the model cannot be identified
96 * from the selection message
100 protected JmolPopup jmolpopup;
106 boolean loadedInline;
109 * current set of model filenames loaded in the Jmol instance
111 String[] modelFileNames = null;
113 public PDBEntry[] pdbentry;
116 * datasource protocol for access to PDBEntry
118 String protocol = null;
120 StringBuffer resetLastRes = new StringBuffer();
123 * sequences mapped to each pdbentry
125 public SequenceI[][] sequence;
127 StructureSelectionManager ssm;
129 public JmolViewer viewer;
131 public JalviewJmolBinding(PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
132 String[][] chains, String protocol)
134 this.sequence = sequenceIs;
135 this.chains = chains;
136 this.pdbentry = pdbentry;
137 this.protocol = protocol;
140 this.chains = new String[pdbentry.length][];
143 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
144 * "jalviewJmol", ap.av.applet .getDocumentBase(),
145 * ap.av.applet.getCodeBase(), "", this);
147 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
151 public JalviewJmolBinding(JmolViewer viewer2)
154 viewer.setJmolStatusListener(this);
155 viewer.addSelectionListener(this);
159 * construct a title string for the viewer window based on the data jalview
164 public String getViewerTitle()
166 if (sequence == null || pdbentry == null || sequence.length < 1
167 || pdbentry.length < 1 || sequence[0].length < 1)
169 return ("Jalview Jmol Window");
171 // TODO: give a more informative title when multiple structures are
173 StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
174 + pdbentry[0].getId());
176 if (pdbentry[0].getProperty() != null)
178 if (pdbentry[0].getProperty().get("method") != null)
180 title.append(" Method: ");
181 title.append(pdbentry[0].getProperty().get("method"));
183 if (pdbentry[0].getProperty().get("chains") != null)
185 title.append(" Chain:");
186 title.append(pdbentry[0].getProperty().get("chains"));
189 return title.toString();
193 * prepare the view for a given set of models/chains. chainList contains
194 * strings of the form 'pdbfilename:Chaincode'
197 * list of chains to make visible
199 public void centerViewer(Vector chainList)
201 StringBuffer cmd = new StringBuffer();
204 for (int i = 0, iSize = chainList.size(); i < iSize; i++)
207 lbl = (String) chainList.elementAt(i);
211 mlength = lbl.indexOf(":", p);
212 } while (p < mlength && mlength < (lbl.length() - 2));
213 cmd.append(":" + lbl.substring(mlength + 1) + " /"
214 + getModelNum(lbl.substring(0, mlength)) + " or ");
216 if (cmd.length() > 0)
217 cmd.setLength(cmd.length() - 4);
218 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
221 public void closeViewer()
223 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
224 // remove listeners for all structures in viewer
225 StructureSelectionManager.getStructureSelectionManager()
226 .removeStructureViewerListener(this, this.getPdbFile());
227 // and shut down jmol
228 viewer.evalStringQuiet("zap");
229 viewer.setJmolStatusListener(null);
234 public void colourByChain()
236 colourBySequence = false;
237 // TODO: colour by chain should colour each chain distinctly across all
239 // TODO: http://issues.jalview.org/browse/JAL-628
240 evalStateCommand("select *;color chain");
243 public void colourByCharge()
245 colourBySequence = false;
246 evalStateCommand("select *;color white;select ASP,GLU;color red;"
247 + "select LYS,ARG;color blue;select CYS;color yellow");
251 * superpose the structures associated with sequences in the alignment
252 * according to their corresponding positions.
254 public void superposeStructures(AlignmentI alignment)
256 superposeStructures(alignment, -1, null);
260 * superpose the structures associated with sequences in the alignment
261 * according to their corresponding positions. ded)
263 * @param refStructure
264 * - select which pdb file to use as reference (default is -1 - the
265 * first structure in the alignment)
267 public void superposeStructures(AlignmentI alignment, int refStructure)
269 superposeStructures(alignment, refStructure, null);
273 * superpose the structures associated with sequences in the alignment
274 * according to their corresponding positions. ded)
276 * @param refStructure
277 * - select which pdb file to use as reference (default is -1 - the
278 * first structure in the alignment)
282 public void superposeStructures(AlignmentI alignment, int refStructure,
283 ColumnSelection hiddenCols)
285 String[] files = getPdbFile();
286 if (refStructure >= files.length)
288 System.err.println("Invalid reference structure value "
292 if (refStructure < -1)
296 StringBuffer command = new StringBuffer(), selectioncom = new StringBuffer();
298 boolean matched[] = new boolean[alignment.getWidth()];
299 for (int m = 0; m < matched.length; m++)
302 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
305 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
306 String isel[] = new String[files.length];
307 // reference structure - all others are superposed in it
308 String[] targetC = new String[files.length];
309 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
311 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
313 if (mapping == null || mapping.length < 1)
317 for (int s = 0; s < sequence[pdbfnum].length; s++)
319 for (int sp, m = 0; m < mapping.length; m++)
321 if (mapping[m].getSequence() == sequence[pdbfnum][s]
322 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
324 if (refStructure == -1)
326 refStructure = pdbfnum;
328 SequenceI asp = alignment.getSequenceAt(sp);
329 for (int r = 0; r < matched.length; r++)
335 matched[r] = false; // assume this is not a good site
336 if (r >= asp.getLength())
341 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
343 // no mapping to gaps in sequence
346 int t = asp.findPosition(r); // sequence position
347 int apos = mapping[m].getAtomNum(t);
348 int pos = mapping[m].getPDBResNum(t);
350 if (pos < 1 || pos == lastPos)
352 // can't align unmapped sequence
355 matched[r] = true; // this is a good ite
357 // just record this residue position
358 commonrpositions[pdbfnum][r] = pos;
360 // create model selection suffix
361 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
362 if (mapping[m].getChain() == null
363 || mapping[m].getChain().trim().length() == 0)
365 targetC[pdbfnum] = "";
369 targetC[pdbfnum] = ":" + mapping[m].getChain();
371 // move on to next pdb file
372 s = sequence[pdbfnum].length;
378 String[] selcom = new String[files.length];
380 // generate select statements to select regions to superimpose structures
382 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
384 String chainCd = targetC[pdbfnum];
387 StringBuffer molsel = new StringBuffer();
389 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
445 // TODO: refactor superposable position search (above) from jmol selection
446 // construction (below)
447 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
449 if (pdbfnum == refStructure)
453 command.append("compare ");
455 command.append(1 + pdbfnum);
456 command.append(".1} {");
457 command.append(1 + refStructure);
458 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
460 // form the matched pair strings
462 for (int s = 0; s < 2; s++)
464 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
466 command.append(" ROTATE TRANSLATE;\n");
468 System.out.println("Select regions:\n" + selectioncom.toString());
469 evalStateCommand("select *; cartoons off; backbone; select ("
470 + selectioncom.toString() + "); cartoons; ");
471 // selcom.append("; ribbons; ");
472 System.out.println("Superimpose command(s):\n" + command.toString());
474 evalStateCommand(command.toString());
476 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
479 public void evalStateCommand(String command)
482 if (lastCommand == null || !lastCommand.equals(command))
484 viewer.evalStringQuiet(command + "\n");
487 lastCommand = command;
491 * colour any structures associated with sequences in the given alignment
492 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
493 * if colourBySequence is enabled.
495 public void colourBySequence(boolean showFeatures, AlignmentI alignment)
497 if (!colourBySequence)
503 String[] files = getPdbFile();
504 SequenceRenderer sr = getSequenceRenderer();
506 FeatureRenderer fr = null;
509 fr = getFeatureRenderer();
512 StringBuffer command = new StringBuffer();
514 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
516 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
518 if (mapping == null || mapping.length < 1)
522 for (int s = 0; s < sequence[pdbfnum].length; s++)
524 for (int sp, m = 0; m < mapping.length; m++)
526 if (mapping[m].getSequence() == sequence[pdbfnum][s]
527 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
529 SequenceI asp = alignment.getSequenceAt(sp);
530 for (int r = 0; r < asp.getLength(); r++)
532 // no mapping to gaps in sequence
533 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
537 int pos = mapping[m].getPDBResNum(asp.findPosition(r));
539 if (pos < 1 || pos == lastPos)
544 Color col = sr.getResidueBoxColour(sequence[pdbfnum][s], r);
547 col = fr.findFeatureColour(col, sequence[pdbfnum][s], r);
548 String newSelcom = (mapping[m].getChain() != " " ? ":"
549 + mapping[m].getChain() : "")
558 + col.getBlue() + "]";
559 if (command.toString().endsWith(newSelcom))
561 command = condenseCommand(command.toString(), pos);
564 // TODO: deal with case when buffer is too large for Jmol to parse
565 // - execute command and flush
567 command.append(";select " + pos);
568 command.append(newSelcom);
575 evalStateCommand(command.toString());
578 public boolean isColourBySequence()
580 return colourBySequence;
583 public void setColourBySequence(boolean colourBySequence)
585 this.colourBySequence = colourBySequence;
588 StringBuffer condenseCommand(String command, int pos)
591 StringBuffer sb = new StringBuffer(command.substring(0,
592 command.lastIndexOf("select") + 7));
594 command = command.substring(sb.length());
598 if (command.indexOf("-") > -1)
600 start = command.substring(0, command.indexOf("-"));
604 start = command.substring(0, command.indexOf(":"));
607 sb.append(start + "-" + pos + command.substring(command.indexOf(":")));
612 public void createImage(String file, String type, int quality)
614 System.out.println("JMOL CREATE IMAGE");
617 public String createImage(String fileName, String type,
618 Object textOrBytes, int quality)
620 System.out.println("JMOL CREATE IMAGE");
624 public String eval(String strEval)
626 // System.out.println(strEval);
627 // "# 'eval' is implemented only for the applet.";
631 // End StructureListener
632 // //////////////////////////
634 public float[][] functionXY(String functionName, int x, int y)
639 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
641 // TODO Auto-generated method stub
645 public Color getColour(int atomIndex, int pdbResNum, String chain,
648 if (getModelNum(pdbfile) < 0)
650 // TODO: verify atomIndex is selecting correct model.
651 return new Color(viewer.getAtomArgb(atomIndex));
655 * returns the current featureRenderer that should be used to colour the
660 public abstract FeatureRenderer getFeatureRenderer();
663 * instruct the Jalview binding to update the pdbentries vector if necessary
664 * prior to matching the jmol view's contents to the list of structure files
665 * Jalview knows about.
667 public abstract void refreshPdbEntries();
669 private int getModelNum(String modelFileName)
671 String[] mfn = getPdbFile();
676 for (int i = 0; i < mfn.length; i++)
678 if (mfn[i].equalsIgnoreCase(modelFileName))
685 * map between index of model filename returned from getPdbFile and the first
686 * index of models from this file in the viewer. Note - this is not trimmed -
687 * use getPdbFile to get number of unique models.
689 private int _modelFileNameMap[];
691 // ////////////////////////////////
692 // /StructureListener
693 public synchronized String[] getPdbFile()
697 return new String[0];
699 if (modelFileNames == null)
702 String mset[] = new String[viewer.getModelCount()];
703 _modelFileNameMap = new int[mset.length];
705 mset[0] = viewer.getModelFileName(0);
706 for (int i = 1; i < mset.length; i++)
708 mset[j] = viewer.getModelFileName(i);
709 _modelFileNameMap[j] = i; // record the model index for the filename
710 // skip any additional models in the same file (NMR structures)
711 if ((mset[j] == null ? mset[j] != mset[j - 1]
712 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
717 modelFileNames = new String[j];
718 System.arraycopy(mset, 0, modelFileNames, 0, j);
720 return modelFileNames;
724 * map from string to applet
726 public Map getRegistryInfo()
728 // TODO Auto-generated method stub
733 * returns the current sequenceRenderer that should be used to colour the
738 public abstract SequenceRenderer getSequenceRenderer();
740 // ///////////////////////////////
741 // JmolStatusListener
743 public void handlePopupMenu(int x, int y)
745 jmolpopup.show(x, y);
749 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
752 if (modelFileNames == null)
757 // look up file model number for this pdbfile
760 // may need to adjust for URLencoding here - we don't worry about that yet.
761 while (mdlNum < modelFileNames.length
762 && !pdbfile.equals(modelFileNames[mdlNum]))
764 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
767 if (mdlNum == modelFileNames.length)
773 // if (!pdbfile.equals(pdbentry.getFile()))
775 if (resetLastRes.length() > 0)
777 viewer.evalStringQuiet(resetLastRes.toString());
781 eval.append("select " + pdbResNum); // +modelNum
783 resetLastRes.setLength(0);
784 resetLastRes.append("select " + pdbResNum); // +modelNum
787 resetLastRes.append(":");
788 if (!chain.equals(" "))
791 resetLastRes.append(chain);
794 eval.append(" /" + (mdlNum + 1));
795 resetLastRes.append("/" + (mdlNum + 1));
797 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
799 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
800 + " and not hetero; spacefill 0;");
802 eval.append("spacefill 200;select none");
804 viewer.evalStringQuiet(eval.toString());
809 boolean debug = true;
811 private void jmolHistory(boolean enable)
813 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
816 public void loadInline(String string)
820 // viewer.loadInline(strModel, isAppend);
822 // construct fake fullPathName and fileName so we can identify the file
824 // Then, construct pass a reader for the string to Jmol.
825 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
826 // fileName, null, reader, false, null, null, 0);
827 viewer.openStringInline(string);
830 public void mouseOverStructure(int atomIndex, String strInfo)
833 int mdlSep = strInfo.indexOf("/");
834 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
836 if (chainSeparator == -1)
838 chainSeparator = strInfo.indexOf(".");
839 if (mdlSep > -1 && mdlSep < chainSeparator)
841 chainSeparator1 = chainSeparator;
842 chainSeparator = mdlSep;
845 pdbResNum = Integer.parseInt(strInfo.substring(
846 strInfo.indexOf("]") + 1, chainSeparator));
850 if (strInfo.indexOf(":") > -1)
851 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
852 strInfo.indexOf("."));
858 String pdbfilename = modelFileNames[frameNo]; // default is first or current
862 if (chainSeparator1 == -1)
864 chainSeparator1 = strInfo.indexOf(".", mdlSep);
866 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
867 chainSeparator1) : strInfo.substring(mdlSep + 1);
870 // recover PDB filename for the model hovered over.
872 .getModelFileName(new Integer(mdlId).intValue() - 1);
873 } catch (Exception e)
878 if (lastMessage == null || !lastMessage.equals(strInfo))
879 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
881 lastMessage = strInfo;
884 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
888 System.err.println("Ignoring additional hover info: " + data
889 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
891 mouseOverStructure(atomIndex, strInfo);
895 * { if (history != null && strStatus != null &&
896 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
900 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
903 * this implements the toggle label behaviour copied from the original
904 * structure viewer, MCView
908 System.err.println("Ignoring additional pick data string " + strData);
910 int chainSeparator = strInfo.indexOf(":");
912 if (chainSeparator == -1)
913 chainSeparator = strInfo.indexOf(".");
915 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
917 String mdlString = "";
918 if ((p = strInfo.indexOf(":")) > -1)
919 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
921 if ((p = strInfo.indexOf("/")) > -1)
923 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
925 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
929 if (!atomsPicked.contains(picked))
931 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
932 atomsPicked.addElement(picked);
936 viewer.evalString("select " + picked + ";label off");
937 atomsPicked.removeElement(picked);
940 // TODO: in application this happens
942 // if (scriptWindow != null)
944 // scriptWindow.sendConsoleMessage(strInfo);
945 // scriptWindow.sendConsoleMessage("\n");
950 public void notifyCallback(int type, Object[] data)
956 case JmolConstants.CALLBACK_LOADSTRUCT:
957 notifyFileLoaded((String) data[1], (String) data[2],
958 (String) data[3], (String) data[4],
959 ((Integer) data[5]).intValue());
962 case JmolConstants.CALLBACK_PICK:
963 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
965 // also highlight in alignment
966 case JmolConstants.CALLBACK_HOVER:
967 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
970 case JmolConstants.CALLBACK_SCRIPT:
971 notifyScriptTermination((String) data[2],
972 ((Integer) data[3]).intValue());
974 case JmolConstants.CALLBACK_ECHO:
975 sendConsoleEcho((String) data[1]);
977 case JmolConstants.CALLBACK_MESSAGE:
978 sendConsoleMessage((data == null) ? ((String) null)
981 case JmolConstants.CALLBACK_ERROR:
982 // System.err.println("Ignoring error callback.");
984 case JmolConstants.CALLBACK_SYNC:
985 case JmolConstants.CALLBACK_RESIZE:
988 case JmolConstants.CALLBACK_MEASURE:
990 case JmolConstants.CALLBACK_CLICK:
992 System.err.println("Unhandled callback " + type + " "
993 + data[1].toString());
996 } catch (Exception e)
998 System.err.println("Squashed Jmol callback handler error:");
1003 public boolean notifyEnabled(int callbackPick)
1005 switch (callbackPick)
1007 case JmolConstants.CALLBACK_ECHO:
1008 case JmolConstants.CALLBACK_LOADSTRUCT:
1009 case JmolConstants.CALLBACK_MEASURE:
1010 case JmolConstants.CALLBACK_MESSAGE:
1011 case JmolConstants.CALLBACK_PICK:
1012 case JmolConstants.CALLBACK_SCRIPT:
1013 case JmolConstants.CALLBACK_HOVER:
1014 case JmolConstants.CALLBACK_ERROR:
1016 case JmolConstants.CALLBACK_RESIZE:
1017 case JmolConstants.CALLBACK_SYNC:
1018 case JmolConstants.CALLBACK_CLICK:
1019 case JmolConstants.CALLBACK_ANIMFRAME:
1020 case JmolConstants.CALLBACK_MINIMIZATION:
1025 // incremented every time a load notification is successfully handled -
1026 // lightweight mechanism for other threads to detect when they can start
1027 // referrring to new structures.
1028 private long loadNotifiesHandled = 0;
1030 public long getLoadNotifiesHandled()
1032 return loadNotifiesHandled;
1035 public void notifyFileLoaded(String fullPathName, String fileName2,
1036 String modelName, String errorMsg, int modelParts)
1038 if (errorMsg != null)
1040 fileLoadingError = errorMsg;
1044 // TODO: deal sensibly with models loaded inLine:
1045 // modelName will be null, as will fullPathName.
1047 // the rest of this routine ignores the arguments, and simply interrogates
1048 // the Jmol view to find out what structures it contains, and adds them to
1049 // the structure selection manager.
1050 fileLoadingError = null;
1051 String[] oldmodels = modelFileNames;
1052 modelFileNames = null;
1053 chainNames = new Vector();
1054 boolean notifyLoaded = false;
1055 String[] modelfilenames = getPdbFile();
1056 ssm = StructureSelectionManager.getStructureSelectionManager();
1057 // first check if we've lost any structures
1058 if (oldmodels != null && oldmodels.length > 0)
1061 for (int i = 0; i < oldmodels.length; i++)
1063 for (int n = 0; n < modelfilenames.length; n++)
1065 if (modelfilenames[n] == oldmodels[i])
1067 oldmodels[i] = null;
1071 if (oldmodels[i] != null)
1078 String[] oldmfn = new String[oldm];
1080 for (int i = 0; i < oldmodels.length; i++)
1082 if (oldmodels[i] != null)
1084 oldmfn[oldm++] = oldmodels[i];
1087 // deregister the Jmol instance for these structures - we'll add
1088 // ourselves again at the end for the current structure set.
1089 ssm.removeStructureViewerListener(this, oldmfn);
1092 refreshPdbEntries();
1093 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1095 String fileName = modelfilenames[modelnum];
1096 boolean foundEntry = false;
1097 MCview.PDBfile pdb = null;
1098 String pdbfile = null, pdbfhash = null;
1099 // model was probably loaded inline - so check the pdb file hashcode
1102 // calculate essential attributes for the pdb data imported inline.
1103 // prolly need to resolve modelnumber properly - for now just use our
1105 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1107 pdbfhash = "" + pdbfile.hashCode();
1109 if (pdbentry != null)
1111 // search pdbentries and sequences to find correct pdbentry for this
1113 for (int pe = 0; pe < pdbentry.length; pe++)
1115 boolean matches = false;
1116 if (fileName == null)
1119 // see JAL-623 - need method of matching pasted data up
1121 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
1122 AppletFormatAdapter.PASTE);
1123 pdbentry[modelnum].setFile("INLINE" + pdb.id);
1130 if (matches = pdbentry[pe].getFile().equals(fileName))
1133 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1136 // to be tested. See mantis bug
1137 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1138 String protocol = AppletFormatAdapter.URL;
1141 File fl = new java.io.File(pdbentry[pe].getFile());
1144 protocol = AppletFormatAdapter.FILE;
1146 } catch (Exception e)
1152 pdb = ssm.setMapping(sequence[pe], chains[pe],
1153 pdbentry[pe].getFile(), protocol);
1159 pdbentry[pe].setId(pdb.id);
1160 // add an entry for every chain in the model
1161 for (int i = 0; i < pdb.chains.size(); i++)
1163 chainNames.addElement(new String(pdb.id + ":"
1164 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id));
1166 notifyLoaded = true;
1170 if (!foundEntry && associateNewStructs)
1172 // this is a foreign pdb file that jalview doesn't know about - add
1173 // it to the dataset and try to find a home - either on a matching
1174 // sequence or as a new sequence.
1175 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1177 // parse pdb file into a chain, etc.
1178 // locate best match for pdb in associated views and add mapping to
1180 // if properly registered then
1181 notifyLoaded = true;
1186 // so finally, update the jmol bits and pieces
1187 if (jmolpopup != null)
1189 // potential for deadlock here:
1190 // jmolpopup.updateComputedMenus();
1192 if (!isLoadingFromArchive())
1194 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1196 setLoadingFromArchive(false);
1197 // register ourselves as a listener and notify the gui that it needs to
1199 ssm.addStructureViewerListener(this);
1202 FeatureRenderer fr = getFeatureRenderer();
1208 loadNotifiesHandled++;
1212 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1214 notifyAtomPicked(iatom, strMeasure, null);
1217 public abstract void notifyScriptTermination(String strStatus,
1221 * display a message echoed from the jmol viewer
1225 public abstract void sendConsoleEcho(String strEcho); /*
1226 * { showConsole(true);
1228 * history.append("\n" +
1232 // /End JmolStatusListener
1233 // /////////////////////////////
1237 * status message - usually the response received after a script
1240 public abstract void sendConsoleMessage(String strStatus);
1242 public void setCallbackFunction(String callbackType,
1243 String callbackFunction)
1245 System.err.println("Ignoring set-callback request to associate "
1246 + callbackType + " with function " + callbackFunction);
1250 public void setJalviewColourScheme(ColourSchemeI cs)
1252 colourBySequence = false;
1261 // TODO: Switch between nucleotide or aa selection expressions
1262 Enumeration en = ResidueProperties.aa3Hash.keys();
1263 StringBuffer command = new StringBuffer("select *;color white;");
1264 while (en.hasMoreElements())
1266 res = en.nextElement().toString();
1267 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
1271 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
1273 command.append("select " + res + ";color[" + col.getRed() + ","
1274 + col.getGreen() + "," + col.getBlue() + "];");
1277 evalStateCommand(command.toString());
1281 public void showHelp()
1283 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1287 * open the URL somehow
1291 public abstract void showUrl(String url, String target);
1294 * called when the binding thinks the UI needs to be refreshed after a Jmol
1295 * state change. this could be because structures were loaded, or because an
1296 * error has occured.
1298 public abstract void refreshGUI();
1301 * called to show or hide the associated console window container.
1305 public abstract void showConsole(boolean show);
1308 * @param renderPanel
1310 * - when true will initialise jmol's file IO system (should be false
1311 * in applet context)
1313 * @param documentBase
1315 * @param commandOptions
1317 public void allocateViewer(Component renderPanel, boolean jmolfileio,
1318 String htmlName, URL documentBase, URL codeBase,
1319 String commandOptions)
1321 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1322 codeBase, commandOptions, null, null);
1327 * @param renderPanel
1329 * - when true will initialise jmol's file IO system (should be false
1330 * in applet context)
1332 * @param documentBase
1334 * @param commandOptions
1335 * @param consolePanel
1336 * - panel to contain Jmol console
1337 * @param buttonsToShow
1338 * - buttons to show on the console, in ordr
1340 public void allocateViewer(Component renderPanel, boolean jmolfileio,
1341 String htmlName, URL documentBase, URL codeBase,
1342 String commandOptions, final Container consolePanel,
1343 String buttonsToShow)
1345 viewer = JmolViewer.allocateViewer(renderPanel,
1346 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1347 + ((Object) this).toString(), documentBase, codeBase,
1348 commandOptions, this);
1350 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
1351 if (console != null)
1353 viewer.setConsole(new JmolAppConsoleInterface()
1357 public JmolScriptEditorInterface getScriptEditor()
1359 return console.getScriptEditor();
1363 public JmolAppConsoleInterface getAppConsole(Viewer viewer,
1369 public String getText()
1371 return console.getText();
1375 public Object getMyMenuBar()
1377 return console.getMyMenuBar();
1381 public void setVisible(boolean b)
1387 public void sendConsoleEcho(String strEcho)
1389 console.sendConsoleEcho(strEcho);
1394 public void sendConsoleMessage(String strInfo)
1396 console.sendConsoleMessage(strInfo);
1406 public void dispose()
1416 protected abstract JmolAppConsoleInterface createJmolConsole(
1417 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
1419 protected org.jmol.api.JmolAppConsoleInterface console = null;
1421 public void setLoadingFromArchive(boolean loadingFromArchive)
1423 this.loadingFromArchive = loadingFromArchive;
1426 public boolean isLoadingFromArchive()
1428 return loadingFromArchive;
1431 public void setBackgroundColour(java.awt.Color col)
1434 viewer.evalStringQuiet("background [" + col.getRed() + ","
1435 + col.getGreen() + "," + col.getBlue() + "];");
1440 * add structures and any known sequence associations
1442 * @returns the pdb entries added to the current set.
1444 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
1445 SequenceI[][] seq, String[][] chns)
1448 Vector v = new Vector();
1449 Vector rtn = new Vector();
1450 for (int i = 0; i < pdbentry.length; i++)
1452 v.addElement(pdbentry[i]);
1454 for (int i = 0; i < pdbe.length; i++)
1456 int r = v.indexOf(pdbe[i]);
1457 if (r == -1 || r >= pdbentry.length)
1459 rtn.addElement(new int[]
1461 v.addElement(pdbe[i]);
1465 // just make sure the sequence/chain entries are all up to date
1466 addSequenceAndChain(r, seq[i], chns[i]);
1469 pdbe = new PDBEntry[v.size()];
1474 // expand the tied seuqence[] and string[] arrays
1475 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
1476 String[][] sch = new String[pdbentry.length][];
1477 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
1478 System.arraycopy(chains, 0, sch, 0, this.chains.length);
1481 pdbe = new PDBEntry[rtn.size()];
1482 for (int r = 0; r < pdbe.length; r++)
1484 int[] stri = ((int[]) rtn.elementAt(r));
1485 // record the pdb file as a new addition
1486 pdbe[r] = pdbentry[stri[0]];
1487 // and add the new sequence/chain entries
1488 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
1498 public void addSequence(int pe, SequenceI[] seq)
1500 // add sequences to the pe'th pdbentry's seuqence set.
1501 addSequenceAndChain(pe, seq, null);
1504 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
1506 if (pe < 0 || pe >= pdbentry.length)
1509 "Implementation error - no corresponding pdbentry (for index "
1510 + pe + ") to add sequences mappings to");
1512 final String nullChain = "TheNullChain";
1513 Vector s = new Vector();
1514 Vector c = new Vector();
1517 chains = new String[pdbentry.length][];
1519 if (sequence[pe] != null)
1521 for (int i = 0; i < sequence[pe].length; i++)
1523 s.addElement(sequence[pe][i]);
1524 if (chains[pe] != null)
1526 if (i < chains[pe].length)
1528 c.addElement(chains[pe][i]);
1532 c.addElement(nullChain);
1537 if (tchain != null && tchain.length > 0)
1539 c.addElement(nullChain);
1544 for (int i = 0; i < seq.length; i++)
1546 if (!s.contains(seq[i]))
1548 s.addElement(seq[i]);
1549 if (tchain != null && i < tchain.length)
1551 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
1555 SequenceI[] tmp = new SequenceI[s.size()];
1560 String[] tch = new String[c.size()];
1562 for (int i = 0; i < tch.length; i++)
1564 if (tch[i] == nullChain)