2 * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)
3 * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 package jalview.appletgui;
23 import java.awt.event.*;
25 import jalview.datamodel.*;
26 import jalview.structure.*;
29 import org.jmol.api.*;
30 import org.jmol.adapter.smarter.SmarterJmolAdapter;
32 import org.jmol.popup.*;
33 import jalview.schemes.*;
35 public class AppletJmol extends EmbmenuFrame implements StructureListener,
36 JmolStatusListener, KeyListener, ActionListener, ItemListener
39 Menu fileMenu = new Menu("File");
41 Menu viewMenu = new Menu("View");
43 Menu coloursMenu = new Menu("Colours");
45 Menu chainMenu = new Menu("Show Chain");
47 Menu helpMenu = new Menu("Help");
49 MenuItem mappingMenuItem = new MenuItem("View Mapping");
51 CheckboxMenuItem seqColour = new CheckboxMenuItem("By Sequence", true);
53 MenuItem chain = new MenuItem("By Chain");
55 MenuItem charge = new MenuItem("Charge & Cysteine");
57 MenuItem zappo = new MenuItem("Zappo");
59 MenuItem taylor = new MenuItem("Taylor");
61 MenuItem hydro = new MenuItem("Hydrophobicity");
63 MenuItem helix = new MenuItem("Helix Propensity");
65 MenuItem strand = new MenuItem("Strand Propensity");
67 MenuItem turn = new MenuItem("Turn Propensity");
69 MenuItem buried = new MenuItem("Buried Index");
71 MenuItem user = new MenuItem("User Defined Colours");
73 MenuItem jmolHelp = new MenuItem("Jmol Help");
89 StructureSelectionManager ssm;
91 RenderPanel renderPanel;
95 String fileLoadingError;
101 boolean colourBySequence = true;
103 Vector atomsPicked = new Vector();
106 * datasource protocol for access to PDBEntry
108 String protocol = null;
110 public AppletJmol(PDBEntry pdbentry, SequenceI[] seq, String[] chains,
111 AlignmentPanel ap, String protocol)
115 this.chains = chains;
116 this.pdbentry = pdbentry;
117 this.protocol = protocol;
118 if (pdbentry.getId() == null || pdbentry.getId().length() < 1)
120 if (jalview.bin.JalviewLite.debug)
122 System.err.println("Setting PDB id for file " + pdbentry.getFile());
123 if (protocol.equals(AppletFormatAdapter.PASTE))
125 pdbentry.setId("PASTED PDB"
126 + (chains == null ? "_" : chains.toString()));
130 pdbentry.setId(pdbentry.getFile());
134 if (jalview.bin.JalviewLite.debug)
137 .println("AppletJmol: PDB ID is '" + pdbentry.getId() + "'");
140 String alreadyMapped = StructureSelectionManager
141 .getStructureSelectionManager().alreadyMappedToFile(
143 MCview.PDBfile reader = null;
144 if (alreadyMapped != null)
146 reader = StructureSelectionManager.getStructureSelectionManager()
147 .setMapping(seq, chains, pdbentry.getFile(), protocol);
148 // PROMPT USER HERE TO ADD TO NEW OR EXISTING VIEW?
149 // FOR NOW, LETS JUST OPEN A NEW WINDOW
151 MenuBar menuBar = new MenuBar();
152 menuBar.add(fileMenu);
153 fileMenu.add(mappingMenuItem);
154 menuBar.add(viewMenu);
155 mappingMenuItem.addActionListener(this);
156 viewMenu.add(chainMenu);
157 menuBar.add(coloursMenu);
158 menuBar.add(helpMenu);
160 charge.addActionListener(this);
161 hydro.addActionListener(this);
162 chain.addActionListener(this);
163 seqColour.addItemListener(this);
164 zappo.addActionListener(this);
165 taylor.addActionListener(this);
166 helix.addActionListener(this);
167 strand.addActionListener(this);
168 turn.addActionListener(this);
169 buried.addActionListener(this);
170 user.addActionListener(this);
172 jmolHelp.addActionListener(this);
174 coloursMenu.add(seqColour);
175 coloursMenu.add(chain);
176 coloursMenu.add(charge);
177 coloursMenu.add(zappo);
178 coloursMenu.add(taylor);
179 coloursMenu.add(hydro);
180 coloursMenu.add(helix);
181 coloursMenu.add(strand);
182 coloursMenu.add(turn);
183 coloursMenu.add(buried);
184 coloursMenu.add(user);
186 helpMenu.add(jmolHelp);
190 renderPanel = new RenderPanel();
191 embedMenuIfNeeded(renderPanel);
192 this.add(renderPanel, BorderLayout.CENTER);
193 viewer = JmolViewer.allocateViewer(renderPanel,
194 new SmarterJmolAdapter());
196 viewer.setAppletContext("jalview", ap.av.applet.getDocumentBase(),
197 ap.av.applet.getCodeBase(), null);
199 viewer.setJmolStatusListener(this);
201 jmolpopup = JmolPopup.newJmolPopup(viewer);
203 this.addWindowListener(new WindowAdapter()
205 public void windowClosing(WindowEvent evt)
211 if (pdbentry.getFile() != null)
213 // import structure data from pdbentry.getFile based on given protocol
214 if (protocol.equals(AppletFormatAdapter.PASTE))
216 loadInline(pdbentry.getFile());
218 else if (protocol.equals(AppletFormatAdapter.FILE)
219 || protocol.equals(AppletFormatAdapter.URL))
221 viewer.openFile(pdbentry.getFile());
225 // probably CLASSLOADER based datasource..
226 // Try and get a reader on the datasource, and pass that to Jmol
229 java.io.Reader freader = null;
232 if (jalview.bin.JalviewLite.debug)
235 .println("AppletJmol:Trying to reuse existing PDBfile IO parser.");
237 // re-use the one we opened earlier
238 freader = reader.getReader();
242 if (jalview.bin.JalviewLite.debug)
245 .println("AppletJmol:Creating new PDBfile IO parser.");
247 FileParse fp = new FileParse(pdbentry.getFile(), protocol);
249 // reader = new MCview.PDBfile(fp);
250 // could set ID, etc.
251 // if (!reader.isValid())
253 // throw new Exception("Invalid datasource.
254 // "+reader.getWarningMessage());
257 freader = fp.getReader();
262 "Invalid datasource. Could not obtain Reader.");
264 viewer.openReader(pdbentry.getFile(), pdbentry.getId(), freader);
265 } catch (Exception e)
268 System.err.println("Couldn't access pdbentry id="
269 + pdbentry.getId() + " and file=" + pdbentry.getFile()
270 + " using protocol=" + protocol);
276 jalview.bin.JalviewLite.addFrame(this, "Jmol", 400, 400);
279 public void loadInline(String string)
282 viewer.openStringInline(string);
285 void setChainMenuItems(Vector chains)
287 chainMenu.removeAll();
289 MenuItem menuItem = new MenuItem("All");
290 menuItem.addActionListener(this);
292 chainMenu.add(menuItem);
294 CheckboxMenuItem menuItemCB;
295 for (int c = 0; c < chains.size(); c++)
297 menuItemCB = new CheckboxMenuItem(chains.elementAt(c).toString(),
299 menuItemCB.addItemListener(this);
300 chainMenu.add(menuItemCB);
304 boolean allChainsSelected = false;
308 StringBuffer cmd = new StringBuffer();
309 for (int i = 0; i < chainMenu.getItemCount(); i++)
311 if (chainMenu.getItem(i) instanceof CheckboxMenuItem)
313 CheckboxMenuItem item = (CheckboxMenuItem) chainMenu.getItem(i);
315 cmd.append(":" + item.getLabel() + " or ");
319 if (cmd.length() > 0)
320 cmd.setLength(cmd.length() - 4);
323 .evalString("select *;restrict " + cmd + ";cartoon;center "
329 viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
330 viewer.evalStringQuiet("zap");
331 viewer.setJmolStatusListener(null);
334 // We'll need to find out what other
335 // listeners need to be shut down in Jmol
336 StructureSelectionManager.getStructureSelectionManager()
337 .removeStructureViewerListener(this, pdbentry.getId());
339 this.setVisible(false);
342 public void actionPerformed(ActionEvent evt)
344 if (evt.getSource() == mappingMenuItem)
346 jalview.appletgui.CutAndPasteTransfer cap = new jalview.appletgui.CutAndPasteTransfer(
348 Frame frame = new Frame();
351 jalview.bin.JalviewLite.addFrame(frame, "PDB - Sequence Mapping",
353 cap.setText(StructureSelectionManager.getStructureSelectionManager()
354 .printMapping(pdbentry.getFile()));
356 else if (evt.getSource() == charge)
358 colourBySequence = false;
359 seqColour.setState(false);
361 .evalStringQuiet("select *;color white;select ASP,GLU;color red;"
362 + "select LYS,ARG;color blue;select CYS;color yellow");
365 else if (evt.getSource() == chain)
367 colourBySequence = false;
368 seqColour.setState(false);
369 viewer.evalStringQuiet("select *;color chain");
371 else if (evt.getSource() == zappo)
373 setJalviewColourScheme(new ZappoColourScheme());
375 else if (evt.getSource() == taylor)
377 setJalviewColourScheme(new TaylorColourScheme());
379 else if (evt.getSource() == hydro)
381 setJalviewColourScheme(new HydrophobicColourScheme());
383 else if (evt.getSource() == helix)
385 setJalviewColourScheme(new HelixColourScheme());
387 else if (evt.getSource() == strand)
389 setJalviewColourScheme(new StrandColourScheme());
391 else if (evt.getSource() == turn)
393 setJalviewColourScheme(new TurnColourScheme());
395 else if (evt.getSource() == buried)
397 setJalviewColourScheme(new BuriedColourScheme());
399 else if (evt.getSource() == user)
401 new UserDefinedColours(this);
403 else if (evt.getSource() == jmolHelp)
407 ap.av.applet.getAppletContext().showDocument(
409 "http://jmol.sourceforge.net/docs/JmolUserGuide/"),
411 } catch (java.net.MalformedURLException ex)
417 allChainsSelected = true;
418 for (int i = 0; i < chainMenu.getItemCount(); i++)
420 if (chainMenu.getItem(i) instanceof CheckboxMenuItem)
421 ((CheckboxMenuItem) chainMenu.getItem(i)).setState(true);
424 allChainsSelected = false;
428 public void setJalviewColourScheme(ColourSchemeI cs)
430 colourBySequence = false;
431 seqColour.setState(false);
440 Enumeration en = ResidueProperties.aa3Hash.keys();
441 StringBuffer command = new StringBuffer("select *;color white;");
442 while (en.hasMoreElements())
444 res = en.nextElement().toString();
445 index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
449 col = cs.findColour(ResidueProperties.aa[index].charAt(0));
451 command.append("select " + res + ";color[" + col.getRed() + ","
452 + col.getGreen() + "," + col.getBlue() + "];");
455 viewer.evalStringQuiet(command.toString());
458 public void itemStateChanged(ItemEvent evt)
460 if (evt.getSource() == seqColour)
463 colourBySequence = seqColour.getState();
464 colourBySequence(ap);
466 else if (!allChainsSelected)
470 public void keyPressed(KeyEvent evt)
472 if (evt.getKeyCode() == KeyEvent.VK_ENTER && scriptWindow.isVisible())
474 viewer.evalString(inputLine.getText());
475 history.append("\n$ " + inputLine.getText());
476 inputLine.setText("");
481 public void keyTyped(KeyEvent evt)
485 public void keyReleased(KeyEvent evt)
489 // ////////////////////////////////
490 // /StructureListener
491 public String getPdbFile()
498 public void mouseOverStructure(int atomIndex, String strInfo)
502 int chainSeparator = strInfo.indexOf(":");
504 if (chainSeparator == -1)
505 chainSeparator = strInfo.indexOf(".");
507 pdbResNum = Integer.parseInt(strInfo.substring(
508 strInfo.indexOf("]") + 1, chainSeparator));
512 if (strInfo.indexOf(":") > -1)
513 chainId = strInfo.substring(strInfo.indexOf(":") + 1, strInfo
520 if (lastMessage == null || !lastMessage.equals(strInfo))
521 ssm.mouseOverStructure(pdbResNum, chainId, pdbentry.getFile());
523 lastMessage = strInfo;
526 StringBuffer resetLastRes = new StringBuffer();
528 StringBuffer eval = new StringBuffer();
530 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
533 if (!pdbfile.equals(pdbentry.getFile()))
536 if (resetLastRes.length() > 0)
538 viewer.evalStringQuiet(resetLastRes.toString());
542 eval.append("select " + pdbResNum);
544 resetLastRes.setLength(0);
545 resetLastRes.append("select " + pdbResNum);
548 resetLastRes.append(":");
549 if (!chain.equals(" "))
552 resetLastRes.append(chain);
555 eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
557 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
558 + " and not hetero; spacefill 0;");
560 eval.append("spacefill 200;select none");
562 viewer.evalStringQuiet(eval.toString());
566 public void updateColours(Object source)
568 colourBySequence((AlignmentPanel) source);
571 // End StructureListener
572 // //////////////////////////
574 public Color getColour(int atomIndex, int pdbResNum, String chain,
577 if (!pdbfile.equals(pdbentry.getFile()))
580 return new Color(viewer.getAtomArgb(atomIndex));
585 FeatureRenderer fr = null;
587 public void colourBySequence(AlignmentPanel sourceap)
591 if (!colourBySequence)
594 StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
596 if (mapping.length < 1)
599 SequenceRenderer sr = new SequenceRenderer(ap.av);
601 boolean showFeatures = false;
603 if (ap.av.showSequenceFeatures)
608 fr = new jalview.appletgui.FeatureRenderer(ap.av);
611 fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer());
614 StringBuffer command = new StringBuffer();
617 for (int s = 0; s < sequence.length; s++)
619 for (int sp, m = 0; m < mapping.length; m++)
621 if (mapping[m].getSequence() == sequence[s]
622 && (sp = ap.av.alignment.findIndex(sequence[s])) > -1)
624 SequenceI asp = ap.av.alignment.getSequenceAt(sp);
625 for (int r = 0; r < asp.getLength(); r++)
627 // no mapping to gaps in sequence
628 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
632 int pos = mapping[m].getPDBResNum(asp.findPosition(r));
634 if (pos < 1 || pos == lastPos)
639 Color col = sr.getResidueBoxColour(sequence[s], r);
642 col = fr.findFeatureColour(col, sequence[s], r);
644 if (command.toString().endsWith(
645 ":" + mapping[m].getChain() + ";color[" + col.getRed()
646 + "," + col.getGreen() + "," + col.getBlue()
649 command = condenseCommand(command.toString(), pos);
653 command.append(";select " + pos);
655 if (!mapping[m].getChain().equals(" "))
657 command.append(":" + mapping[m].getChain());
660 command.append(";color[" + col.getRed() + "," + col.getGreen()
661 + "," + col.getBlue() + "]");
668 if (lastCommand == null || !lastCommand.equals(command.toString()))
670 viewer.evalStringQuiet(command.toString());
672 lastCommand = command.toString();
675 StringBuffer condenseCommand(String command, int pos)
678 StringBuffer sb = new StringBuffer(command.substring(0, command
679 .lastIndexOf("select") + 7));
681 command = command.substring(sb.length());
685 if (command.indexOf("-") > -1)
687 start = command.substring(0, command.indexOf("-"));
691 start = command.substring(0, command.indexOf(":"));
694 sb.append(start + "-" + pos + command.substring(command.indexOf(":")));
699 // ///////////////////////////////
700 // JmolStatusListener
702 public String eval(String strEval)
704 // System.out.println(strEval);
705 // "# 'eval' is implemented only for the applet.";
709 public void createImage(String file, String type, int quality)
713 public void setCallbackFunction(String callbackType,
714 String callbackFunction)
718 public void notifyFileLoaded(String fullPathName, String fileName,
719 String modelName, Object clientFile, String errorMsg)
721 if (errorMsg != null)
723 fileLoadingError = errorMsg;
728 fileLoadingError = null;
730 if (fileName != null)
733 jmolpopup.updateComputedMenus();
735 .evalStringQuiet("select backbone;restrict;cartoon;wireframe off;spacefill off");
737 ssm = StructureSelectionManager.getStructureSelectionManager();
741 pdb = ssm.setMapping(sequence, chains, pdbentry.getFile(),
742 AppletFormatAdapter.PASTE);
743 pdbentry.setFile("INLINE" + pdb.id);
747 // TODO: Jmol can in principle retrieve from CLASSLOADER but this needs
748 // to be tested. See mantis bug
749 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
751 pdb = ssm.setMapping(sequence, chains, pdbentry.getFile(),
752 AppletFormatAdapter.URL);
756 pdbentry.setId(pdb.id);
758 ssm.addStructureViewerListener(this);
760 Vector chains = new Vector();
761 for (int i = 0; i < pdb.chains.size(); i++)
763 chains.addElement(((MCview.PDBChain) pdb.chains.elementAt(i)).id);
765 setChainMenuItems(chains);
767 colourBySequence(ap);
769 StringBuffer title = new StringBuffer(sequence[0].getName() + ":"
772 if (pdbentry.getProperty() != null)
774 if (pdbentry.getProperty().get("method") != null)
776 title.append(" Method: ");
777 title.append(pdbentry.getProperty().get("method"));
779 if (pdbentry.getProperty().get("chains") != null)
781 title.append(" Chain:");
782 title.append(pdbentry.getProperty().get("chains"));
786 this.setTitle(title.toString());
793 public void notifyFrameChanged(int frameNo)
795 boolean isAnimationRunning = (frameNo <= -2);
798 public void notifyScriptStart(String statusMessage, String additionalInfo)
802 public void sendConsoleEcho(String strEcho)
804 if (scriptWindow == null)
807 history.append("\n" + strEcho);
810 public void sendConsoleMessage(String strStatus)
812 if (history != null && strStatus != null
813 && !strStatus.equals("Script completed"))
815 history.append("\n" + strStatus);
819 public void notifyScriptTermination(String strStatus, int msWalltime)
823 public void handlePopupMenu(int x, int y)
825 jmolpopup.show(x, y);
828 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
830 notifyAtomPicked(iatom, strMeasure);
833 public void notifyNewDefaultModeMeasurement(int count, String strInfo)
837 public void notifyAtomPicked(int atomIndex, String strInfo)
840 int chainSeparator = strInfo.indexOf(":");
842 if (chainSeparator == -1)
843 chainSeparator = strInfo.indexOf(".");
845 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
848 if (strInfo.indexOf(":") > -1)
849 picked += strInfo.substring(strInfo.indexOf(":") + 1, strInfo
854 if (!atomsPicked.contains(picked))
856 viewer.evalString("select " + picked + ";label %n %r:%c");
857 atomsPicked.addElement(picked);
861 viewer.evalString("select " + picked + ";label off");
862 atomsPicked.removeElement(picked);
866 public void notifyAtomHovered(int atomIndex, String strInfo)
868 mouseOverStructure(atomIndex, strInfo);
871 public void sendSyncScript(String script, String appletName)
875 public void showUrl(String url)
879 ap.av.applet.getAppletContext().showDocument(new java.net.URL(url),
881 } catch (java.net.MalformedURLException ex)
886 public void showConsole(boolean showConsole)
888 if (scriptWindow == null)
890 scriptWindow = new Panel(new BorderLayout());
891 inputLine = new TextField();
892 history = new TextArea(5, 40);
893 scriptWindow.add(history, BorderLayout.CENTER);
894 scriptWindow.add(inputLine, BorderLayout.SOUTH);
895 add(scriptWindow, BorderLayout.SOUTH);
896 scriptWindow.setVisible(false);
897 history.setEditable(false);
898 inputLine.addKeyListener(this);
901 scriptWindow.setVisible(!scriptWindow.isVisible());
905 public float functionXY(String functionName, int x, int y)
910 // /End JmolStatusListener
911 // /////////////////////////////
913 class RenderPanel extends Panel
915 Dimension currentSize = new Dimension();
917 Rectangle rectClip = new Rectangle();
919 public void update(Graphics g)
924 public void paint(Graphics g)
926 currentSize = this.getSize();
927 rectClip = g.getClipBounds();
931 g.setColor(Color.black);
932 g.fillRect(0, 0, currentSize.width, currentSize.height);
933 g.setColor(Color.white);
934 g.setFont(new Font("Verdana", Font.BOLD, 14));
935 g.drawString("Retrieving PDB data....", 20, currentSize.height / 2);
939 viewer.renderScreenImage(g, currentSize, rectClip);