2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3 * Copyright (C) 2008 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);
547 if (!chain.equals(" "))
549 eval.append(":" + chain);
550 resetLastRes.append(":" + chain);
553 eval.append(";wireframe 100;" + eval.toString() + ".CA;");
555 resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
556 + ".CA;spacefill 0;");
558 eval.append("spacefill 200;select none");
560 viewer.evalStringQuiet(eval.toString());
564 public void updateColours(Object source)
566 colourBySequence((AlignmentPanel) source);
569 // End StructureListener
570 // //////////////////////////
572 public Color getColour(int atomIndex, int pdbResNum, String chain,
575 if (!pdbfile.equals(pdbentry.getFile()))
578 return new Color(viewer.getAtomArgb(atomIndex));
583 FeatureRenderer fr = null;
585 public void colourBySequence(AlignmentPanel sourceap)
589 if (!colourBySequence)
592 StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
594 if (mapping.length < 1)
597 SequenceRenderer sr = new SequenceRenderer(ap.av);
599 boolean showFeatures = false;
601 if (ap.av.showSequenceFeatures)
606 fr = new jalview.appletgui.FeatureRenderer(ap.av);
609 fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer());
612 StringBuffer command = new StringBuffer();
615 for (int s = 0; s < sequence.length; s++)
617 for (int sp, m = 0; m < mapping.length; m++)
619 if (mapping[m].getSequence() == sequence[s]
620 && (sp = ap.av.alignment.findIndex(sequence[s])) > -1)
622 SequenceI asp = ap.av.alignment.getSequenceAt(sp);
623 for (int r = 0; r < asp.getLength(); r++)
625 // no mapping to gaps in sequence
626 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
630 int pos = mapping[m].getPDBResNum(asp.findPosition(r));
632 if (pos < 1 || pos == lastPos)
637 Color col = sr.getResidueBoxColour(sequence[s], r);
640 col = fr.findFeatureColour(col, sequence[s], r);
642 if (command.toString().endsWith(
643 ":" + mapping[m].getChain() + ";color[" + col.getRed()
644 + "," + col.getGreen() + "," + col.getBlue()
647 command = condenseCommand(command.toString(), pos);
651 command.append(";select " + pos);
653 if (!mapping[m].getChain().equals(" "))
655 command.append(":" + mapping[m].getChain());
658 command.append(";color[" + col.getRed() + "," + col.getGreen()
659 + "," + col.getBlue() + "]");
666 if (lastCommand == null || !lastCommand.equals(command.toString()))
668 viewer.evalStringQuiet(command.toString());
670 lastCommand = command.toString();
673 StringBuffer condenseCommand(String command, int pos)
676 StringBuffer sb = new StringBuffer(command.substring(0, command
677 .lastIndexOf("select") + 7));
679 command = command.substring(sb.length());
683 if (command.indexOf("-") > -1)
685 start = command.substring(0, command.indexOf("-"));
689 start = command.substring(0, command.indexOf(":"));
692 sb.append(start + "-" + pos + command.substring(command.indexOf(":")));
697 // ///////////////////////////////
698 // JmolStatusListener
700 public String eval(String strEval)
702 // System.out.println(strEval);
703 // "# 'eval' is implemented only for the applet.";
707 public void createImage(String file, String type, int quality)
711 public void setCallbackFunction(String callbackType,
712 String callbackFunction)
716 public void notifyFileLoaded(String fullPathName, String fileName,
717 String modelName, Object clientFile, String errorMsg)
719 if (errorMsg != null)
721 fileLoadingError = errorMsg;
726 fileLoadingError = null;
728 if (fileName != null)
731 jmolpopup.updateComputedMenus();
733 .evalStringQuiet("select backbone;restrict;cartoon;wireframe off;spacefill off");
735 ssm = StructureSelectionManager.getStructureSelectionManager();
739 pdb = ssm.setMapping(sequence, chains, pdbentry.getFile(),
740 AppletFormatAdapter.PASTE);
741 pdbentry.setFile("INLINE" + pdb.id);
745 // TODO: Jmol can in principle retrieve from CLASSLOADER but this needs
746 // to be tested. See mantis bug
747 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
749 pdb = ssm.setMapping(sequence, chains, pdbentry.getFile(),
750 AppletFormatAdapter.URL);
754 pdbentry.setId(pdb.id);
756 ssm.addStructureViewerListener(this);
758 Vector chains = new Vector();
759 for (int i = 0; i < pdb.chains.size(); i++)
761 chains.addElement(((MCview.PDBChain) pdb.chains.elementAt(i)).id);
763 setChainMenuItems(chains);
765 colourBySequence(ap);
767 StringBuffer title = new StringBuffer(sequence[0].getName() + ":"
770 if (pdbentry.getProperty() != null)
772 if (pdbentry.getProperty().get("method") != null)
774 title.append(" Method: ");
775 title.append(pdbentry.getProperty().get("method"));
777 if (pdbentry.getProperty().get("chains") != null)
779 title.append(" Chain:");
780 title.append(pdbentry.getProperty().get("chains"));
784 this.setTitle(title.toString());
791 public void notifyFrameChanged(int frameNo)
793 boolean isAnimationRunning = (frameNo <= -2);
796 public void notifyScriptStart(String statusMessage, String additionalInfo)
800 public void sendConsoleEcho(String strEcho)
802 if (scriptWindow == null)
805 history.append("\n" + strEcho);
808 public void sendConsoleMessage(String strStatus)
810 if (history != null && strStatus != null
811 && !strStatus.equals("Script completed"))
813 history.append("\n" + strStatus);
817 public void notifyScriptTermination(String strStatus, int msWalltime)
821 public void handlePopupMenu(int x, int y)
823 jmolpopup.show(x, y);
826 public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
828 notifyAtomPicked(iatom, strMeasure);
831 public void notifyNewDefaultModeMeasurement(int count, String strInfo)
835 public void notifyAtomPicked(int atomIndex, String strInfo)
838 int chainSeparator = strInfo.indexOf(":");
840 if (chainSeparator == -1)
841 chainSeparator = strInfo.indexOf(".");
843 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
846 if (strInfo.indexOf(":") > -1)
847 picked += strInfo.substring(strInfo.indexOf(":") + 1, strInfo
852 if (!atomsPicked.contains(picked))
854 viewer.evalString("select " + picked + ";label %n %r:%c");
855 atomsPicked.addElement(picked);
859 viewer.evalString("select " + picked + ";label off");
860 atomsPicked.removeElement(picked);
864 public void notifyAtomHovered(int atomIndex, String strInfo)
866 mouseOverStructure(atomIndex, strInfo);
869 public void sendSyncScript(String script, String appletName)
873 public void showUrl(String url)
877 ap.av.applet.getAppletContext().showDocument(new java.net.URL(url),
879 } catch (java.net.MalformedURLException ex)
884 public void showConsole(boolean showConsole)
886 if (scriptWindow == null)
888 scriptWindow = new Panel(new BorderLayout());
889 inputLine = new TextField();
890 history = new TextArea(5, 40);
891 scriptWindow.add(history, BorderLayout.CENTER);
892 scriptWindow.add(inputLine, BorderLayout.SOUTH);
893 add(scriptWindow, BorderLayout.SOUTH);
894 scriptWindow.setVisible(false);
895 history.setEditable(false);
896 inputLine.addKeyListener(this);
899 scriptWindow.setVisible(!scriptWindow.isVisible());
903 public float functionXY(String functionName, int x, int y)
908 // /End JmolStatusListener
909 // /////////////////////////////
911 class RenderPanel extends Panel
913 Dimension currentSize = new Dimension();
915 Rectangle rectClip = new Rectangle();
917 public void update(Graphics g)
922 public void paint(Graphics g)
924 currentSize = this.getSize();
925 rectClip = g.getClipBounds();
929 g.setColor(Color.black);
930 g.fillRect(0, 0, currentSize.width, currentSize.height);
931 g.setColor(Color.white);
932 g.setFont(new Font("Verdana", Font.BOLD, 14));
933 g.drawString("Retrieving PDB data....", 20, currentSize.height / 2);
937 viewer.renderScreenImage(g, currentSize, rectClip);