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