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++)
396 if (lpos != commonrpositions[pdbfnum][r] - 1)
402 molsel.append(chainCd);
403 // molsel.append("} {");
409 // continuous run - and lpos >-1
412 // at the beginning, so add dash
418 lpos = commonrpositions[pdbfnum][r];
419 // molsel.append(lpos);
422 // add final selection phrase
426 molsel.append(chainCd);
429 selcom[pdbfnum] = molsel.toString();
430 selectioncom.append("((");
431 selectioncom.append(selcom[pdbfnum].substring(1,
432 selcom[pdbfnum].length() - 1));
433 selectioncom.append(" )& ");
434 selectioncom.append(pdbfnum + 1);
435 selectioncom.append(".1)");
436 if (pdbfnum < files.length - 1)
438 selectioncom.append("|");
442 // TODO: consider bailing if nmatched less than 4 because superposition not well defined.
443 // TODO: refactor superposable position search (above) from jmol selection construction (below)
444 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
446 if (pdbfnum == refStructure)
450 command.append("compare ");
452 command.append(1 + pdbfnum);
453 command.append(".1} {");
454 command.append(1 + refStructure);
455 command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
457 // form the matched pair strings
459 for (int s = 0; s < 2; s++)
461 command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
463 command.append(" ROTATE TRANSLATE;\n");
465 System.out.println("Select regions:\n" + selectioncom.toString());
466 evalStateCommand("select *; cartoons off; backbone; select ("
467 + selectioncom.toString() + "); cartoons; ");
468 // selcom.append("; ribbons; ");
469 System.out.println("Superimpose command(s):\n" + command.toString());
471 evalStateCommand(command.toString());
473 // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
476 public void evalStateCommand(String command)
479 if (lastCommand == null || !lastCommand.equals(command))
481 viewer.evalStringQuiet(command + "\n");
484 lastCommand = command;
488 * colour any structures associated with sequences in the given alignment
489 * using the getFeatureRenderer() and getSequenceRenderer() renderers but only
490 * if colourBySequence is enabled.
492 public void colourBySequence(boolean showFeatures, AlignmentI alignment)
494 if (!colourBySequence)
500 String[] files = getPdbFile();
501 SequenceRenderer sr = getSequenceRenderer();
503 FeatureRenderer fr = null;
506 fr = getFeatureRenderer();
509 StringBuffer command = new StringBuffer();
511 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
513 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
515 if (mapping == null || mapping.length < 1)
519 for (int s = 0; s < sequence[pdbfnum].length; s++)
521 for (int sp, m = 0; m < mapping.length; m++)
523 if (mapping[m].getSequence() == sequence[pdbfnum][s]
524 && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
526 SequenceI asp = alignment.getSequenceAt(sp);
527 for (int r = 0; r < asp.getLength(); r++)
529 // no mapping to gaps in sequence
530 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
534 int pos = mapping[m].getPDBResNum(asp.findPosition(r));
536 if (pos < 1 || pos == lastPos)
541 Color col = sr.getResidueBoxColour(sequence[pdbfnum][s], r);
544 col = fr.findFeatureColour(col, sequence[pdbfnum][s], r);
545 String newSelcom = (mapping[m].getChain() != " " ? ":"
546 + mapping[m].getChain() : "")
555 + col.getBlue() + "]";
556 if (command.toString().endsWith(newSelcom))
558 command = condenseCommand(command.toString(), pos);
561 // TODO: deal with case when buffer is too large for Jmol to parse
562 // - execute command and flush
564 command.append(";select " + pos);
565 command.append(newSelcom);
572 evalStateCommand(command.toString());
575 public boolean isColourBySequence()
577 return colourBySequence;
580 public void setColourBySequence(boolean colourBySequence)
582 this.colourBySequence = colourBySequence;
585 StringBuffer condenseCommand(String command, int pos)
588 StringBuffer sb = new StringBuffer(command.substring(0,
589 command.lastIndexOf("select") + 7));
591 command = command.substring(sb.length());
595 if (command.indexOf("-") > -1)
597 start = command.substring(0, command.indexOf("-"));
601 start = command.substring(0, command.indexOf(":"));
604 sb.append(start + "-" + pos + command.substring(command.indexOf(":")));
609 public void createImage(String file, String type, int quality)
611 System.out.println("JMOL CREATE IMAGE");
614 public String createImage(String fileName, String type,
615 Object textOrBytes, int quality)
617 System.out.println("JMOL CREATE IMAGE");
621 public String eval(String strEval)
623 // System.out.println(strEval);
624 // "# 'eval' is implemented only for the applet.";
628 // End StructureListener
629 // //////////////////////////
631 public float[][] functionXY(String functionName, int x, int y)
636 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
638 // TODO Auto-generated method stub
642 public Color getColour(int atomIndex, int pdbResNum, String chain,
645 if (getModelNum(pdbfile) < 0)
647 // TODO: verify atomIndex is selecting correct model.
648 return new Color(viewer.getAtomArgb(atomIndex));
652 * returns the current featureRenderer that should be used to colour the
657 public abstract FeatureRenderer getFeatureRenderer();
660 * instruct the Jalview binding to update the pdbentries vector if necessary
661 * prior to matching the jmol view's contents to the list of structure files
662 * Jalview knows about.
664 public abstract void refreshPdbEntries();
666 private int getModelNum(String modelFileName)
668 String[] mfn = getPdbFile();
673 for (int i = 0; i < mfn.length; i++)
675 if (mfn[i].equalsIgnoreCase(modelFileName))
682 * map between index of model filename returned from getPdbFile and the first
683 * index of models from this file in the viewer. Note - this is not trimmed -
684 * use getPdbFile to get number of unique models.
686 private int _modelFileNameMap[];
688 // ////////////////////////////////
689 // /StructureListener
690 public synchronized String[] getPdbFile()
694 return new String[0];
696 if (modelFileNames == null)
699 String mset[] = new String[viewer.getModelCount()];
700 _modelFileNameMap = new int[mset.length];
702 mset[0] = viewer.getModelFileName(0);
703 for (int i = 1; i < mset.length; i++)
705 mset[j] = viewer.getModelFileName(i);
706 _modelFileNameMap[j] = i; // record the model index for the filename
707 // skip any additional models in the same file (NMR structures)
708 if ((mset[j] == null ? mset[j] != mset[j - 1] : (mset[j - 1] == null
709 || !mset[j].equals(mset[j - 1]))))
714 modelFileNames = new String[j];
715 System.arraycopy(mset, 0, modelFileNames, 0, j);
717 return modelFileNames;
721 * map from string to applet
723 public Map getRegistryInfo()
725 // TODO Auto-generated method stub
730 * returns the current sequenceRenderer that should be used to colour the
735 public abstract SequenceRenderer getSequenceRenderer();
737 // ///////////////////////////////
738 // JmolStatusListener
740 public void handlePopupMenu(int x, int y)
742 jmolpopup.show(x, y);
746 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
749 if (modelFileNames == null)
754 // look up file model number for this pdbfile
757 // may need to adjust for URLencoding here - we don't worry about that yet.
758 while (mdlNum < modelFileNames.length
759 && !pdbfile.equals(modelFileNames[mdlNum]))
761 // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);
764 if (mdlNum == modelFileNames.length)
770 // if (!pdbfile.equals(pdbentry.getFile()))
772 if (resetLastRes.length() > 0)
774 viewer.evalStringQuiet(resetLastRes.toString());
778 eval.append("select " + pdbResNum); // +modelNum
780 resetLastRes.setLength(0);
781 resetLastRes.append("select " + pdbResNum); // +modelNum
784 resetLastRes.append(":");
785 if (!chain.equals(" "))
788 resetLastRes.append(chain);
791 eval.append(" /" + (mdlNum + 1));
792 resetLastRes.append("/" + (mdlNum + 1));
794 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
796 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
797 + " and not hetero; spacefill 0;");
799 eval.append("spacefill 200;select none");
801 viewer.evalStringQuiet(eval.toString());
806 boolean debug = true;
808 private void jmolHistory(boolean enable)
810 viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
813 public void loadInline(String string)
817 // viewer.loadInline(strModel, isAppend);
819 // construct fake fullPathName and fileName so we can identify the file
821 // Then, construct pass a reader for the string to Jmol.
822 // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
823 // fileName, null, reader, false, null, null, 0);
824 viewer.openStringInline(string);
827 public void mouseOverStructure(int atomIndex, String strInfo)
830 int mdlSep = strInfo.indexOf("/");
831 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
833 if (chainSeparator == -1)
835 chainSeparator = strInfo.indexOf(".");
836 if (mdlSep > -1 && mdlSep < chainSeparator)
838 chainSeparator1 = chainSeparator;
839 chainSeparator = mdlSep;
842 pdbResNum = Integer.parseInt(strInfo.substring(
843 strInfo.indexOf("]") + 1, chainSeparator));
847 if (strInfo.indexOf(":") > -1)
848 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
849 strInfo.indexOf("."));
855 String pdbfilename = modelFileNames[frameNo]; // default is first or current
859 if (chainSeparator1 == -1)
861 chainSeparator1 = strInfo.indexOf(".", mdlSep);
863 String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
864 chainSeparator1) : strInfo.substring(mdlSep + 1);
867 // recover PDB filename for the model hovered over.
869 .getModelFileName(new Integer(mdlId).intValue() - 1);
870 } catch (Exception e)
875 if (lastMessage == null || !lastMessage.equals(strInfo))
876 ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
878 lastMessage = strInfo;
881 public void notifyAtomHovered(int atomIndex, String strInfo, String data)
885 System.err.println("Ignoring additional hover info: " + data
886 + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
888 mouseOverStructure(atomIndex, strInfo);
892 * { if (history != null && strStatus != null &&
893 * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
897 public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
900 * this implements the toggle label behaviour copied from the original
901 * structure viewer, MCView
905 System.err.println("Ignoring additional pick data string " + strData);
907 int chainSeparator = strInfo.indexOf(":");
909 if (chainSeparator == -1)
910 chainSeparator = strInfo.indexOf(".");
912 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
914 String mdlString = "";
915 if ((p = strInfo.indexOf(":")) > -1)
916 picked += strInfo.substring(p + 1, strInfo.indexOf("."));
918 if ((p = strInfo.indexOf("/")) > -1)
920 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
922 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
926 if (!atomsPicked.contains(picked))
928 viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
929 atomsPicked.addElement(picked);
933 viewer.evalString("select " + picked + ";label off");
934 atomsPicked.removeElement(picked);
937 // TODO: in application this happens
939 // if (scriptWindow != null)
941 // scriptWindow.sendConsoleMessage(strInfo);
942 // scriptWindow.sendConsoleMessage("\n");
947 public void notifyCallback(int type, Object[] data)
953 case JmolConstants.CALLBACK_LOADSTRUCT:
954 notifyFileLoaded((String) data[1], (String) data[2],
955 (String) data[3], (String) data[4],
956 ((Integer) data[5]).intValue());
959 case JmolConstants.CALLBACK_PICK:
960 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
962 // also highlight in alignment
963 case JmolConstants.CALLBACK_HOVER:
964 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
967 case JmolConstants.CALLBACK_SCRIPT:
968 notifyScriptTermination((String) data[2],
969 ((Integer) data[3]).intValue());
971 case JmolConstants.CALLBACK_ECHO:
972 sendConsoleEcho((String) data[1]);
974 case JmolConstants.CALLBACK_MESSAGE:
975 sendConsoleMessage((data == null) ? ((String) null)
978 case JmolConstants.CALLBACK_ERROR:
979 // System.err.println("Ignoring error callback.");
981 case JmolConstants.CALLBACK_SYNC:
982 case JmolConstants.CALLBACK_RESIZE:
985 case JmolConstants.CALLBACK_MEASURE:
987 case JmolConstants.CALLBACK_CLICK:
989 System.err.println("Unhandled callback " + type + " "
990 + data[1].toString());
993 } catch (Exception e)
995 System.err.println("Squashed Jmol callback handler error:");
1000 public boolean notifyEnabled(int callbackPick)
1002 switch (callbackPick)
1004 case JmolConstants.CALLBACK_ECHO:
1005 case JmolConstants.CALLBACK_LOADSTRUCT:
1006 case JmolConstants.CALLBACK_MEASURE:
1007 case JmolConstants.CALLBACK_MESSAGE:
1008 case JmolConstants.CALLBACK_PICK:
1009 case JmolConstants.CALLBACK_SCRIPT:
1010 case JmolConstants.CALLBACK_HOVER:
1011 case JmolConstants.CALLBACK_ERROR:
1013 case JmolConstants.CALLBACK_RESIZE:
1014 case JmolConstants.CALLBACK_SYNC:
1015 case JmolConstants.CALLBACK_CLICK:
1016 case JmolConstants.CALLBACK_ANIMFRAME:
1017 case JmolConstants.CALLBACK_MINIMIZATION:
1022 // incremented every time a load notification is successfully handled - lightweight mechanism for other threads to detect when they can start referrring to new structures.
1023 private long loadNotifiesHandled=0;
1024 public long getLoadNotifiesHandled()
1026 return loadNotifiesHandled;
1028 public void notifyFileLoaded(String fullPathName, String fileName2,
1029 String modelName, String errorMsg, int modelParts)
1031 if (errorMsg != null)
1033 fileLoadingError = errorMsg;
1037 // TODO: deal sensibly with models loaded inLine:
1038 // modelName will be null, as will fullPathName.
1040 // the rest of this routine ignores the arguments, and simply interrogates
1041 // the Jmol view to find out what structures it contains, and adds them to
1042 // the structure selection manager.
1043 fileLoadingError = null;
1044 String[] oldmodels = modelFileNames;
1045 modelFileNames = null;
1046 chainNames = new Vector();
1047 boolean notifyLoaded = false;
1048 String[] modelfilenames = getPdbFile();
1049 ssm = StructureSelectionManager.getStructureSelectionManager();
1050 // first check if we've lost any structures
1051 if (oldmodels != null && oldmodels.length > 0)
1054 for (int i = 0; i < oldmodels.length; i++)
1056 for (int n = 0; n < modelfilenames.length; n++)
1058 if (modelfilenames[n] == oldmodels[i])
1060 oldmodels[i] = null;
1064 if (oldmodels[i] != null)
1071 String[] oldmfn = new String[oldm];
1073 for (int i = 0; i < oldmodels.length; i++)
1075 if (oldmodels[i] != null)
1077 oldmfn[oldm++] = oldmodels[i];
1080 // deregister the Jmol instance for these structures - we'll add
1081 // ourselves again at the end for the current structure set.
1082 ssm.removeStructureViewerListener(this, oldmfn);
1085 refreshPdbEntries();
1086 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
1088 String fileName = modelfilenames[modelnum];
1089 boolean foundEntry = false;
1090 MCview.PDBfile pdb = null;
1091 String pdbfile = null, pdbfhash = null;
1092 // model was probably loaded inline - so check the pdb file hashcode
1095 // calculate essential attributes for the pdb data imported inline.
1096 // prolly need to resolve modelnumber properly - for now just use our 'best guess'
1097 pdbfile = viewer.getData(""+(1+_modelFileNameMap[modelnum])+".0",
1099 pdbfhash = "" + pdbfile.hashCode();
1101 if (pdbentry != null)
1103 // search pdbentries and sequences to find correct pdbentry for this
1105 for (int pe = 0; pe < pdbentry.length; pe++)
1107 boolean matches = false;
1108 if (fileName == null)
1111 // see JAL-623 - need method of matching pasted data up
1113 pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
1114 AppletFormatAdapter.PASTE);
1115 pdbentry[modelnum].setFile("INLINE" + pdb.id);
1122 if (matches = pdbentry[pe].getFile().equals(fileName))
1125 // TODO: Jmol can in principle retrieve from CLASSLOADER but
1128 // to be tested. See mantis bug
1129 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
1130 String protocol = AppletFormatAdapter.URL;
1133 File fl = new java.io.File(pdbentry[pe].getFile());
1136 protocol = AppletFormatAdapter.FILE;
1138 } catch (Exception e)
1144 pdb = ssm.setMapping(sequence[pe], chains[pe],
1145 pdbentry[pe].getFile(), protocol);
1152 pdbentry[pe].setId(pdb.id);
1153 // add an entry for every chain in the model
1154 for (int i = 0; i < pdb.chains.size(); i++)
1156 chainNames.addElement(new String(pdb.id + ":"
1157 + ((MCview.PDBChain) pdb.chains.elementAt(i)).id));
1159 notifyLoaded = true;
1163 if (!foundEntry && associateNewStructs)
1165 // this is a foreign pdb file that jalview doesn't know about - add
1166 // it to the dataset and try to find a home - either on a matching
1167 // sequence or as a new sequence.
1168 String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
1170 // parse pdb file into a chain, etc.
1171 // locate best match for pdb in associated views and add mapping to
1173 // if properly registered then
1174 notifyLoaded = true;
1179 // so finally, update the jmol bits and pieces
1180 if (jmolpopup != null)
1182 // potential for deadlock here:
1183 // jmolpopup.updateComputedMenus();
1185 if (!isLoadingFromArchive())
1187 viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
1189 setLoadingFromArchive(false);
1190 // register ourselves as a listener and notify the gui that it needs to
1192 ssm.addStructureViewerListener(this);
1195 FeatureRenderer fr = getFeatureRenderer();
1201 loadNotifiesHandled++;
1205 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
1207 notifyAtomPicked(iatom, strMeasure, null);
1210 public abstract void notifyScriptTermination(String strStatus,
1214 * display a message echoed from the jmol viewer
1218 public abstract void sendConsoleEcho(String strEcho); /*
1219 * { showConsole(true);
1221 * history.append("\n" +
1225 // /End JmolStatusListener
1226 // /////////////////////////////
1230 * status message - usually the response received after a script
1233 public abstract void sendConsoleMessage(String strStatus);
1235 public void setCallbackFunction(String callbackType,
1236 String callbackFunction)
1238 System.err.println("Ignoring set-callback request to associate "
1239 + callbackType + " with function " + callbackFunction);
1243 public void setJalviewColourScheme(ColourSchemeI cs)
1245 colourBySequence = false;
1254 // TODO: Switch between nucleotide or aa selection expressions
1255 Enumeration en = ResidueProperties.aa3Hash.keys();
1256 StringBuffer command = new StringBuffer("select *;color white;");
1257 while (en.hasMoreElements())
1259 res = en.nextElement().toString();
1260 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
1264 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
1266 command.append("select " + res + ";color[" + col.getRed() + ","
1267 + col.getGreen() + "," + col.getBlue() + "];");
1270 evalStateCommand(command.toString());
1274 public void showHelp()
1276 showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
1280 * open the URL somehow
1284 public abstract void showUrl(String url, String target);
1287 * called when the binding thinks the UI needs to be refreshed after a Jmol
1288 * state change. this could be because structures were loaded, or because an
1289 * error has occured.
1291 public abstract void refreshGUI();
1294 * called to show or hide the associated console window container.
1297 public abstract void showConsole(boolean show);
1299 * @param renderPanel
1301 * - when true will initialise jmol's file IO system (should be false
1302 * in applet context)
1304 * @param documentBase
1306 * @param commandOptions
1308 public void allocateViewer(Component renderPanel, boolean jmolfileio,
1309 String htmlName, URL documentBase, URL codeBase,
1310 String commandOptions)
1312 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase, codeBase, commandOptions, null,null);
1316 * @param renderPanel
1318 * - when true will initialise jmol's file IO system (should be false
1319 * in applet context)
1321 * @param documentBase
1323 * @param commandOptions
1324 * @param consolePanel - panel to contain Jmol console
1325 * @param buttonsToShow - buttons to show on the console, in ordr
1327 public void allocateViewer(Component renderPanel, boolean jmolfileio,
1328 String htmlName, URL documentBase, URL codeBase,
1329 String commandOptions, final Container consolePanel, String buttonsToShow)
1331 viewer = JmolViewer.allocateViewer(renderPanel,
1332 (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
1333 + ((Object) this).toString(), documentBase, codeBase,
1334 commandOptions, this);
1336 console = createJmolConsole(viewer, consolePanel,
1339 viewer.setConsole(new JmolAppConsoleInterface() {
1342 public JmolScriptEditorInterface getScriptEditor()
1344 return console.getScriptEditor();
1348 public JmolAppConsoleInterface getAppConsole(Viewer viewer,
1354 public String getText()
1356 return console.getText();
1360 public Object getMyMenuBar()
1362 return console.getMyMenuBar();
1366 public void setVisible(boolean b)
1372 public void sendConsoleEcho(String strEcho)
1374 console.sendConsoleEcho(strEcho);
1379 public void sendConsoleMessage(String strInfo)
1381 console.sendConsoleMessage(strInfo);
1391 public void dispose()
1402 protected abstract JmolAppConsoleInterface createJmolConsole(JmolViewer viewer2,
1403 Container consolePanel, String buttonsToShow);
1405 protected org.jmol.api.JmolAppConsoleInterface console = null;
1407 public void setLoadingFromArchive(boolean loadingFromArchive)
1409 this.loadingFromArchive = loadingFromArchive;
1412 public boolean isLoadingFromArchive()
1414 return loadingFromArchive;
1417 public void setBackgroundColour(java.awt.Color col)
1420 viewer.evalStringQuiet("background [" + col.getRed() + ","
1421 + col.getGreen() + "," + col.getBlue() + "];");
1426 * add structures and any known sequence associations
1428 * @returns the pdb entries added to the current set.
1430 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
1431 SequenceI[][] seq, String[][] chns)
1434 Vector v = new Vector();
1435 Vector rtn = new Vector();
1436 for (int i = 0; i < pdbentry.length; i++)
1438 v.addElement(pdbentry[i]);
1440 for (int i = 0; i < pdbe.length; i++)
1442 int r = v.indexOf(pdbe[i]);
1443 if (r == -1 || r >= pdbentry.length)
1445 rtn.addElement(new int[]
1447 v.addElement(pdbe[i]);
1451 // just make sure the sequence/chain entries are all up to date
1452 addSequenceAndChain(r, seq[i], chns[i]);
1455 pdbe = new PDBEntry[v.size()];
1460 // expand the tied seuqence[] and string[] arrays
1461 SequenceI[][] sqs = new SequenceI[pdbentry.length][];
1462 String[][] sch = new String[pdbentry.length][];
1463 System.arraycopy(sequence, 0, sqs, 0, sequence.length);
1464 System.arraycopy(chains, 0, sch, 0, this.chains.length);
1467 pdbe = new PDBEntry[rtn.size()];
1468 for (int r = 0; r < pdbe.length; r++)
1470 int[] stri = ((int[]) rtn.elementAt(r));
1471 // record the pdb file as a new addition
1472 pdbe[r] = pdbentry[stri[0]];
1473 // and add the new sequence/chain entries
1474 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
1484 public void addSequence(int pe, SequenceI[] seq)
1486 // add sequences to the pe'th pdbentry's seuqence set.
1487 addSequenceAndChain(pe, seq, null);
1490 private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
1492 if (pe < 0 || pe >= pdbentry.length)
1495 "Implementation error - no corresponding pdbentry (for index "
1496 + pe + ") to add sequences mappings to");
1498 final String nullChain = "TheNullChain";
1499 Vector s = new Vector();
1500 Vector c = new Vector();
1503 chains = new String[pdbentry.length][];
1505 if (sequence[pe] != null)
1507 for (int i = 0; i < sequence[pe].length; i++)
1509 s.addElement(sequence[pe][i]);
1510 if (chains[pe] != null)
1512 if (i < chains[pe].length)
1514 c.addElement(chains[pe][i]);
1518 c.addElement(nullChain);
1523 if (tchain != null && tchain.length > 0)
1525 c.addElement(nullChain);
1530 for (int i = 0; i < seq.length; i++)
1532 if (!s.contains(seq[i]))
1534 s.addElement(seq[i]);
1535 if (tchain != null && i < tchain.length)
1537 c.addElement(tchain[i] == null ? nullChain : tchain[i]);
1541 SequenceI[] tmp = new SequenceI[s.size()];
1546 String[] tch = new String[c.size()];
1548 for (int i = 0; i < tch.length; i++)
1550 if (tch[i] == nullChain)