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, ComponentListener
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;
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 // TODO: lookup each pdb id and recover proper model number for it.
215 cmd.append(":" + lbl.substring(mlength + 1) + " /"
216 + (1+getModelNum((String)chainFile.get(lbl))) + " or ");
218 if (cmd.length() > 0)
219 cmd.setLength(cmd.length() - 4);
220 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
223 public void closeViewer()
225 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
226 // remove listeners for all structures in viewer
227 StructureSelectionManager.getStructureSelectionManager()
228 .removeStructureViewerListener(this, this.getPdbFile());
229 // and shut down jmol
230 viewer.evalStringQuiet("zap");
231 viewer.setJmolStatusListener(null);
236 public void colourByChain()
238 colourBySequence = false;
239 // TODO: colour by chain should colour each chain distinctly across all
241 // TODO: http://issues.jalview.org/browse/JAL-628
242 evalStateCommand("select *;color chain");
245 public void colourByCharge()
247 colourBySequence = false;
248 evalStateCommand("select *;color white;select ASP,GLU;color red;"
249 + "select LYS,ARG;color blue;select CYS;color yellow");
253 * superpose the structures associated with sequences in the alignment
254 * according to their corresponding positions.
256 public void superposeStructures(AlignmentI alignment)
258 superposeStructures(alignment, -1, null);
262 * superpose the structures associated with sequences in the alignment
263 * according to their corresponding positions. ded)
265 * @param refStructure
266 * - select which pdb file to use as reference (default is -1 - the
267 * first structure in the alignment)
269 public void superposeStructures(AlignmentI alignment, int refStructure)
271 superposeStructures(alignment, refStructure, null);
275 * superpose the structures associated with sequences in the alignment
276 * according to their corresponding positions. ded)
278 * @param refStructure
279 * - select which pdb file to use as reference (default is -1 - the
280 * first structure in the alignment)
284 public void superposeStructures(AlignmentI alignment, int refStructure,
285 ColumnSelection hiddenCols)
287 String[] files = getPdbFile();
288 if (refStructure >= files.length)
290 System.err.println("Invalid reference structure value "
294 if (refStructure < -1)
298 StringBuffer command = new StringBuffer(), selectioncom = new StringBuffer();
300 boolean matched[] = new boolean[alignment.getWidth()];
301 for (int m = 0; m < matched.length; m++)
304 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
307 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
308 String isel[] = new String[files.length];
309 // reference structure - all others are superposed in it
310 String[] targetC = new String[files.length];
311 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
313 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
315 if (mapping == null || mapping.length < 1)
319 for (int s = 0; s < sequence[pdbfnum].length; s++)
321 for (int sp, m = 0; m < mapping.length; m++)
323 if (mapping[m].getSequence() == sequence[pdbfnum][s]
324 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
326 if (refStructure == -1)
328 refStructure = pdbfnum;
330 SequenceI asp = alignment.getSequenceAt(sp);
331 for (int r = 0; r < matched.length; r++)
337 matched[r] = false; // assume this is not a good site
338 if (r >= asp.getLength())
343 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
345 // no mapping to gaps in sequence
348 int t = asp.findPosition(r); // sequence position
349 int apos = mapping[m].getAtomNum(t);
350 int pos = mapping[m].getPDBResNum(t);
352 if (pos < 1 || pos == lastPos)
354 // can't align unmapped sequence
357 matched[r] = true; // this is a good ite
359 // just record this residue position
360 commonrpositions[pdbfnum][r] = pos;
362 // create model selection suffix
363 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
364 if (mapping[m].getChain() == null
365 || mapping[m].getChain().trim().length() == 0)
367 targetC[pdbfnum] = "";
371 targetC[pdbfnum] = ":" + mapping[m].getChain();
373 // move on to next pdb file
374 s = sequence[pdbfnum].length;
380 String[] selcom = new String[files.length];
382 // generate select statements to select regions to superimpose structures
384 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
386 String chainCd = targetC[pdbfnum];
389 StringBuffer molsel = new StringBuffer();
391 for (int r = 0; r < matched.length; r++)
399 if (lpos != commonrpositions[pdbfnum][r] - 1)
405 molsel.append(chainCd);
406 // molsel.append("} {");
412 // continuous run - and lpos >-1
415 // at the beginning, so add dash
421 lpos = commonrpositions[pdbfnum][r];
422 // molsel.append(lpos);
425 // add final selection phrase
429 molsel.append(chainCd);
432 selcom[pdbfnum] = molsel.toString();
433 selectioncom.append("((");
434 selectioncom.append(selcom[pdbfnum].substring(1,
435 selcom[pdbfnum].length() - 1));
436 selectioncom.append(" )& ");
437 selectioncom.append(pdbfnum + 1);
438 selectioncom.append(".1)");
439 if (pdbfnum < files.length - 1)
441 selectioncom.append("|");
445 // TODO: consider bailing if nmatched less than 4 because superposition not
447 // TODO: refactor superposable position search (above) from jmol selection
448 // construction (below)
449 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
451 if (pdbfnum == refStructure)
455 command.append("compare ");
457 command.append(1 + pdbfnum);
458 command.append(".1} {");
459 command.append(1 + refStructure);
460 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
462 // form the matched pair strings
464 for (int s = 0; s < 2; s++)
466 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
468 command.append(" ROTATE TRANSLATE;\n");
470 System.out.println("Select regions:\n" + selectioncom.toString());
471 evalStateCommand("select *; cartoons off; backbone; select ("
472 + selectioncom.toString() + "); cartoons; ");
473 // selcom.append("; ribbons; ");
474 System.out.println("Superimpose command(s):\n" + command.toString());
476 evalStateCommand(command.toString());
478 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
481 public void evalStateCommand(String command)
484 if (lastCommand == null || !lastCommand.equals(command))
486 viewer.evalStringQuiet(command + "\n");
489 lastCommand = command;
493 * colour any structures associated with sequences in the given alignment
494 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
495 * if colourBySequence is enabled.
497 public void colourBySequence(boolean showFeatures, AlignmentI alignment)
499 if (!colourBySequence)
505 String[] files = getPdbFile();
506 SequenceRenderer sr = getSequenceRenderer();
508 FeatureRenderer fr = null;
511 fr = getFeatureRenderer();
514 StringBuffer command = new StringBuffer();
516 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
518 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
520 if (mapping == null || mapping.length < 1)
524 for (int s = 0; s < sequence[pdbfnum].length; s++)
526 for (int sp, m = 0; m < mapping.length; m++)
528 if (mapping[m].getSequence() == sequence[pdbfnum][s]
529 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
531 SequenceI asp = alignment.getSequenceAt(sp);
532 for (int r = 0; r < asp.getLength(); r++)
534 // no mapping to gaps in sequence
535 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
539 int pos = mapping[m].getPDBResNum(asp.findPosition(r));
541 if (pos < 1 || pos == lastPos)
546 Color col = sr.getResidueBoxColour(sequence[pdbfnum][s], r);
548 if (showFeatures && fr!=null)
549 col = fr.findFeatureColour(col, sequence[pdbfnum][s], r);
550 String newSelcom = (mapping[m].getChain() != " " ? ":"
551 + mapping[m].getChain() : "")
560 + col.getBlue() + "]";
561 if (command.toString().endsWith(newSelcom))
563 command = condenseCommand(command.toString(), pos);
566 // TODO: deal with case when buffer is too large for Jmol to parse
567 // - execute command and flush
569 command.append(";select " + pos);
570 command.append(newSelcom);
577 evalStateCommand(command.toString());
580 public boolean isColourBySequence()
582 return colourBySequence;
585 public void setColourBySequence(boolean colourBySequence)
587 this.colourBySequence = colourBySequence;
590 StringBuffer condenseCommand(String command, int pos)
593 StringBuffer sb = new StringBuffer(command.substring(0,
594 command.lastIndexOf("select") + 7));
596 command = command.substring(sb.length());
600 if (command.indexOf("-") > -1)
602 start = command.substring(0, command.indexOf("-"));
606 start = command.substring(0, command.indexOf(":"));
609 sb.append(start + "-" + pos + command.substring(command.indexOf(":")));
614 public void createImage(String file, String type, int quality)
616 System.out.println("JMOL CREATE IMAGE");
619 public String createImage(String fileName, String type,
620 Object textOrBytes, int quality)
622 System.out.println("JMOL CREATE IMAGE");
626 public String eval(String strEval)
628 // System.out.println(strEval);
629 // "# 'eval' is implemented only for the applet.";
633 // End StructureListener
634 // //////////////////////////
636 public float[][] functionXY(String functionName, int x, int y)
641 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
643 // TODO Auto-generated method stub
647 public Color getColour(int atomIndex, int pdbResNum, String chain,
650 if (getModelNum(pdbfile) < 0)
652 // TODO: verify atomIndex is selecting correct model.
653 return new Color(viewer.getAtomArgb(atomIndex));
657 * returns the current featureRenderer that should be used to colour the
662 public abstract FeatureRenderer getFeatureRenderer();
665 * instruct the Jalview binding to update the pdbentries vector if necessary
666 * prior to matching the jmol view's contents to the list of structure files
667 * Jalview knows about.
669 public abstract void refreshPdbEntries();
671 private int getModelNum(String modelFileName)
673 String[] mfn = getPdbFile();
678 for (int i = 0; i < mfn.length; i++)
680 if (mfn[i].equalsIgnoreCase(modelFileName))
687 * map between index of model filename returned from getPdbFile and the first
688 * index of models from this file in the viewer. Note - this is not trimmed -
689 * use getPdbFile to get number of unique models.
691 private int _modelFileNameMap[];
693 // ////////////////////////////////
694 // /StructureListener
695 public synchronized String[] getPdbFile()
699 return new String[0];
701 if (modelFileNames == null)
704 String mset[] = new String[viewer.getModelCount()];
705 _modelFileNameMap = new int[mset.length];
707 mset[0] = viewer.getModelFileName(0);
708 for (int i = 1; i < mset.length; i++)
710 mset[j] = viewer.getModelFileName(i);
711 _modelFileNameMap[j] = i; // record the model index for the filename
712 // skip any additional models in the same file (NMR structures)
713 if ((mset[j] == null ? mset[j] != mset[j - 1]
714 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
719 modelFileNames = new String[j];
720 System.arraycopy(mset, 0, modelFileNames, 0, j);
722 return modelFileNames;
726 * map from string to applet
728 public Map getRegistryInfo()
730 // TODO Auto-generated method stub
735 * returns the current sequenceRenderer that should be used to colour the
740 public abstract SequenceRenderer getSequenceRenderer();
742 // ///////////////////////////////
743 // JmolStatusListener
745 public void handlePopupMenu(int x, int y)
747 jmolpopup.show(x, y);
751 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
754 if (modelFileNames == null)
759 // look up file model number for this pdbfile
762 // may need to adjust for URLencoding here - we don't worry about that yet.
763 while (mdlNum < modelFileNames.length
764 && !pdbfile.equals(modelFileNames[mdlNum]))
766 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
769 if (mdlNum == modelFileNames.length)
775 // if (!pdbfile.equals(pdbentry.getFile()))
777 if (resetLastRes.length() > 0)
779 viewer.evalStringQuiet(resetLastRes.toString());
783 eval.append("select " + pdbResNum); // +modelNum
785 resetLastRes.setLength(0);
786 resetLastRes.append("select " + pdbResNum); // +modelNum
789 resetLastRes.append(":");
790 if (!chain.equals(" "))
793 resetLastRes.append(chain);
796 eval.append(" /" + (mdlNum + 1));
797 resetLastRes.append("/" + (mdlNum + 1));
799 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
801 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
802 + " and not hetero; spacefill 0;");
804 eval.append("spacefill 200;select none");
806 viewer.evalStringQuiet(eval.toString());
811 boolean debug = true;
813 private void jmolHistory(boolean enable)
815 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
818 public void loadInline(String string)
822 // viewer.loadInline(strModel, isAppend);
824 // construct fake fullPathName and fileName so we can identify the file
826 // Then, construct pass a reader for the string to Jmol.
827 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
828 // fileName, null, reader, false, null, null, 0);
829 viewer.openStringInline(string);
832 public void mouseOverStructure(int atomIndex, String strInfo)
835 int mdlSep = strInfo.indexOf("/");
836 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
838 if (chainSeparator == -1)
840 chainSeparator = strInfo.indexOf(".");
841 if (mdlSep > -1 && mdlSep < chainSeparator)
843 chainSeparator1 = chainSeparator;
844 chainSeparator = mdlSep;
847 pdbResNum = Integer.parseInt(strInfo.substring(
848 strInfo.indexOf("]") + 1, chainSeparator));
852 if (strInfo.indexOf(":") > -1)
853 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
854 strInfo.indexOf("."));
860 String pdbfilename = modelFileNames[frameNo]; // default is first or current
864 if (chainSeparator1 == -1)
866 chainSeparator1 = strInfo.indexOf(".", mdlSep);
868 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
869 chainSeparator1) : strInfo.substring(mdlSep + 1);
872 // recover PDB filename for the model hovered over.
874 .getModelFileName(new Integer(mdlId).intValue() - 1);
875 } catch (Exception e)
880 if (lastMessage == null || !lastMessage.equals(strInfo))
881 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
883 lastMessage = strInfo;
886 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
890 System.err.println("Ignoring additional hover info: " + data
891 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
893 mouseOverStructure(atomIndex, strInfo);
897 * { if (history != null && strStatus != null &&
898 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
902 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
905 * this implements the toggle label behaviour copied from the original
906 * structure viewer, MCView
910 System.err.println("Ignoring additional pick data string " + strData);
912 int chainSeparator = strInfo.indexOf(":");
914 if (chainSeparator == -1)
915 chainSeparator = strInfo.indexOf(".");
917 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
919 String mdlString = "";
920 if ((p = strInfo.indexOf(":")) > -1)
921 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
923 if ((p = strInfo.indexOf("/")) > -1)
925 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
927 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
931 if (!atomsPicked.contains(picked))
933 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
934 atomsPicked.addElement(picked);
938 viewer.evalString("select " + picked + ";label off");
939 atomsPicked.removeElement(picked);
942 // TODO: in application this happens
944 // if (scriptWindow != null)
946 // scriptWindow.sendConsoleMessage(strInfo);
947 // scriptWindow.sendConsoleMessage("\n");
952 public void notifyCallback(int type, Object[] data)
958 case JmolConstants.CALLBACK_LOADSTRUCT:
959 notifyFileLoaded((String) data[1], (String) data[2],
960 (String) data[3], (String) data[4],
961 ((Integer) data[5]).intValue());
964 case JmolConstants.CALLBACK_PICK:
965 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
967 // also highlight in alignment
968 case JmolConstants.CALLBACK_HOVER:
969 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
972 case JmolConstants.CALLBACK_SCRIPT:
973 notifyScriptTermination((String) data[2],
974 ((Integer) data[3]).intValue());
976 case JmolConstants.CALLBACK_ECHO:
977 sendConsoleEcho((String) data[1]);
979 case JmolConstants.CALLBACK_MESSAGE:
980 sendConsoleMessage((data == null) ? ((String) null)
983 case JmolConstants.CALLBACK_ERROR:
984 // System.err.println("Ignoring error callback.");
986 case JmolConstants.CALLBACK_SYNC:
987 case JmolConstants.CALLBACK_RESIZE:
990 case JmolConstants.CALLBACK_MEASURE:
992 case JmolConstants.CALLBACK_CLICK:
994 System.err.println("Unhandled callback " + type + " "
995 + data[1].toString());
998 } catch (Exception e)
1000 System.err.println("Squashed Jmol callback handler error:");
1001 e.printStackTrace();
1005 public boolean notifyEnabled(int callbackPick)
1007 switch (callbackPick)
1009 case JmolConstants.CALLBACK_ECHO:
1010 case JmolConstants.CALLBACK_LOADSTRUCT:
1011 case JmolConstants.CALLBACK_MEASURE:
1012 case JmolConstants.CALLBACK_MESSAGE:
1013 case JmolConstants.CALLBACK_PICK:
1014 case JmolConstants.CALLBACK_SCRIPT:
1015 case JmolConstants.CALLBACK_HOVER:
1016 case JmolConstants.CALLBACK_ERROR:
1018 case JmolConstants.CALLBACK_RESIZE:
1019 case JmolConstants.CALLBACK_SYNC:
1020 case JmolConstants.CALLBACK_CLICK:
1021 case JmolConstants.CALLBACK_ANIMFRAME:
1022 case JmolConstants.CALLBACK_MINIMIZATION:
1027 // incremented every time a load notification is successfully handled -
1028 // lightweight mechanism for other threads to detect when they can start
1029 // referrring to new structures.
1030 private long loadNotifiesHandled = 0;
1032 public long getLoadNotifiesHandled()
1034 return loadNotifiesHandled;
1037 public void notifyFileLoaded(String fullPathName, String fileName2,
1038 String modelName, String errorMsg, int modelParts)
1040 if (errorMsg != null)
1042 fileLoadingError = errorMsg;
1046 // TODO: deal sensibly with models loaded inLine:
1047 // modelName will be null, as will fullPathName.
1049 // the rest of this routine ignores the arguments, and simply interrogates
1050 // the Jmol view to find out what structures it contains, and adds them to
1051 // the structure selection manager.
1052 fileLoadingError = null;
1053 String[] oldmodels = modelFileNames;
1054 modelFileNames = null;
1055 chainNames = new Vector();
1056 chainFile = new Hashtable();
1057 boolean notifyLoaded = false;
1058 String[] modelfilenames = getPdbFile();
1059 ssm = StructureSelectionManager.getStructureSelectionManager();
1060 // first check if we've lost any structures
1061 if (oldmodels != null && oldmodels.length > 0)
1064 for (int i = 0; i < oldmodels.length; i++)
1066 for (int n = 0; n < modelfilenames.length; n++)
1068 if (modelfilenames[n] == oldmodels[i])
1070 oldmodels[i] = null;
1074 if (oldmodels[i] != null)
1081 String[] oldmfn = new String[oldm];
1083 for (int i = 0; i < oldmodels.length; i++)
1085 if (oldmodels[i] != null)
1087 oldmfn[oldm++] = oldmodels[i];
1090 // deregister the Jmol instance for these structures - we'll add
1091 // ourselves again at the end for the current structure set.
1092 ssm.removeStructureViewerListener(this, oldmfn);
1095 refreshPdbEntries();
1096 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1098 String fileName = modelfilenames[modelnum];
1099 boolean foundEntry = false;
1100 MCview.PDBfile pdb = null;
1101 String pdbfile = null, pdbfhash = null;
1102 // model was probably loaded inline - so check the pdb file hashcode
1105 // calculate essential attributes for the pdb data imported inline.
1106 // prolly need to resolve modelnumber properly - for now just use our
1108 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1110 pdbfhash = "" + pdbfile.hashCode();
1112 if (pdbentry != null)
1114 // search pdbentries and sequences to find correct pdbentry for this
1116 for (int pe = 0; pe < pdbentry.length; pe++)
1118 boolean matches = false;
1119 if (fileName == null)
1122 // see JAL-623 - need method of matching pasted data up
1124 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
1125 AppletFormatAdapter.PASTE);
1126 pdbentry[modelnum].setFile("INLINE" + pdb.id);
1133 if (matches = pdbentry[pe].getFile().equals(fileName))
1136 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1139 // to be tested. See mantis bug
1140 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1141 String protocol = AppletFormatAdapter.URL;
1144 File fl = new java.io.File(pdbentry[pe].getFile());
1147 protocol = AppletFormatAdapter.FILE;
1149 } catch (Exception e)
1155 pdb = ssm.setMapping(sequence[pe], chains[pe],
1156 pdbentry[pe].getFile(), protocol);
1162 pdbentry[pe].setId(pdb.id);
1163 // add an entry for every chain in the model
1164 for (int i = 0; i < pdb.chains.size(); i++)
1166 String chid = new String(pdb.id + ":"
1167 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
1168 chainFile.put(chid, pdbentry[pe].getFile());
1169 chainNames.addElement(chid);
1171 notifyLoaded = true;
1175 if (!foundEntry && associateNewStructs)
1177 // this is a foreign pdb file that jalview doesn't know about - add
1178 // it to the dataset and try to find a home - either on a matching
1179 // sequence or as a new sequence.
1180 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1182 // parse pdb file into a chain, etc.
1183 // locate best match for pdb in associated views and add mapping to
1185 // if properly registered then
1186 notifyLoaded = true;
1191 // so finally, update the jmol bits and pieces
1192 if (jmolpopup != null)
1194 // potential for deadlock here:
1195 // jmolpopup.updateComputedMenus();
1197 if (!isLoadingFromArchive())
1199 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1201 setLoadingFromArchive(false);
1202 // register ourselves as a listener and notify the gui that it needs to
1204 ssm.addStructureViewerListener(this);
1207 FeatureRenderer fr = getFeatureRenderer();
1213 loadNotifiesHandled++;
1217 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1219 notifyAtomPicked(iatom, strMeasure, null);
1222 public abstract void notifyScriptTermination(String strStatus,
1226 * display a message echoed from the jmol viewer
1230 public abstract void sendConsoleEcho(String strEcho); /*
1231 * { showConsole(true);
1233 * history.append("\n" +
1237 // /End JmolStatusListener
1238 // /////////////////////////////
1242 * status message - usually the response received after a script
1245 public abstract void sendConsoleMessage(String strStatus);
1247 public void setCallbackFunction(String callbackType,
1248 String callbackFunction)
1250 System.err.println("Ignoring set-callback request to associate "
1251 + callbackType + " with function " + callbackFunction);
1255 public void setJalviewColourScheme(ColourSchemeI cs)
1257 colourBySequence = false;
1266 // TODO: Switch between nucleotide or aa selection expressions
1267 Enumeration en = ResidueProperties.aa3Hash.keys();
1268 StringBuffer command = new StringBuffer("select *;color white;");
1269 while (en.hasMoreElements())
1271 res = en.nextElement().toString();
1272 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
1276 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
1278 command.append("select " + res + ";color[" + col.getRed() + ","
1279 + col.getGreen() + "," + col.getBlue() + "];");
1282 evalStateCommand(command.toString());
1286 public void showHelp()
1288 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1292 * open the URL somehow
1296 public abstract void showUrl(String url, String target);
1299 * called when the binding thinks the UI needs to be refreshed after a Jmol
1300 * state change. this could be because structures were loaded, or because an
1301 * error has occured.
1303 public abstract void refreshGUI();
1306 * called to show or hide the associated console window container.
1310 public abstract void showConsole(boolean show);
1313 * @param renderPanel
1315 * - when true will initialise jmol's file IO system (should be false
1316 * in applet context)
1318 * @param documentBase
1320 * @param commandOptions
1322 public void allocateViewer(Component renderPanel, boolean jmolfileio,
1323 String htmlName, URL documentBase, URL codeBase,
1324 String commandOptions)
1326 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1327 codeBase, commandOptions, null, null);
1332 * @param renderPanel
1334 * - when true will initialise jmol's file IO system (should be false
1335 * in applet context)
1337 * @param documentBase
1339 * @param commandOptions
1340 * @param consolePanel
1341 * - panel to contain Jmol console
1342 * @param buttonsToShow
1343 * - buttons to show on the console, in ordr
1345 public void allocateViewer(Component renderPanel, boolean jmolfileio,
1346 String htmlName, URL documentBase, URL codeBase,
1347 String commandOptions, final Container consolePanel,
1348 String buttonsToShow)
1350 viewer = JmolViewer.allocateViewer(renderPanel,
1351 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1352 + ((Object) this).toString(), documentBase, codeBase,
1353 commandOptions, this);
1355 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
1356 if (consolePanel != null)
1358 consolePanel.addComponentListener(this);
1365 protected abstract JmolAppConsoleInterface createJmolConsole(
1366 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
1368 protected org.jmol.api.JmolAppConsoleInterface console = null;
1371 public void componentResized(ComponentEvent e)
1377 public void componentMoved(ComponentEvent e)
1383 public void componentShown(ComponentEvent e)
1389 public void componentHidden(ComponentEvent e)
1395 public void setLoadingFromArchive(boolean loadingFromArchive)
1397 this.loadingFromArchive = loadingFromArchive;
1400 public boolean isLoadingFromArchive()
1402 return loadingFromArchive;
1405 public void setBackgroundColour(java.awt.Color col)
1408 viewer.evalStringQuiet("background [" + col.getRed() + ","
1409 + col.getGreen() + "," + col.getBlue() + "];");
1414 * add structures and any known sequence associations
1416 * @returns the pdb entries added to the current set.
1418 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
1419 SequenceI[][] seq, String[][] chns)
1422 Vector v = new Vector();
1423 Vector rtn = new Vector();
1424 for (int i = 0; i < pdbentry.length; i++)
1426 v.addElement(pdbentry[i]);
1428 for (int i = 0; i < pdbe.length; i++)
1430 int r = v.indexOf(pdbe[i]);
1431 if (r == -1 || r >= pdbentry.length)
1433 rtn.addElement(new int[]
1435 v.addElement(pdbe[i]);
1439 // just make sure the sequence/chain entries are all up to date
1440 addSequenceAndChain(r, seq[i], chns[i]);
1443 pdbe = new PDBEntry[v.size()];
1448 // expand the tied seuqence[] and string[] arrays
1449 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
1450 String[][] sch = new String[pdbentry.length][];
1451 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
1452 System.arraycopy(chains, 0, sch, 0, this.chains.length);
1455 pdbe = new PDBEntry[rtn.size()];
1456 for (int r = 0; r < pdbe.length; r++)
1458 int[] stri = ((int[]) rtn.elementAt(r));
1459 // record the pdb file as a new addition
1460 pdbe[r] = pdbentry[stri[0]];
1461 // and add the new sequence/chain entries
1462 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
1472 public void addSequence(int pe, SequenceI[] seq)
1474 // add sequences to the pe'th pdbentry's seuqence set.
1475 addSequenceAndChain(pe, seq, null);
1478 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
1480 if (pe < 0 || pe >= pdbentry.length)
1483 "Implementation error - no corresponding pdbentry (for index "
1484 + pe + ") to add sequences mappings to");
1486 final String nullChain = "TheNullChain";
1487 Vector s = new Vector();
1488 Vector c = new Vector();
1491 chains = new String[pdbentry.length][];
1493 if (sequence[pe] != null)
1495 for (int i = 0; i < sequence[pe].length; i++)
1497 s.addElement(sequence[pe][i]);
1498 if (chains[pe] != null)
1500 if (i < chains[pe].length)
1502 c.addElement(chains[pe][i]);
1506 c.addElement(nullChain);
1511 if (tchain != null && tchain.length > 0)
1513 c.addElement(nullChain);
1518 for (int i = 0; i < seq.length; i++)
1520 if (!s.contains(seq[i]))
1522 s.addElement(seq[i]);
1523 if (tchain != null && i < tchain.length)
1525 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
1529 SequenceI[] tmp = new SequenceI[s.size()];
1534 String[] tch = new String[c.size()];
1536 for (int i = 0; i < tch.length; i++)
1538 if (tch[i] == nullChain)