jmol added
[jalview.git] / src / jalview / appletgui / AppletJmol.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 \r
20 package jalview.appletgui;\r
21 \r
22 import java.util.*;\r
23 import java.awt.*;\r
24 import java.awt.event.*;\r
25 \r
26 import jalview.datamodel.*;\r
27 import jalview.structure.*;\r
28 import jalview.io.*;\r
29 \r
30 import org.jmol.api.*;\r
31 import org.jmol.adapter.smarter.SmarterJmolAdapter;\r
32 import org.jmol.popup.*;\r
33 \r
34 \r
35 public class AppletJmol extends Frame\r
36     implements  StructureListener, JmolStatusListener,\r
37     KeyListener, ActionListener, ItemListener\r
38 \r
39 {\r
40   Menu fileMenu = new Menu("File");\r
41   Menu viewMenu = new Menu("View");\r
42   Menu chainMenu = new Menu("Show Chain");\r
43   MenuItem mappingMenuItem = new MenuItem("View Mapping");\r
44 \r
45   JmolViewer viewer;\r
46   JmolPopup jmolpopup;\r
47 \r
48   Panel scriptWindow;\r
49   TextField inputLine;\r
50   TextArea history;\r
51   SequenceI[] sequence;\r
52   StructureSelectionManager ssm;\r
53   RenderPanel renderPanel;\r
54   AlignmentPanel ap;\r
55   String fileLoadingError;\r
56   boolean loadedInline;\r
57   PDBEntry pdbentry;\r
58 \r
59   public AppletJmol(PDBEntry pdbentry,\r
60                     SequenceI[] seq,\r
61                     AlignmentPanel ap,\r
62                     String protocol)\r
63   {\r
64     this.ap = ap;\r
65     this.sequence = seq;\r
66     this.pdbentry = pdbentry;\r
67 \r
68    String alreadyMapped = StructureSelectionManager\r
69         .getStructureSelectionManager()\r
70         .alreadyMappedToFile(pdbentry.getId());\r
71 \r
72     if (alreadyMapped != null)\r
73     {\r
74        StructureSelectionManager.getStructureSelectionManager()\r
75             .setMapping(seq, pdbentry.getFile(), protocol);\r
76         return;\r
77     }\r
78 \r
79     renderPanel = new RenderPanel();\r
80 \r
81     this.add(renderPanel, BorderLayout.CENTER);\r
82 \r
83     viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter());\r
84 \r
85     viewer.setAppletContext("jalview",\r
86                        ap.av.applet.getDocumentBase(),\r
87                             ap.av.applet.getCodeBase(),\r
88                             null);\r
89 \r
90     viewer.setJmolStatusListener(this);\r
91 \r
92     jmolpopup = JmolPopup.newJmolPopup(viewer);\r
93 \r
94     this.addWindowListener(new WindowAdapter()\r
95         {\r
96           public void windowClosing(WindowEvent evt)\r
97           {\r
98             closeViewer();\r
99           }\r
100         });\r
101 \r
102     MenuBar menuBar = new MenuBar();\r
103     menuBar.add(fileMenu);\r
104     fileMenu.add(mappingMenuItem);\r
105     menuBar.add(viewMenu);\r
106     mappingMenuItem.addActionListener(this);\r
107     viewMenu.add(chainMenu);\r
108     this.setMenuBar(menuBar);\r
109 \r
110     if(pdbentry.getFile()!=null)\r
111     {\r
112       if (protocol.equals(AppletFormatAdapter.PASTE))\r
113         loadInline(pdbentry.getFile());\r
114       else\r
115           viewer.openFile(pdbentry.getFile());\r
116     }\r
117 \r
118     this.setBounds(400, 400, 400, 400);\r
119 \r
120     this.setVisible(true);\r
121   }\r
122 \r
123   public void loadInline(String string)\r
124   {\r
125     loadedInline = true;\r
126     viewer.openStringInline(string);\r
127   }\r
128 \r
129 \r
130   void setChainMenuItems(Vector chains)\r
131   {\r
132     chainMenu.removeAll();\r
133 \r
134     MenuItem menuItem = new MenuItem("All");\r
135     menuItem.addActionListener(this);\r
136 \r
137     chainMenu.add(menuItem);\r
138 \r
139     CheckboxMenuItem menuItemCB;\r
140     for (int c = 0; c < chains.size(); c++)\r
141     {\r
142       menuItemCB = new CheckboxMenuItem(chains.elementAt(c).toString(), true);\r
143       menuItemCB.addItemListener(this);\r
144       chainMenu.add(menuItemCB);\r
145     }\r
146   }\r
147 \r
148   boolean allChainsSelected = false;\r
149   void centerViewer()\r
150   {\r
151     StringBuffer cmd = new StringBuffer();\r
152     for (int i = 0; i < chainMenu.getItemCount(); i++)\r
153     {\r
154       if (chainMenu.getItem(i) instanceof CheckboxMenuItem)\r
155       {\r
156         CheckboxMenuItem item = (CheckboxMenuItem) chainMenu.getItem(i);\r
157         if (item.getState())\r
158           cmd.append(":" + item.getLabel() + " or ");\r
159       }\r
160     }\r
161 \r
162     if (cmd.length() > 0)\r
163       cmd.setLength(cmd.length() - 4);\r
164 \r
165     viewer.evalString("select *;restrict "\r
166                       + cmd + ";cartoon;center " + cmd);\r
167   }\r
168 \r
169 \r
170   void closeViewer()\r
171   {\r
172     viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);\r
173     viewer.evalStringQuiet("zap");\r
174     viewer.setJmolStatusListener(null);\r
175     viewer = null;\r
176 \r
177     //We'll need to find out what other\r
178     // listeners need to be shut down in Jmol\r
179     StructureSelectionManager\r
180         .getStructureSelectionManager()\r
181         .removeStructureViewerListener(this, pdbentry.getId());\r
182 \r
183     this.setVisible(false);\r
184   }\r
185 \r
186   public void actionPerformed(ActionEvent evt)\r
187   {\r
188     if(evt.getSource()==mappingMenuItem)\r
189     {\r
190       jalview.appletgui.CutAndPasteTransfer cap\r
191           = new jalview.appletgui.CutAndPasteTransfer(false, null);\r
192       Frame frame = new Frame();\r
193       frame.add(cap);\r
194 \r
195       jalview.bin.JalviewLite.addFrame(frame, "PDB - Sequence Mapping", 550,\r
196                                        600);\r
197       cap.setText(\r
198           StructureSelectionManager.getStructureSelectionManager().printMapping(\r
199               pdbentry.getFile())\r
200           );\r
201     }\r
202     else\r
203     {\r
204       allChainsSelected = true;\r
205       for (int i = 0; i < chainMenu.getItemCount(); i++)\r
206       {\r
207         if (chainMenu.getItem(i) instanceof CheckboxMenuItem)\r
208           ( (CheckboxMenuItem) chainMenu.getItem(i)).setState(true);\r
209       }\r
210       centerViewer();\r
211       allChainsSelected = false;\r
212     }\r
213   }\r
214 \r
215   public void itemStateChanged(ItemEvent evt)\r
216   {\r
217     if (!allChainsSelected)\r
218       centerViewer();\r
219   }\r
220 \r
221   public void keyPressed(KeyEvent evt)\r
222   {\r
223     if (evt.getKeyCode() == KeyEvent.VK_ENTER\r
224         && scriptWindow.isVisible())\r
225     {\r
226       viewer.evalString(inputLine.getText());\r
227 \r
228       history.append("\n"+inputLine.getText());\r
229 \r
230       inputLine.setText("");\r
231     }\r
232 \r
233   }\r
234 \r
235   public void keyTyped(KeyEvent evt)\r
236   {  }\r
237 \r
238   public void keyReleased(KeyEvent evt){}\r
239 \r
240   //////////////////////////////////\r
241   ///StructureListener\r
242   public String getPdbFile()\r
243   {\r
244     return "???";\r
245   }\r
246 \r
247 \r
248 \r
249   String lastMessage;\r
250   public void mouseOverStructure(int atomIndex, String strInfo)\r
251   {\r
252       int pdbResNum = Integer.parseInt(\r
253           strInfo.substring(strInfo.indexOf("]")+ 1, strInfo.indexOf(":")));\r
254 \r
255       String chainId = strInfo.substring\r
256           (strInfo.indexOf(":"), strInfo.indexOf("."));\r
257 \r
258       if (chainId != null)\r
259         chainId = chainId.substring(1, chainId.length());\r
260       else\r
261       {\r
262         chainId = " ";\r
263       }\r
264 \r
265       if (lastMessage == null || !lastMessage.equals(strInfo))\r
266         ssm.mouseOverStructure(pdbResNum, chainId, pdbentry.getFile());\r
267 \r
268       lastMessage = strInfo;\r
269   }\r
270 \r
271   StringBuffer resetLastRes = new StringBuffer();\r
272   StringBuffer eval = new StringBuffer();\r
273 \r
274   public void highlightAtom(int atomIndex, int pdbResNum, String chain, String pdbfile)\r
275   {\r
276     if (!pdbfile.equals(pdbentry.getFile()))\r
277       return;\r
278 \r
279     if (resetLastRes.length() > 0)\r
280     {\r
281       viewer.evalStringQuiet(resetLastRes.toString());\r
282     }\r
283 \r
284     eval.setLength(0);\r
285     eval.append("select " + pdbResNum);\r
286 \r
287     resetLastRes.setLength(0);\r
288     resetLastRes.append("select " + pdbResNum);\r
289 \r
290     if (!chain.equals(" "))\r
291     {\r
292       eval.append(":" + chain);\r
293       resetLastRes.append(":" + chain);\r
294     }\r
295 \r
296     eval.append(";color gold;wireframe 100");\r
297 \r
298     Color col = new Color(viewer.getAtomArgb(atomIndex));\r
299 \r
300     resetLastRes.append(";color["\r
301                         + col.getRed() + ","\r
302                         + col.getGreen() + ","\r
303                         + col.getBlue() + "];wireframe 0");\r
304 \r
305     viewer.evalStringQuiet(eval.toString());\r
306 \r
307   }\r
308 \r
309   public void updateColours(Object source)\r
310   {\r
311     colourBySequence( (AlignmentPanel) source);\r
312   }\r
313 \r
314 //End StructureListener\r
315 ////////////////////////////\r
316 \r
317   FeatureRenderer fr;\r
318   public void colourBySequence(AlignmentPanel ap)\r
319   {\r
320     StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());\r
321 \r
322     if (mapping.length < 1)\r
323       return;\r
324 \r
325     SequenceRenderer sr = ap.seqPanel.seqCanvas.getSequenceRenderer();\r
326 \r
327     boolean showFeatures = false;\r
328     if (ap.av.showSequenceFeatures)\r
329     {\r
330       showFeatures = true;\r
331       if (fr == null)\r
332       {\r
333         fr = new jalview.appletgui.FeatureRenderer(ap.av);\r
334       }\r
335 \r
336       fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer());\r
337     }\r
338 \r
339     StringBuffer command = new StringBuffer();\r
340 \r
341     for (int s = 0; s < sequence.length; s++)\r
342     {\r
343       for (int m = 0; m < mapping.length; m++)\r
344       {\r
345         if (mapping[m].getSequence() == sequence[s])\r
346         {\r
347           for (int r = 0; r < sequence[s].getLength(); r++)\r
348           {\r
349             int pos = mapping[m].getPDBResNum(\r
350                 sequence[s].findPosition(r));\r
351 \r
352             if (pos < 1)\r
353               continue;\r
354 \r
355             command.append(";select " + pos);\r
356 \r
357             if (!mapping[m].getChain().equals(" "))\r
358             {\r
359               command.append(":" + mapping[m].getChain());\r
360             }\r
361 \r
362             Color col = sr.getResidueBoxColour(sequence[s], r);\r
363 \r
364             if (showFeatures)\r
365               col = fr.findFeatureColour(col, sequence[s], r);\r
366 \r
367             command.append("; color ["\r
368                            + col.getRed() + ","\r
369                            + col.getGreen() + ","\r
370                            + col.getBlue() + "]");\r
371 \r
372           }\r
373         }\r
374       }\r
375     }\r
376 \r
377     viewer.evalStringQuiet(command.toString());\r
378   }\r
379 \r
380   /////////////////////////////////\r
381   //JmolStatusListener\r
382 \r
383   public String eval(String strEval)\r
384   {\r
385    // System.out.println(strEval);\r
386    //"# 'eval' is implemented only for the applet.";\r
387     return null;\r
388   }\r
389 \r
390   public void createImage(String file, String type, int quality)\r
391   {\r
392     System.out.println("JMOL CREATE IMAGE");\r
393   }\r
394 \r
395   public void setCallbackFunction(String callbackType,\r
396                                   String callbackFunction)\r
397   {}\r
398 \r
399   public void notifyFileLoaded(String fullPathName, String fileName,\r
400                                String modelName, Object clientFile,\r
401                                String errorMsg)\r
402   {\r
403     if(errorMsg!=null)\r
404     {\r
405       fileLoadingError = errorMsg;\r
406       repaint();\r
407       return;\r
408     }\r
409 \r
410     fileLoadingError = null;\r
411 \r
412     if (fileName != null)\r
413     {\r
414       //FILE LOADED OK\r
415       jmolpopup.updateComputedMenus();\r
416             viewer.evalStringQuiet(\r
417           "select backbone;restrict;cartoon;wireframe off;spacefill off");\r
418 \r
419       ssm = StructureSelectionManager.getStructureSelectionManager();\r
420 \r
421       MCview.PDBfile pdb;\r
422       if (loadedInline)\r
423       {\r
424         pdb = ssm.setMapping(sequence,\r
425                                 pdbentry.getFile(),\r
426                                 AppletFormatAdapter.PASTE);\r
427         pdbentry.setFile("INLINE"+pdb.id);\r
428 \r
429       }\r
430       else\r
431       {\r
432          pdb = ssm.setMapping(sequence,\r
433                               pdbentry.getFile(),\r
434                               AppletFormatAdapter.URL);\r
435       }\r
436 \r
437       pdbentry.setId(pdb.id);\r
438 \r
439       ssm.addStructureViewerListener(this);\r
440 \r
441       Vector chains = new Vector();\r
442       for (int i = 0; i < pdb.chains.size(); i++)\r
443       {\r
444         chains.addElement( ( (MCview.PDBChain) pdb.chains.elementAt(i)).id);\r
445       }\r
446       setChainMenuItems(chains);\r
447 \r
448       colourBySequence(ap);\r
449 \r
450       StringBuffer title = new StringBuffer(sequence[0].getName() + ":" +\r
451                                             pdbentry.getId());\r
452 \r
453       if (pdbentry.getProperty() != null)\r
454       {\r
455         if (pdbentry.getProperty().get("method") != null)\r
456         {\r
457           title.append(" Method: ");\r
458           title.append(pdbentry.getProperty().get("method"));\r
459         }\r
460         if (pdbentry.getProperty().get("chains") != null)\r
461         {\r
462           title.append(" Chain:");\r
463           title.append(pdbentry.getProperty().get("chains"));\r
464         }\r
465       }\r
466 \r
467       this.setTitle(title.toString());\r
468 \r
469     }\r
470     else\r
471       return;\r
472   }\r
473 \r
474   public void notifyFrameChanged(int frameNo)\r
475   {\r
476     boolean isAnimationRunning = (frameNo <= -2);\r
477   }\r
478 \r
479   public void notifyScriptStart(String statusMessage, String additionalInfo)\r
480   {}\r
481 \r
482   public void sendConsoleEcho(String strEcho)\r
483   {\r
484   //  if (scriptWindow != null)\r
485    //   scriptWindow.sendConsoleEcho(strEcho);\r
486   }\r
487 \r
488   public void sendConsoleMessage(String strStatus)\r
489   {\r
490    // if (scriptWindow != null)\r
491    //   scriptWindow.sendConsoleMessage(strStatus);\r
492   }\r
493 \r
494   public void notifyScriptTermination(String strStatus, int msWalltime)\r
495   {\r
496   //  if (scriptWindow != null)\r
497   //    scriptWindow.notifyScriptTermination(strStatus, msWalltime);\r
498   }\r
499 \r
500   public void handlePopupMenu(int x, int y)\r
501   {\r
502     jmolpopup.show(x, y);\r
503   }\r
504 \r
505   public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)\r
506   {\r
507     notifyAtomPicked(iatom, strMeasure);\r
508   }\r
509 \r
510   public void notifyNewDefaultModeMeasurement(int count, String strInfo)\r
511   {}\r
512 \r
513   public void notifyAtomPicked(int atomIndex, String strInfo)\r
514   {\r
515    // if (scriptWindow != null)\r
516     {\r
517    //   scriptWindow.sendConsoleMessage(strInfo);\r
518    //   scriptWindow.sendConsoleMessage("\n");\r
519     }\r
520   }\r
521 \r
522   public void notifyAtomHovered(int atomIndex, String strInfo)\r
523   {\r
524     mouseOverStructure(atomIndex, strInfo);\r
525   }\r
526 \r
527   public void sendSyncScript(String script, String appletName)\r
528   {}\r
529 \r
530   public void showUrl(String url)\r
531   {}\r
532 \r
533   public void showConsole(boolean showConsole)\r
534   {\r
535     if (scriptWindow == null)\r
536     {\r
537       scriptWindow = new Panel(new BorderLayout());\r
538       inputLine = new TextField();\r
539       history = new TextArea(5, 40);\r
540       scriptWindow.add(history, BorderLayout.CENTER);\r
541       scriptWindow.add(inputLine, BorderLayout.SOUTH);\r
542       add(scriptWindow, BorderLayout.SOUTH);\r
543       scriptWindow.setVisible(false);\r
544       history.setEditable(false);\r
545       inputLine.addKeyListener(this);\r
546     }\r
547 \r
548     scriptWindow.setVisible(!scriptWindow.isVisible());\r
549     validate();\r
550   }\r
551 \r
552   public float functionXY(String functionName, int x, int y)\r
553   {\r
554     return 0;\r
555   }\r
556 \r
557   ///End JmolStatusListener\r
558   ///////////////////////////////\r
559 \r
560 \r
561   class RenderPanel\r
562       extends Panel\r
563   {\r
564     Dimension currentSize = new Dimension();\r
565     Rectangle rectClip = new Rectangle();\r
566 \r
567     public void update(Graphics g) {\r
568       paint(g);\r
569     }\r
570     public void paint(Graphics g)\r
571     {\r
572       currentSize = this.getSize();\r
573       rectClip = g.getClipBounds();\r
574 \r
575       if (viewer == null)\r
576       {\r
577         g.setColor(Color.black);\r
578         g.fillRect(0, 0, currentSize.width, currentSize.height);\r
579         g.setColor(Color.white);\r
580         g.setFont(new Font("Verdana", Font.BOLD, 14));\r
581         g.drawString("Retrieving PDB data....", 20, currentSize.height / 2);\r
582       }\r
583       else\r
584       {\r
585         viewer.renderScreenImage(g, currentSize, rectClip);\r
586       }\r
587     }\r
588   }\r
589 \r
590 }\r