correct initing of JmolViewer to avoid security exception in unsigned applet moed
[jalview.git] / src / jalview / appletgui / AppletJmol.java
1 /*
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
4  * 
5  * This file is part of Jalview.
6  * 
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.
10  * 
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.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.appletgui;
19
20 import java.util.*;
21 import java.awt.*;
22 import java.awt.event.*;
23
24 import jalview.api.SequenceStructureBinding;
25 import jalview.datamodel.*;
26 import jalview.structure.*;
27 import jalview.io.*;
28
29 import org.jmol.api.*;
30
31 import org.jmol.popup.*;
32 import org.jmol.viewer.JmolConstants;
33
34 import jalview.schemes.*;
35
36 public class AppletJmol extends EmbmenuFrame implements
37 // StructureListener,
38         KeyListener, ActionListener, ItemListener, SequenceStructureBinding
39
40 {
41   Menu fileMenu = new Menu("File");
42
43   Menu viewMenu = new Menu("View");
44
45   Menu coloursMenu = new Menu("Colours");
46
47   Menu chainMenu = new Menu("Show Chain");
48
49   Menu helpMenu = new Menu("Help");
50
51   MenuItem mappingMenuItem = new MenuItem("View Mapping");
52
53   CheckboxMenuItem seqColour = new CheckboxMenuItem("By Sequence", true);
54
55   MenuItem chain = new MenuItem("By Chain");
56
57   MenuItem charge = new MenuItem("Charge & Cysteine");
58
59   MenuItem zappo = new MenuItem("Zappo");
60
61   MenuItem taylor = new MenuItem("Taylor");
62
63   MenuItem hydro = new MenuItem("Hydrophobicity");
64
65   MenuItem helix = new MenuItem("Helix Propensity");
66
67   MenuItem strand = new MenuItem("Strand Propensity");
68
69   MenuItem turn = new MenuItem("Turn Propensity");
70
71   MenuItem buried = new MenuItem("Buried Index");
72
73   MenuItem user = new MenuItem("User Defined Colours");
74
75   MenuItem jmolHelp = new MenuItem("Jmol Help");
76
77   Panel scriptWindow;
78
79   TextField inputLine;
80
81   TextArea history;
82
83   RenderPanel renderPanel;
84
85   AlignmentPanel ap;
86
87   String fileLoadingError;
88
89   boolean loadedInline;
90
91   // boolean colourBySequence = true;
92
93   FeatureRenderer fr = null;
94
95   AppletJmolBinding jmb;
96
97   /**
98    * datasource protocol for access to PDBEntry
99    */
100   String protocol = null;
101
102   public AppletJmol(PDBEntry pdbentry, SequenceI[] seq, String[] chains,
103           AlignmentPanel ap, String protocol)
104   {
105     this.ap = ap;
106     jmb = new AppletJmolBinding(this, new PDBEntry[]
107     { pdbentry }, seq, chains, protocol);
108     jmb.setColourBySequence(true);
109     if (pdbentry.getId() == null || pdbentry.getId().length() < 1)
110     {
111       if (protocol.equals(AppletFormatAdapter.PASTE))
112       {
113         pdbentry.setId("PASTED PDB"
114                 + (chains == null ? "_" : chains.toString()));
115       }
116       else
117       {
118         pdbentry.setId(pdbentry.getFile());
119       }
120     }
121
122     if (jalview.bin.JalviewLite.debug)
123     {
124       System.err
125               .println("AppletJmol: PDB ID is '" + pdbentry.getId() + "'");
126     }
127
128     String alreadyMapped = StructureSelectionManager
129             .getStructureSelectionManager().alreadyMappedToFile(
130                     pdbentry.getId());
131     MCview.PDBfile reader = null;
132     if (alreadyMapped != null)
133     {
134       reader = StructureSelectionManager.getStructureSelectionManager()
135               .setMapping(seq, chains, pdbentry.getFile(), protocol);
136       // PROMPT USER HERE TO ADD TO NEW OR EXISTING VIEW?
137       // FOR NOW, LETS JUST OPEN A NEW WINDOW
138     }
139     MenuBar menuBar = new MenuBar();
140     menuBar.add(fileMenu);
141     fileMenu.add(mappingMenuItem);
142     menuBar.add(viewMenu);
143     mappingMenuItem.addActionListener(this);
144     viewMenu.add(chainMenu);
145     menuBar.add(coloursMenu);
146     menuBar.add(helpMenu);
147
148     charge.addActionListener(this);
149     hydro.addActionListener(this);
150     chain.addActionListener(this);
151     seqColour.addItemListener(this);
152     zappo.addActionListener(this);
153     taylor.addActionListener(this);
154     helix.addActionListener(this);
155     strand.addActionListener(this);
156     turn.addActionListener(this);
157     buried.addActionListener(this);
158     user.addActionListener(this);
159
160     jmolHelp.addActionListener(this);
161
162     coloursMenu.add(seqColour);
163     coloursMenu.add(chain);
164     coloursMenu.add(charge);
165     coloursMenu.add(zappo);
166     coloursMenu.add(taylor);
167     coloursMenu.add(hydro);
168     coloursMenu.add(helix);
169     coloursMenu.add(strand);
170     coloursMenu.add(turn);
171     coloursMenu.add(buried);
172     coloursMenu.add(user);
173
174     helpMenu.add(jmolHelp);
175
176     setMenuBar(menuBar);
177
178     renderPanel = new RenderPanel();
179     embedMenuIfNeeded(renderPanel);
180     this.add(renderPanel, BorderLayout.CENTER);
181     try
182     {
183       jmb.allocateViewer(renderPanel, true, ap.av.applet.getName()+"_jmol_",
184               ap.av.applet.getDocumentBase(), ap.av.applet.getCodeBase(),
185               "-applet");
186     } catch (Exception e)
187     {
188       System.err
189               .println("Couldn't create a jmol viewer. Args to allocate viewer were:\nDocumentBase="
190                       + ap.av.applet.getDocumentBase()
191                       + "\nCodebase="
192                       + ap.av.applet.getCodeBase());
193       e.printStackTrace();
194       dispose();
195       return;
196     }
197     jmb.newJmolPopup(true, "Jmol", true);
198
199     this.addWindowListener(new WindowAdapter()
200     {
201       public void windowClosing(WindowEvent evt)
202       {
203         closeViewer();
204       }
205     });
206
207     if (pdbentry.getFile() != null)
208     {
209       // import structure data from pdbentry.getFile based on given protocol
210       if (protocol.equals(AppletFormatAdapter.PASTE))
211       {
212         loadInline(pdbentry.getFile());
213       }
214       else if (protocol.equals(AppletFormatAdapter.FILE)
215               || protocol.equals(AppletFormatAdapter.URL))
216       {
217         jmb.viewer.openFile(pdbentry.getFile());
218       }
219       else
220       {
221         // probably CLASSLOADER based datasource..
222         // Try and get a reader on the datasource, and pass that to Jmol
223         try
224         {
225           java.io.Reader freader = null;
226           if (reader != null)
227           {
228             if (jalview.bin.JalviewLite.debug)
229             {
230               System.err
231                       .println("AppletJmol:Trying to reuse existing PDBfile IO parser.");
232             }
233             // re-use the one we opened earlier
234             freader = reader.getReader();
235           }
236           if (freader == null)
237           {
238             if (jalview.bin.JalviewLite.debug)
239             {
240               System.err
241                       .println("AppletJmol:Creating new PDBfile IO parser.");
242             }
243             FileParse fp = new FileParse(pdbentry.getFile(), protocol);
244             fp.mark();
245             // reader = new MCview.PDBfile(fp);
246             // could set ID, etc.
247             // if (!reader.isValid())
248             // {
249             // throw new Exception("Invalid datasource.
250             // "+reader.getWarningMessage());
251             // }
252             // fp.reset();
253             freader = fp.getReader();
254           }
255           if (freader == null)
256           {
257             throw new Exception(
258                     "Invalid datasource. Could not obtain Reader.");
259           }
260           jmb.viewer.openReader(pdbentry.getFile(), pdbentry.getId(),
261                   freader);
262         } catch (Exception e)
263         {
264           // give up!
265           System.err.println("Couldn't access pdbentry id="
266                   + pdbentry.getId() + " and file=" + pdbentry.getFile()
267                   + " using protocol=" + protocol);
268           e.printStackTrace();
269         }
270       }
271     }
272
273     jalview.bin.JalviewLite.addFrame(this, jmb.getViewerTitle(), 400, 400);
274   }
275
276   public void loadInline(String string)
277   {
278     loadedInline = true;
279     jmb.viewer.openStringInline(string);
280   }
281
282   void setChainMenuItems(Vector chains)
283   {
284     chainMenu.removeAll();
285
286     MenuItem menuItem = new MenuItem("All");
287     menuItem.addActionListener(this);
288
289     chainMenu.add(menuItem);
290
291     CheckboxMenuItem menuItemCB;
292     for (int c = 0; c < chains.size(); c++)
293     {
294       menuItemCB = new CheckboxMenuItem(chains.elementAt(c).toString(),
295               true);
296       menuItemCB.addItemListener(this);
297       chainMenu.add(menuItemCB);
298     }
299   }
300
301   boolean allChainsSelected = false;
302
303   void centerViewer()
304   {
305     Vector toshow = new Vector();
306     String lbl;
307     int mlength, p, mnum;
308     for (int i = 0; i < chainMenu.getItemCount(); i++)
309     {
310       if (chainMenu.getItem(i) instanceof CheckboxMenuItem)
311       {
312         CheckboxMenuItem item = (CheckboxMenuItem) chainMenu.getItem(i);
313         if (item.getState())
314         {
315           toshow.addElement(item.getLabel());
316         }
317       }
318     }
319     jmb.centerViewer(toshow);
320   }
321
322   void closeViewer()
323   {
324     jmb.closeViewer();
325     jmb = null;
326     this.setVisible(false);
327   }
328
329   public void actionPerformed(ActionEvent evt)
330   {
331     if (evt.getSource() == mappingMenuItem)
332     {
333       jalview.appletgui.CutAndPasteTransfer cap = new jalview.appletgui.CutAndPasteTransfer(
334               false, null);
335       Frame frame = new Frame();
336       frame.add(cap);
337
338       StringBuffer sb = new StringBuffer();
339       try {
340       for (int s = 0; s < jmb.pdbentry.length; s++)
341       {
342         sb.append(StructureSelectionManager.getStructureSelectionManager()
343                 .printMapping(jmb.pdbentry[s].getFile()));
344         sb.append("\n");
345       }
346       cap.setText(sb.toString());
347       }
348       catch (OutOfMemoryError ex)
349       {
350         frame.dispose();
351         System.err.println("Out of memory when trying to create dialog box with sequence-structure mapping.");
352         return;
353       }
354       jalview.bin.JalviewLite.addFrame(frame, "PDB - Sequence Mapping",
355               550, 600);
356     }
357     else if (evt.getSource() == charge)
358     {
359       setEnabled(charge);
360       jmb.colourByCharge();
361     }
362
363     else if (evt.getSource() == chain)
364     {
365       setEnabled(chain);
366       jmb.colourByChain();
367     }
368     else if (evt.getSource() == zappo)
369     {
370       setEnabled(zappo);
371       jmb.setJalviewColourScheme(new ZappoColourScheme());
372     }
373     else if (evt.getSource() == taylor)
374     {
375       setEnabled(taylor);
376       jmb.setJalviewColourScheme(new TaylorColourScheme());
377     }
378     else if (evt.getSource() == hydro)
379     {
380       setEnabled(hydro);
381       jmb.setJalviewColourScheme(new HydrophobicColourScheme());
382     }
383     else if (evt.getSource() == helix)
384     {
385       setEnabled(helix);
386       jmb.setJalviewColourScheme(new HelixColourScheme());
387     }
388     else if (evt.getSource() == strand)
389     {
390       setEnabled(strand);
391       jmb.setJalviewColourScheme(new StrandColourScheme());
392     }
393     else if (evt.getSource() == turn)
394     {
395       setEnabled(turn);
396       jmb.setJalviewColourScheme(new TurnColourScheme());
397     }
398     else if (evt.getSource() == buried)
399     {
400       setEnabled(buried);
401       jmb.setJalviewColourScheme(new BuriedColourScheme());
402     }
403     else if (evt.getSource() == user)
404     {
405       setEnabled(user);
406       new UserDefinedColours(this);
407     }
408     else if (evt.getSource() == jmolHelp)
409     {
410       try
411       {
412         ap.av.applet.getAppletContext().showDocument(
413                 new java.net.URL(
414                         "http://jmol.sourceforge.net/docs/JmolUserGuide/"),
415                 "jmolHelp");
416       } catch (java.net.MalformedURLException ex)
417       {
418       }
419     }
420     else
421     {
422       allChainsSelected = true;
423       for (int i = 0; i < chainMenu.getItemCount(); i++)
424       {
425         if (chainMenu.getItem(i) instanceof CheckboxMenuItem)
426           ((CheckboxMenuItem) chainMenu.getItem(i)).setState(true);
427       }
428
429       centerViewer();
430       allChainsSelected = false;
431     }
432   }
433
434   /**
435    * tick or untick the seqColour menu entry depending upon if it was selected
436    * or not.
437    * 
438    * @param itm
439    */
440   private void setEnabled(MenuItem itm)
441   {
442     seqColour.setState(itm == seqColour);
443     jmb.setColourBySequence(itm == seqColour);
444   }
445
446   public void itemStateChanged(ItemEvent evt)
447   {
448     if (evt.getSource() == seqColour)
449     {
450       setEnabled(seqColour);
451       jmb.colourBySequence(ap.av.getShowSequenceFeatures(), ap.av.alignment);
452     }
453     else if (!allChainsSelected)
454       centerViewer();
455   }
456
457   public void keyPressed(KeyEvent evt)
458   {
459     if (evt.getKeyCode() == KeyEvent.VK_ENTER && scriptWindow.isVisible())
460     {
461       jmb.eval(inputLine.getText());
462       history.append("\n$ " + inputLine.getText());
463       inputLine.setText("");
464     }
465
466   }
467
468   public void keyTyped(KeyEvent evt)
469   {
470   }
471
472   public void keyReleased(KeyEvent evt)
473   {
474   }
475
476   public void updateColours(Object source)
477   {
478     AlignmentPanel ap = (AlignmentPanel) source;
479     jmb.colourBySequence(ap.av.getShowSequenceFeatures(), ap.av.alignment);
480   }
481
482   public void updateTitleAndMenus()
483   {
484     if (jmb.fileLoadingError != null && jmb.fileLoadingError.length() > 0)
485     {
486       repaint();
487       return;
488     }
489     setChainMenuItems(jmb.chainNames);
490     jmb.colourBySequence(ap.av.getShowSequenceFeatures(), ap.av.alignment);
491
492     setTitle(jmb.getViewerTitle());
493   }
494
495   public void showUrl(String url)
496   {
497     try
498     {
499       ap.av.applet.getAppletContext().showDocument(new java.net.URL(url),
500               "jmolOutput");
501     } catch (java.net.MalformedURLException ex)
502     {
503     }
504   }
505
506   public void showConsole(boolean showConsole)
507   {
508     if (scriptWindow == null)
509     {
510       scriptWindow = new Panel(new BorderLayout());
511       inputLine = new TextField();
512       history = new TextArea(5, 40);
513       scriptWindow.add(history, BorderLayout.CENTER);
514       scriptWindow.add(inputLine, BorderLayout.SOUTH);
515       add(scriptWindow, BorderLayout.SOUTH);
516       scriptWindow.setVisible(false);
517       history.setEditable(false);
518       inputLine.addKeyListener(this);
519     }
520
521     scriptWindow.setVisible(!scriptWindow.isVisible());
522     validate();
523   }
524
525   public float[][] functionXY(String functionName, int x, int y)
526   {
527     return null;
528   }
529
530   // /End JmolStatusListener
531   // /////////////////////////////
532
533   class RenderPanel extends Panel
534   {
535     Dimension currentSize = new Dimension();
536
537     Rectangle rectClip = new Rectangle();
538
539     public void update(Graphics g)
540     {
541       paint(g);
542     }
543
544     public void paint(Graphics g)
545     {
546       currentSize = this.getSize();
547       rectClip = g.getClipBounds();
548
549       if (jmb.viewer == null)
550       {
551         g.setColor(Color.black);
552         g.fillRect(0, 0, currentSize.width, currentSize.height);
553         g.setColor(Color.white);
554         g.setFont(new Font("Verdana", Font.BOLD, 14));
555         g.drawString("Retrieving PDB data....", 20, currentSize.height / 2);
556       }
557       else
558       {
559         jmb.viewer.renderScreenImage(g, currentSize, rectClip);
560       }
561     }
562   }
563
564   /*
565    * @Override public Color getColour(int atomIndex, int pdbResNum, String
566    * chain, String pdbId) { return jmb.getColour(atomIndex, pdbResNum, chain,
567    * pdbId); }
568    * 
569    * @Override public String[] getPdbFile() { return jmb.getPdbFile(); }
570    * 
571    * @Override public void highlightAtom(int atomIndex, int pdbResNum, String
572    * chain, String pdbId) { jmb.highlightAtom(atomIndex, pdbResNum, chain,
573    * pdbId);
574    * 
575    * }
576    * 
577    * @Override public void mouseOverStructure(int atomIndex, String strInfo) {
578    * jmb.mouseOverStructure(atomIndex, strInfo);
579    * 
580    * }
581    */
582   public void setJalviewColourScheme(UserColourScheme ucs)
583   {
584     jmb.setJalviewColourScheme(ucs);
585   }
586 }