2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
3 * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
18 package jalview.ext.jmol;
23 import java.applet.Applet;
25 import java.awt.event.*;
27 import javax.swing.JPanel;
29 import jalview.api.FeatureRenderer;
30 import jalview.api.SequenceRenderer;
31 import jalview.api.SequenceStructureBinding;
32 import jalview.datamodel.*;
33 import jalview.structure.*;
36 import org.jmol.api.*;
37 import org.jmol.adapter.smarter.SmarterJmolAdapter;
39 import org.jmol.popup.*;
40 import org.jmol.viewer.JmolConstants;
41 import org.jmol.viewer.Viewer;
43 import jalview.schemes.*;
45 public abstract class JalviewJmolBinding implements StructureListener,
46 JmolStatusListener, SequenceStructureBinding,
47 JmolSelectionListener, ComponentListener
51 * set if Jmol state is being restored from some source - instructs binding
52 * not to apply default display style when structure set is updated for first
55 private boolean loadingFromArchive = false;
58 * state flag used to check if the Jmol viewer's paint method can be called
60 private boolean finishedInit = false;
62 public boolean isFinishedInit()
67 public void setFinishedInit(boolean finishedInit)
69 this.finishedInit = finishedInit;
72 boolean allChainsSelected = false;
75 * when true, try to search the associated datamodel for sequences that are
76 * associated with any unknown structures in the Jmol view.
78 private boolean associateNewStructs = false;
80 Vector atomsPicked = new Vector();
82 public Vector chainNames;
87 * array of target chains for seuqences - tied to pdbentry and sequence[]
89 protected String[][] chains;
91 boolean colourBySequence = true;
93 StringBuffer eval = new StringBuffer();
95 public String fileLoadingError;
98 * the default or current model displayed if the model cannot be identified
99 * from the selection message
103 protected JmolPopup jmolpopup;
109 boolean loadedInline;
112 * current set of model filenames loaded in the Jmol instance
114 String[] modelFileNames = null;
116 public PDBEntry[] pdbentry;
119 * datasource protocol for access to PDBEntrylatest
121 String protocol = null;
123 StringBuffer resetLastRes = new StringBuffer();
126 * sequences mapped to each pdbentry
128 public SequenceI[][] sequence;
130 StructureSelectionManager ssm;
132 public JmolViewer viewer;
134 public JalviewJmolBinding(PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
135 String[][] chains, String protocol)
137 this.sequence = sequenceIs;
138 this.chains = chains;
139 this.pdbentry = pdbentry;
140 this.protocol = protocol;
143 this.chains = new String[pdbentry.length][];
146 * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
147 * "jalviewJmol", ap.av.applet .getDocumentBase(),
148 * ap.av.applet.getCodeBase(), "", this);
150 * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
154 public JalviewJmolBinding(JmolViewer viewer2)
157 viewer.setJmolStatusListener(this);
158 viewer.addSelectionListener(this);
162 * construct a title string for the viewer window based on the data jalview
167 public String getViewerTitle()
169 if (sequence == null || pdbentry == null || sequence.length < 1
170 || pdbentry.length < 1 || sequence[0].length < 1)
172 return ("Jalview Jmol Window");
174 // TODO: give a more informative title when multiple structures are
176 StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
177 + pdbentry[0].getId());
179 if (pdbentry[0].getProperty() != null)
181 if (pdbentry[0].getProperty().get("method") != null)
183 title.append(" Method: ");
184 title.append(pdbentry[0].getProperty().get("method"));
186 if (pdbentry[0].getProperty().get("chains") != null)
188 title.append(" Chain:");
189 title.append(pdbentry[0].getProperty().get("chains"));
192 return title.toString();
196 * prepare the view for a given set of models/chains. chainList contains
197 * strings of the form 'pdbfilename:Chaincode'
200 * list of chains to make visible
202 public void centerViewer(Vector chainList)
204 StringBuffer cmd = new StringBuffer();
207 for (int i = 0, iSize = chainList.size(); i < iSize; i++)
210 lbl = (String) chainList.elementAt(i);
214 mlength = lbl.indexOf(":", p);
215 } while (p < mlength && mlength < (lbl.length() - 2));
216 // TODO: lookup each pdb id and recover proper model number for it.
217 cmd.append(":" + lbl.substring(mlength + 1) + " /"
218 + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");
220 if (cmd.length() > 0)
221 cmd.setLength(cmd.length() - 4);
222 evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
225 public void closeViewer()
227 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
228 // remove listeners for all structures in viewer
229 StructureSelectionManager.getStructureSelectionManager()
230 .removeStructureViewerListener(this, this.getPdbFile());
231 // and shut down jmol
232 viewer.evalStringQuiet("zap");
233 viewer.setJmolStatusListener(null);
236 releaseUIResources();
240 * called by JalviewJmolbinding after closeViewer is called - release any
241 * resources and references so they can be garbage collected.
243 protected abstract void releaseUIResources();
245 public void colourByChain()
247 colourBySequence = false;
248 // TODO: colour by chain should colour each chain distinctly across all
250 // TODO: http://issues.jalview.org/browse/JAL-628
251 evalStateCommand("select *;color chain");
254 public void colourByCharge()
256 colourBySequence = false;
257 evalStateCommand("select *;color white;select ASP,GLU;color red;"
258 + "select LYS,ARG;color blue;select CYS;color yellow");
262 * superpose the structures associated with sequences in the alignment
263 * according to their corresponding positions.
265 public void superposeStructures(AlignmentI alignment)
267 superposeStructures(alignment, -1, null);
271 * superpose the structures associated with sequences in the alignment
272 * according to their corresponding positions. ded)
274 * @param refStructure
275 * - select which pdb file to use as reference (default is -1 - the
276 * first structure in the alignment)
278 public void superposeStructures(AlignmentI alignment, int refStructure)
280 superposeStructures(alignment, refStructure, null);
284 * superpose the structures associated with sequences in the alignment
285 * according to their corresponding positions. ded)
287 * @param refStructure
288 * - select which pdb file to use as reference (default is -1 - the
289 * first structure in the alignment)
293 public void superposeStructures(AlignmentI alignment, int refStructure,
294 ColumnSelection hiddenCols)
296 String[] files = getPdbFile();
297 if (refStructure >= files.length)
299 System.err.println("Invalid reference structure value "
303 if (refStructure < -1)
307 StringBuffer command = new StringBuffer(), selectioncom = new StringBuffer();
309 boolean matched[] = new boolean[alignment.getWidth()];
310 for (int m = 0; m < matched.length; m++)
313 matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
316 int commonrpositions[][] = new int[files.length][alignment.getWidth()];
317 String isel[] = new String[files.length];
318 // reference structure - all others are superposed in it
319 String[] targetC = new String[files.length];
320 String[] chainNames = new String[files.length];
321 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
323 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
325 if (mapping == null || mapping.length < 1)
329 for (int s = 0; s < sequence[pdbfnum].length; s++)
331 for (int sp, m = 0; m < mapping.length; m++)
333 if (mapping[m].getSequence() == sequence[pdbfnum][s]
334 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
336 if (refStructure == -1)
338 refStructure = pdbfnum;
340 SequenceI asp = alignment.getSequenceAt(sp);
341 for (int r = 0; r < matched.length; r++)
347 matched[r] = false; // assume this is not a good site
348 if (r >= asp.getLength())
353 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
355 // no mapping to gaps in sequence
358 int t = asp.findPosition(r); // sequence position
359 int apos = mapping[m].getAtomNum(t);
360 int pos = mapping[m].getPDBResNum(t);
362 if (pos < 1 || pos == lastPos)
364 // can't align unmapped sequence
367 matched[r] = true; // this is a good ite
369 // just record this residue position
370 commonrpositions[pdbfnum][r] = pos;
372 // create model selection suffix
373 isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
374 if (mapping[m].getChain() == null
375 || mapping[m].getChain().trim().length() == 0)
377 targetC[pdbfnum] = "";
381 targetC[pdbfnum] = ":" + mapping[m].getChain();
383 chainNames[pdbfnum] = mapping[m].getPdbId()+targetC[pdbfnum];
384 // move on to next pdb file
385 s = sequence[pdbfnum].length;
391 String[] selcom = new String[files.length];
393 // generate select statements to select regions to superimpose structures
395 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
397 String chainCd = targetC[pdbfnum];
400 StringBuffer molsel = new StringBuffer();
402 for (int r = 0; r < matched.length; r++)
410 if (lpos != commonrpositions[pdbfnum][r] - 1)
416 molsel.append(chainCd);
417 // molsel.append("} {");
423 // continuous run - and lpos >-1
426 // at the beginning, so add dash
432 lpos = commonrpositions[pdbfnum][r];
433 // molsel.append(lpos);
436 // add final selection phrase
440 molsel.append(chainCd);
443 selcom[pdbfnum] = molsel.toString();
444 selectioncom.append("((");
445 selectioncom.append(selcom[pdbfnum].substring(1,
446 selcom[pdbfnum].length() - 1));
447 selectioncom.append(" )& ");
448 selectioncom.append(pdbfnum + 1);
449 selectioncom.append(".1)");
450 if (pdbfnum < files.length - 1)
452 selectioncom.append("|");
456 // TODO: consider bailing if nmatched less than 4 because superposition not
458 // TODO: refactor superposable position search (above) from jmol selection
459 // construction (below)
460 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
462 if (pdbfnum == refStructure)
466 command.append("echo ");
467 command.append("\"Superposing (");
468 command.append(chainNames[pdbfnum]);
469 command.append(") against reference (");
470 command.append(chainNames[refStructure]);
471 command.append(")\";\ncompare ");
473 command.append(1 + pdbfnum);
474 command.append(".1} {");
475 command.append(1 + refStructure);
476 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
478 // form the matched pair strings
480 for (int s = 0; s < 2; s++)
482 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
484 command.append(" ROTATE TRANSLATE;\n");
486 System.out.println("Select regions:\n" + selectioncom.toString());
487 evalStateCommand("select *; cartoons off; backbone; select ("
488 + selectioncom.toString() + "); cartoons; ");
489 // selcom.append("; ribbons; ");
490 System.out.println("Superimpose command(s):\n" + command.toString());
492 evalStateCommand(command.toString());
494 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
497 public void evalStateCommand(String command)
500 if (lastCommand == null || !lastCommand.equals(command))
502 viewer.evalStringQuiet(command + "\n");
505 lastCommand = command;
509 * colour any structures associated with sequences in the given alignment
510 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
511 * if colourBySequence is enabled.
513 public void colourBySequence(boolean showFeatures, AlignmentI alignment)
515 if (!colourBySequence)
521 String[] files = getPdbFile();
522 SequenceRenderer sr = getSequenceRenderer();
524 FeatureRenderer fr = null;
527 fr = getFeatureRenderer();
530 StringBuffer command = new StringBuffer();
532 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
534 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
536 if (mapping == null || mapping.length < 1)
540 for (int s = 0; s < sequence[pdbfnum].length; s++)
542 for (int sp, m = 0; m < mapping.length; m++)
544 if (mapping[m].getSequence() == sequence[pdbfnum][s]
545 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
547 SequenceI asp = alignment.getSequenceAt(sp);
548 for (int r = 0; r < asp.getLength(); r++)
550 // no mapping to gaps in sequence
551 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
555 int pos = mapping[m].getPDBResNum(asp.findPosition(r));
557 if (pos < 1 || pos == lastPos)
562 Color col = sr.getResidueBoxColour(sequence[pdbfnum][s], r);
564 if (showFeatures && fr != null)
565 col = fr.findFeatureColour(col, sequence[pdbfnum][s], r);
566 String newSelcom = (mapping[m].getChain() != " " ? ":"
567 + mapping[m].getChain() : "")
576 + col.getBlue() + "]";
577 if (command.toString().endsWith(newSelcom))
579 command = condenseCommand(command.toString(), pos);
582 // TODO: deal with case when buffer is too large for Jmol to parse
583 // - execute command and flush
585 command.append(";select " + pos);
586 command.append(newSelcom);
593 evalStateCommand(command.toString());
596 public boolean isColourBySequence()
598 return colourBySequence;
601 public void setColourBySequence(boolean colourBySequence)
603 this.colourBySequence = colourBySequence;
606 StringBuffer condenseCommand(String command, int pos)
609 StringBuffer sb = new StringBuffer(command.substring(0,
610 command.lastIndexOf("select") + 7));
612 command = command.substring(sb.length());
616 if (command.indexOf("-") > -1)
618 start = command.substring(0, command.indexOf("-"));
622 start = command.substring(0, command.indexOf(":"));
625 sb.append(start + "-" + pos + command.substring(command.indexOf(":")));
630 public void createImage(String file, String type, int quality)
632 System.out.println("JMOL CREATE IMAGE");
635 public String createImage(String fileName, String type,
636 Object textOrBytes, int quality)
638 System.out.println("JMOL CREATE IMAGE");
642 public String eval(String strEval)
644 // System.out.println(strEval);
645 // "# 'eval' is implemented only for the applet.";
649 // End StructureListener
650 // //////////////////////////
652 public float[][] functionXY(String functionName, int x, int y)
657 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
659 // TODO Auto-generated method stub
663 public Color getColour(int atomIndex, int pdbResNum, String chain,
666 if (getModelNum(pdbfile) < 0)
668 // TODO: verify atomIndex is selecting correct model.
669 return new Color(viewer.getAtomArgb(atomIndex));
673 * returns the current featureRenderer that should be used to colour the
678 public abstract FeatureRenderer getFeatureRenderer();
681 * instruct the Jalview binding to update the pdbentries vector if necessary
682 * prior to matching the jmol view's contents to the list of structure files
683 * Jalview knows about.
685 public abstract void refreshPdbEntries();
687 private int getModelNum(String modelFileName)
689 String[] mfn = getPdbFile();
694 for (int i = 0; i < mfn.length; i++)
696 if (mfn[i].equalsIgnoreCase(modelFileName))
703 * map between index of model filename returned from getPdbFile and the first
704 * index of models from this file in the viewer. Note - this is not trimmed -
705 * use getPdbFile to get number of unique models.
707 private int _modelFileNameMap[];
709 // ////////////////////////////////
710 // /StructureListener
711 public synchronized String[] getPdbFile()
715 return new String[0];
717 if (modelFileNames == null)
720 String mset[] = new String[viewer.getModelCount()];
721 _modelFileNameMap = new int[mset.length];
723 mset[0] = viewer.getModelFileName(0);
724 for (int i = 1; i < mset.length; i++)
726 mset[j] = viewer.getModelFileName(i);
727 _modelFileNameMap[j] = i; // record the model index for the filename
728 // skip any additional models in the same file (NMR structures)
729 if ((mset[j] == null ? mset[j] != mset[j - 1]
730 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
735 modelFileNames = new String[j];
736 System.arraycopy(mset, 0, modelFileNames, 0, j);
738 return modelFileNames;
742 * map from string to applet
744 public Map getRegistryInfo()
746 // TODO Auto-generated method stub
751 * returns the current sequenceRenderer that should be used to colour the
756 public abstract SequenceRenderer getSequenceRenderer();
758 // ///////////////////////////////
759 // JmolStatusListener
761 public void handlePopupMenu(int x, int y)
763 jmolpopup.show(x, y);
767 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
770 if (modelFileNames == null)
775 // look up file model number for this pdbfile
778 // may need to adjust for URLencoding here - we don't worry about that yet.
779 while (mdlNum < modelFileNames.length
780 && !pdbfile.equals(modelFileNames[mdlNum]))
782 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
785 if (mdlNum == modelFileNames.length)
791 // if (!pdbfile.equals(pdbentry.getFile()))
793 if (resetLastRes.length() > 0)
795 viewer.evalStringQuiet(resetLastRes.toString());
799 eval.append("select " + pdbResNum); // +modelNum
801 resetLastRes.setLength(0);
802 resetLastRes.append("select " + pdbResNum); // +modelNum
805 resetLastRes.append(":");
806 if (!chain.equals(" "))
809 resetLastRes.append(chain);
812 eval.append(" /" + (mdlNum + 1));
813 resetLastRes.append("/" + (mdlNum + 1));
815 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
817 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
818 + " and not hetero; spacefill 0;");
820 eval.append("spacefill 200;select none");
822 viewer.evalStringQuiet(eval.toString());
827 boolean debug = true;
829 private void jmolHistory(boolean enable)
831 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
834 public void loadInline(String string)
838 // viewer.loadInline(strModel, isAppend);
840 // construct fake fullPathName and fileName so we can identify the file
842 // Then, construct pass a reader for the string to Jmol.
843 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
844 // fileName, null, reader, false, null, null, 0);
845 viewer.openStringInline(string);
848 public void mouseOverStructure(int atomIndex, String strInfo)
851 int mdlSep = strInfo.indexOf("/");
852 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
854 if (chainSeparator == -1)
856 chainSeparator = strInfo.indexOf(".");
857 if (mdlSep > -1 && mdlSep < chainSeparator)
859 chainSeparator1 = chainSeparator;
860 chainSeparator = mdlSep;
863 pdbResNum = Integer.parseInt(strInfo.substring(
864 strInfo.indexOf("]") + 1, chainSeparator));
868 if (strInfo.indexOf(":") > -1)
869 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
870 strInfo.indexOf("."));
876 String pdbfilename = modelFileNames[frameNo]; // default is first or current
880 if (chainSeparator1 == -1)
882 chainSeparator1 = strInfo.indexOf(".", mdlSep);
884 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
885 chainSeparator1) : strInfo.substring(mdlSep + 1);
888 // recover PDB filename for the model hovered over.
890 .getModelFileName(new Integer(mdlId).intValue() - 1);
891 } catch (Exception e)
896 if (lastMessage == null || !lastMessage.equals(strInfo))
897 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
899 lastMessage = strInfo;
902 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
906 System.err.println("Ignoring additional hover info: " + data
907 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
909 mouseOverStructure(atomIndex, strInfo);
913 * { if (history != null && strStatus != null &&
914 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
918 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
921 * this implements the toggle label behaviour copied from the original
922 * structure viewer, MCView
926 System.err.println("Ignoring additional pick data string " + strData);
928 int chainSeparator = strInfo.indexOf(":");
930 if (chainSeparator == -1)
931 chainSeparator = strInfo.indexOf(".");
933 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
935 String mdlString = "";
936 if ((p = strInfo.indexOf(":")) > -1)
937 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
939 if ((p = strInfo.indexOf("/")) > -1)
941 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
943 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
947 if (!atomsPicked.contains(picked))
949 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
950 atomsPicked.addElement(picked);
954 viewer.evalString("select " + picked + ";label off");
955 atomsPicked.removeElement(picked);
958 // TODO: in application this happens
960 // if (scriptWindow != null)
962 // scriptWindow.sendConsoleMessage(strInfo);
963 // scriptWindow.sendConsoleMessage("\n");
968 public void notifyCallback(int type, Object[] data)
974 case JmolConstants.CALLBACK_LOADSTRUCT:
975 notifyFileLoaded((String) data[1], (String) data[2],
976 (String) data[3], (String) data[4],
977 ((Integer) data[5]).intValue());
980 case JmolConstants.CALLBACK_PICK:
981 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
983 // also highlight in alignment
984 case JmolConstants.CALLBACK_HOVER:
985 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
988 case JmolConstants.CALLBACK_SCRIPT:
989 notifyScriptTermination((String) data[2],
990 ((Integer) data[3]).intValue());
992 case JmolConstants.CALLBACK_ECHO:
993 sendConsoleEcho((String) data[1]);
995 case JmolConstants.CALLBACK_MESSAGE:
996 sendConsoleMessage((data == null) ? ((String) null)
999 case JmolConstants.CALLBACK_ERROR:
1000 // System.err.println("Ignoring error callback.");
1002 case JmolConstants.CALLBACK_SYNC:
1003 case JmolConstants.CALLBACK_RESIZE:
1006 case JmolConstants.CALLBACK_MEASURE:
1008 case JmolConstants.CALLBACK_CLICK:
1010 System.err.println("Unhandled callback " + type + " "
1011 + data[1].toString());
1014 } catch (Exception e)
1016 System.err.println("Squashed Jmol callback handler error:");
1017 e.printStackTrace();
1021 public boolean notifyEnabled(int callbackPick)
1023 switch (callbackPick)
1025 case JmolConstants.CALLBACK_ECHO:
1026 case JmolConstants.CALLBACK_LOADSTRUCT:
1027 case JmolConstants.CALLBACK_MEASURE:
1028 case JmolConstants.CALLBACK_MESSAGE:
1029 case JmolConstants.CALLBACK_PICK:
1030 case JmolConstants.CALLBACK_SCRIPT:
1031 case JmolConstants.CALLBACK_HOVER:
1032 case JmolConstants.CALLBACK_ERROR:
1034 case JmolConstants.CALLBACK_RESIZE:
1035 case JmolConstants.CALLBACK_SYNC:
1036 case JmolConstants.CALLBACK_CLICK:
1037 case JmolConstants.CALLBACK_ANIMFRAME:
1038 case JmolConstants.CALLBACK_MINIMIZATION:
1043 // incremented every time a load notification is successfully handled -
1044 // lightweight mechanism for other threads to detect when they can start
1045 // referrring to new structures.
1046 private long loadNotifiesHandled = 0;
1048 public long getLoadNotifiesHandled()
1050 return loadNotifiesHandled;
1053 public void notifyFileLoaded(String fullPathName, String fileName2,
1054 String modelName, String errorMsg, int modelParts)
1056 if (errorMsg != null)
1058 fileLoadingError = errorMsg;
1062 // TODO: deal sensibly with models loaded inLine:
1063 // modelName will be null, as will fullPathName.
1065 // the rest of this routine ignores the arguments, and simply interrogates
1066 // the Jmol view to find out what structures it contains, and adds them to
1067 // the structure selection manager.
1068 fileLoadingError = null;
1069 String[] oldmodels = modelFileNames;
1070 modelFileNames = null;
1071 chainNames = new Vector();
1072 chainFile = new Hashtable();
1073 boolean notifyLoaded = false;
1074 String[] modelfilenames = getPdbFile();
1075 ssm = StructureSelectionManager.getStructureSelectionManager();
1076 // first check if we've lost any structures
1077 if (oldmodels != null && oldmodels.length > 0)
1080 for (int i = 0; i < oldmodels.length; i++)
1082 for (int n = 0; n < modelfilenames.length; n++)
1084 if (modelfilenames[n] == oldmodels[i])
1086 oldmodels[i] = null;
1090 if (oldmodels[i] != null)
1097 String[] oldmfn = new String[oldm];
1099 for (int i = 0; i < oldmodels.length; i++)
1101 if (oldmodels[i] != null)
1103 oldmfn[oldm++] = oldmodels[i];
1106 // deregister the Jmol instance for these structures - we'll add
1107 // ourselves again at the end for the current structure set.
1108 ssm.removeStructureViewerListener(this, oldmfn);
1111 refreshPdbEntries();
1112 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1114 String fileName = modelfilenames[modelnum];
1115 boolean foundEntry = false;
1116 MCview.PDBfile pdb = null;
1117 String pdbfile = null, pdbfhash = null;
1118 // model was probably loaded inline - so check the pdb file hashcode
1121 // calculate essential attributes for the pdb data imported inline.
1122 // prolly need to resolve modelnumber properly - for now just use our
1124 pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])
1126 pdbfhash = "" + pdbfile.hashCode();
1128 if (pdbentry != null)
1130 // search pdbentries and sequences to find correct pdbentry for this
1132 for (int pe = 0; pe < pdbentry.length; pe++)
1134 boolean matches = false;
1135 if (fileName == null)
1138 // see JAL-623 - need method of matching pasted data up
1140 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
1141 AppletFormatAdapter.PASTE);
1142 pdbentry[modelnum].setFile("INLINE" + pdb.id);
1149 if (matches = pdbentry[pe].getFile().equals(fileName))
1152 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1155 // to be tested. See mantis bug
1156 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1157 String protocol = AppletFormatAdapter.URL;
1160 File fl = new java.io.File(pdbentry[pe].getFile());
1163 protocol = AppletFormatAdapter.FILE;
1165 } catch (Exception e)
1171 pdb = ssm.setMapping(sequence[pe], chains[pe],
1172 pdbentry[pe].getFile(), protocol);
1178 pdbentry[pe].setId(pdb.id);
1179 // add an entry for every chain in the model
1180 for (int i = 0; i < pdb.chains.size(); i++)
1182 String chid = new String(pdb.id + ":"
1183 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
1184 chainFile.put(chid, pdbentry[pe].getFile());
1185 chainNames.addElement(chid);
1187 notifyLoaded = true;
1191 if (!foundEntry && associateNewStructs)
1193 // this is a foreign pdb file that jalview doesn't know about - add
1194 // it to the dataset and try to find a home - either on a matching
1195 // sequence or as a new sequence.
1196 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1198 // parse pdb file into a chain, etc.
1199 // locate best match for pdb in associated views and add mapping to
1201 // if properly registered then
1202 notifyLoaded = true;
1207 // so finally, update the jmol bits and pieces
1208 if (jmolpopup != null)
1210 // potential for deadlock here:
1211 // jmolpopup.updateComputedMenus();
1213 if (!isLoadingFromArchive())
1215 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1217 setLoadingFromArchive(false);
1218 // register ourselves as a listener and notify the gui that it needs to
1220 ssm.addStructureViewerListener(this);
1223 FeatureRenderer fr = getFeatureRenderer();
1229 loadNotifiesHandled++;
1233 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1235 notifyAtomPicked(iatom, strMeasure, null);
1238 public abstract void notifyScriptTermination(String strStatus,
1242 * display a message echoed from the jmol viewer
1246 public abstract void sendConsoleEcho(String strEcho); /*
1247 * { showConsole(true);
1249 * history.append("\n" +
1253 // /End JmolStatusListener
1254 // /////////////////////////////
1258 * status message - usually the response received after a script
1261 public abstract void sendConsoleMessage(String strStatus);
1263 public void setCallbackFunction(String callbackType,
1264 String callbackFunction)
1266 System.err.println("Ignoring set-callback request to associate "
1267 + callbackType + " with function " + callbackFunction);
1271 public void setJalviewColourScheme(ColourSchemeI cs)
1273 colourBySequence = false;
1282 // TODO: Switch between nucleotide or aa selection expressions
1283 Enumeration en = ResidueProperties.aa3Hash.keys();
1284 StringBuffer command = new StringBuffer("select *;color white;");
1285 while (en.hasMoreElements())
1287 res = en.nextElement().toString();
1288 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
1292 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
1294 command.append("select " + res + ";color[" + col.getRed() + ","
1295 + col.getGreen() + "," + col.getBlue() + "];");
1298 evalStateCommand(command.toString());
1302 public void showHelp()
1304 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1308 * open the URL somehow
1312 public abstract void showUrl(String url, String target);
1315 * called when the binding thinks the UI needs to be refreshed after a Jmol
1316 * state change. this could be because structures were loaded, or because an
1317 * error has occured.
1319 public abstract void refreshGUI();
1322 * called to show or hide the associated console window container.
1326 public abstract void showConsole(boolean show);
1329 * @param renderPanel
1331 * - when true will initialise jmol's file IO system (should be false
1332 * in applet context)
1334 * @param documentBase
1336 * @param commandOptions
1338 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1339 String htmlName, URL documentBase, URL codeBase,
1340 String commandOptions)
1342 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
1343 codeBase, commandOptions, null, null);
1348 * @param renderPanel
1350 * - when true will initialise jmol's file IO system (should be false
1351 * in applet context)
1353 * @param documentBase
1355 * @param commandOptions
1356 * @param consolePanel
1357 * - panel to contain Jmol console
1358 * @param buttonsToShow
1359 * - buttons to show on the console, in ordr
1361 public void allocateViewer(Container renderPanel, boolean jmolfileio,
1362 String htmlName, URL documentBase, URL codeBase,
1363 String commandOptions, final Container consolePanel,
1364 String buttonsToShow)
1366 viewer = JmolViewer.allocateViewer(renderPanel,
1367 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1368 + ((Object) this).toString(), documentBase, codeBase,
1369 commandOptions, this);
1371 console = createJmolConsole(viewer, consolePanel, buttonsToShow);
1372 if (consolePanel != null)
1374 consolePanel.addComponentListener(this);
1380 protected abstract JmolAppConsoleInterface createJmolConsole(
1381 JmolViewer viewer2, Container consolePanel, String buttonsToShow);
1383 protected org.jmol.api.JmolAppConsoleInterface console = null;
1385 public void componentResized(ComponentEvent e)
1390 public void componentMoved(ComponentEvent e)
1395 public void componentShown(ComponentEvent e)
1400 public void componentHidden(ComponentEvent e)
1405 public void setLoadingFromArchive(boolean loadingFromArchive)
1407 this.loadingFromArchive = loadingFromArchive;
1410 public boolean isLoadingFromArchive()
1412 return loadingFromArchive;
1415 public void setBackgroundColour(java.awt.Color col)
1418 viewer.evalStringQuiet("background [" + col.getRed() + ","
1419 + col.getGreen() + "," + col.getBlue() + "];");
1424 * add structures and any known sequence associations
1426 * @returns the pdb entries added to the current set.
1428 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
1429 SequenceI[][] seq, String[][] chns)
1432 Vector v = new Vector();
1433 Vector rtn = new Vector();
1434 for (int i = 0; i < pdbentry.length; i++)
1436 v.addElement(pdbentry[i]);
1438 for (int i = 0; i < pdbe.length; i++)
1440 int r = v.indexOf(pdbe[i]);
1441 if (r == -1 || r >= pdbentry.length)
1443 rtn.addElement(new int[]
1445 v.addElement(pdbe[i]);
1449 // just make sure the sequence/chain entries are all up to date
1450 addSequenceAndChain(r, seq[i], chns[i]);
1453 pdbe = new PDBEntry[v.size()];
1458 // expand the tied seuqence[] and string[] arrays
1459 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
1460 String[][] sch = new String[pdbentry.length][];
1461 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
1462 System.arraycopy(chains, 0, sch, 0, this.chains.length);
1465 pdbe = new PDBEntry[rtn.size()];
1466 for (int r = 0; r < pdbe.length; r++)
1468 int[] stri = ((int[]) rtn.elementAt(r));
1469 // record the pdb file as a new addition
1470 pdbe[r] = pdbentry[stri[0]];
1471 // and add the new sequence/chain entries
1472 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
1482 public void addSequence(int pe, SequenceI[] seq)
1484 // add sequences to the pe'th pdbentry's seuqence set.
1485 addSequenceAndChain(pe, seq, null);
1488 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
1490 if (pe < 0 || pe >= pdbentry.length)
1493 "Implementation error - no corresponding pdbentry (for index "
1494 + pe + ") to add sequences mappings to");
1496 final String nullChain = "TheNullChain";
1497 Vector s = new Vector();
1498 Vector c = new Vector();
1501 chains = new String[pdbentry.length][];
1503 if (sequence[pe] != null)
1505 for (int i = 0; i < sequence[pe].length; i++)
1507 s.addElement(sequence[pe][i]);
1508 if (chains[pe] != null)
1510 if (i < chains[pe].length)
1512 c.addElement(chains[pe][i]);
1516 c.addElement(nullChain);
1521 if (tchain != null && tchain.length > 0)
1523 c.addElement(nullChain);
1528 for (int i = 0; i < seq.length; i++)
1530 if (!s.contains(seq[i]))
1532 s.addElement(seq[i]);
1533 if (tchain != null && i < tchain.length)
1535 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
1539 SequenceI[] tmp = new SequenceI[s.size()];
1544 String[] tch = new String[c.size()];
1546 for (int i = 0; i < tch.length; i++)
1548 if (tch[i] == nullChain)