d8ef11a1d3de3c2fb93b1bc12f763552719d402b
[jalview.git] / src / jalview / gui / AppJMol.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  *
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.
9  *
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.
14  *
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
18  */
19 package jalview.gui;
20
21 import java.util.regex.*;
22 import java.util.*;
23 import java.awt.*;
24 import javax.swing.*;
25 import javax.swing.event.*;
26 import java.awt.event.*;
27 import java.io.*;
28
29 import jalview.jbgui.GStructureViewer;
30 import jalview.datamodel.*;
31 import jalview.gui.*;
32 import jalview.structure.*;
33 import jalview.datamodel.PDBEntry;
34 import jalview.io.*;
35 import jalview.schemes.*;
36
37 import org.jmol.api.*;
38 import org.jmol.adapter.smarter.SmarterJmolAdapter;
39 import org.jmol.popup.*;
40
41
42 public class AppJMol
43     extends GStructureViewer
44     implements StructureListener, JmolStatusListener, Runnable
45
46 {
47   JmolViewer viewer;
48   JmolPopup jmolpopup;
49   ScriptWindow scriptWindow;
50   PDBEntry pdbentry;
51   SequenceI[] sequence;
52   String [] chains;
53   StructureSelectionManager ssm;
54   JSplitPane splitPane;
55   RenderPanel renderPanel;
56   AlignmentPanel ap;
57   String fileLoadingError;
58   boolean colourBySequence = true;
59   boolean loadingFromArchive = false;
60   Vector atomsPicked = new Vector();
61
62   public AppJMol(String file, String id,
63                  SequenceI[] seq,
64                  AlignmentPanel ap,
65                  String loadStatus,
66                  Rectangle bounds)
67   {
68     loadingFromArchive = true;
69     pdbentry = new PDBEntry();
70     pdbentry.setFile(file);
71     pdbentry.setId(id);
72     this.chains = chains;
73     this.sequence = seq;
74     this.ap = ap;
75     this.setBounds(bounds);
76
77     colourBySequence = false;
78     seqColour.setSelected(false);
79
80     jalview.gui.Desktop.addInternalFrame(this, "Loading File",
81                                          bounds.width,bounds.height);
82
83     initJmol(loadStatus);
84
85     this.addInternalFrameListener(new InternalFrameAdapter()
86     {
87       public void internalFrameClosing(InternalFrameEvent internalFrameEvent)
88       {
89         closeViewer();
90       }
91     });
92   }
93
94 public synchronized void addSequence(SequenceI [] seq)
95    {
96     Vector v = new Vector();
97      for(int i=0; i<sequence.length; i++)
98        v.addElement(sequence[i]);
99
100      for(int i=0; i<seq.length; i++)
101       if(!v.contains(seq[i]))
102           v.addElement(seq[i]);
103
104      SequenceI [] tmp = new SequenceI[v.size()];
105      v.copyInto(tmp);
106      sequence = tmp;
107    }
108
109   public AppJMol(PDBEntry pdbentry, SequenceI[] seq, String [] chains, AlignmentPanel ap)
110   {
111     //////////////////////////////////
112     //Is the pdb file already loaded?
113     String alreadyMapped = StructureSelectionManager
114         .getStructureSelectionManager()
115         .alreadyMappedToFile(pdbentry.getId());
116
117     if (alreadyMapped != null)
118     {
119       int option = JOptionPane.showInternalConfirmDialog(Desktop.desktop,
120           pdbentry.getId() + " is already displayed."
121           + "\nDo you want to map sequences to the visible structure?",
122           "Map Sequences to Visible Window: " + pdbentry.getId(),
123           JOptionPane.YES_NO_OPTION);
124
125       if (option == JOptionPane.YES_OPTION)
126       {
127         StructureSelectionManager.getStructureSelectionManager()
128             .setMapping(seq, chains, alreadyMapped, AppletFormatAdapter.FILE);
129         if (ap.seqPanel.seqCanvas.fr!=null) {
130           ap.seqPanel.seqCanvas.fr.featuresAdded();
131           ap.paintAlignment(true);
132         }
133         return;
134       }
135     }
136     ///////////////////////////////////
137
138     this.ap = ap;
139     this.pdbentry = pdbentry;
140     this.sequence = seq;
141
142     jalview.gui.Desktop.addInternalFrame(this, "Loading File", 400, 400);
143
144     if (pdbentry.getFile() != null)
145     {
146       initJmol("load \""+pdbentry.getFile()+"\"");
147     }
148     else
149     {
150       Thread worker = new Thread(this);
151       worker.start();
152     }
153
154     this.addInternalFrameListener(new InternalFrameAdapter()
155     {
156       public void internalFrameClosing(InternalFrameEvent internalFrameEvent)
157       {
158         closeViewer();
159       }
160     });
161   }
162
163
164   void initJmol(String command)
165   {
166     renderPanel = new RenderPanel();
167
168     this.getContentPane().add(renderPanel, java.awt.BorderLayout.CENTER);
169
170     StringBuffer title = new StringBuffer(sequence[0].getName() + ":" +
171                                           pdbentry.getId());
172
173     if (pdbentry.getProperty() != null)
174     {
175       if (pdbentry.getProperty().get("method") != null)
176       {
177         title.append(" Method: ");
178         title.append(pdbentry.getProperty().get("method"));
179       }
180       if (pdbentry.getProperty().get("chains") != null)
181       {
182         title.append(" Chain:");
183         title.append(pdbentry.getProperty().get("chains"));
184       }
185     }
186
187     this.setTitle(title.toString());
188
189     viewer = org.jmol.api.JmolViewer.allocateViewer(renderPanel,
190         new SmarterJmolAdapter());
191
192
193     viewer.setAppletContext("", null, null, "");
194
195     viewer.setJmolStatusListener(this);
196
197     jmolpopup = JmolPopup.newJmolPopup(viewer);
198
199     viewer.evalStringQuiet(command);
200   }
201
202
203   void setChainMenuItems(Vector chains)
204   {
205     chainMenu.removeAll();
206
207     JMenuItem menuItem = new JMenuItem("All");
208     menuItem.addActionListener(new ActionListener()
209         {
210           public void actionPerformed(ActionEvent evt)
211           {
212             allChainsSelected = true;
213             for(int i=0; i<chainMenu.getItemCount(); i++)
214             {
215               if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
216                 ( (JCheckBoxMenuItem) chainMenu.getItem(i)).setSelected(true);
217             }
218             centerViewer();
219             allChainsSelected = false;
220           }
221         });
222
223     chainMenu.add(menuItem);
224
225     for (int c = 0; c < chains.size(); c++)
226     {
227       menuItem = new JCheckBoxMenuItem(chains.elementAt(c).toString(), true);
228       menuItem.addItemListener(new ItemListener()
229       {
230         public void itemStateChanged(ItemEvent evt)
231         {
232           if (!allChainsSelected)
233             centerViewer();
234         }
235       });
236
237       chainMenu.add(menuItem);
238     }
239   }
240
241   boolean allChainsSelected = false;
242   void centerViewer()
243   {
244     StringBuffer cmd = new StringBuffer();
245     for(int i=0; i<chainMenu.getItemCount(); i++)
246     {
247       if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
248       {
249        JCheckBoxMenuItem item = (JCheckBoxMenuItem) chainMenu.getItem(i);
250        if(item.isSelected())
251          cmd.append(":"+item.getText()+" or ");
252       }
253     }
254
255     if (cmd.length() > 0)
256       cmd.setLength(cmd.length() - 4);
257
258     viewer.evalStringQuiet("select *;restrict "
259                       +cmd+";cartoon;center "+cmd);
260   }
261
262   void closeViewer()
263   {
264     viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
265     viewer.evalStringQuiet("zap");
266     viewer.setJmolStatusListener(null);
267     viewer = null;
268
269     //We'll need to find out what other
270     // listeners need to be shut down in Jmol
271     StructureSelectionManager
272         .getStructureSelectionManager()
273         .removeStructureViewerListener(this, pdbentry.getFile());
274   }
275
276   public void run()
277   {
278     try
279     {
280       EBIFetchClient ebi = new EBIFetchClient();
281       String query = "pdb:" + pdbentry.getId();
282       pdbentry.setFile(ebi.fetchDataAsFile(query, "default", "raw")
283                        .getAbsolutePath());
284       initJmol("load "+pdbentry.getFile());
285     }
286     catch (Exception ex)
287     {
288       ex.printStackTrace();
289     }
290   }
291
292   public void pdbFile_actionPerformed(ActionEvent actionEvent)
293   {
294     JalviewFileChooser chooser = new JalviewFileChooser(
295         jalview.bin.Cache.getProperty(
296             "LAST_DIRECTORY"));
297
298     chooser.setFileView(new JalviewFileView());
299     chooser.setDialogTitle("Save PDB File");
300     chooser.setToolTipText("Save");
301
302     int value = chooser.showSaveDialog(this);
303
304     if (value == JalviewFileChooser.APPROVE_OPTION)
305     {
306       try
307       {
308         BufferedReader in = new BufferedReader(new FileReader(pdbentry.getFile()));
309         File outFile = chooser.getSelectedFile();
310
311         PrintWriter out = new PrintWriter(new FileOutputStream(outFile));
312         String data;
313         while ( (data = in.readLine()) != null)
314         {
315           if (
316               ! (data.indexOf("<PRE>") > -1 || data.indexOf("</PRE>") > -1)
317               )
318           {
319             out.println(data);
320           }
321         }
322         out.close();
323       }
324       catch (Exception ex)
325       {
326         ex.printStackTrace();
327       }
328     }
329   }
330
331   public void viewMapping_actionPerformed(ActionEvent actionEvent)
332   {
333     jalview.gui.CutAndPasteTransfer cap = new jalview.gui.CutAndPasteTransfer();
334     jalview.gui.Desktop.addInternalFrame(cap, "PDB - Sequence Mapping", 550,
335                                          600);
336     cap.setText(
337         StructureSelectionManager.getStructureSelectionManager().printMapping(
338             pdbentry.getFile())
339         );
340   }
341
342   /**
343    * DOCUMENT ME!
344    *
345    * @param e DOCUMENT ME!
346    */
347   public void eps_actionPerformed(ActionEvent e)
348   {
349     makePDBImage(jalview.util.ImageMaker.EPS);
350   }
351
352   /**
353    * DOCUMENT ME!
354    *
355    * @param e DOCUMENT ME!
356    */
357   public void png_actionPerformed(ActionEvent e)
358   {
359     makePDBImage(jalview.util.ImageMaker.PNG);
360   }
361
362   void makePDBImage(int type)
363   {
364     int width = getWidth();
365     int height = getHeight();
366
367     jalview.util.ImageMaker im;
368
369     if (type == jalview.util.ImageMaker.PNG)
370     {
371       im = new jalview.util.ImageMaker(this,
372                                        jalview.util.ImageMaker.PNG,
373                                        "Make PNG image from view",
374                                        width, height,
375                                        null, null);
376     }
377     else
378     {
379       im = new jalview.util.ImageMaker(this,
380                                        jalview.util.ImageMaker.EPS,
381                                        "Make EPS file from view",
382                                        width, height,
383                                        null, this.getTitle());
384     }
385
386     if (im.getGraphics() != null)
387     {
388       Rectangle rect = new Rectangle(width, height);
389       viewer.renderScreenImage(im.getGraphics(),
390                                rect.getSize(), rect);
391       im.writeImage();
392     }
393   }
394
395
396   public void seqColour_actionPerformed(ActionEvent actionEvent)
397   {
398     colourBySequence = seqColour.isSelected();
399     colourBySequence(ap.alignFrame.alignPanel);
400   }
401
402   public void chainColour_actionPerformed(ActionEvent actionEvent)
403   {
404     colourBySequence = false;
405     seqColour.setSelected(false);
406     viewer.evalStringQuiet("select *;color chain");
407   }
408
409   public void chargeColour_actionPerformed(ActionEvent actionEvent)
410   {
411     colourBySequence = false;
412     seqColour.setSelected(false);
413     viewer.evalStringQuiet("select *;color white;select ASP,GLU;color red;"
414                       +"select LYS,ARG;color blue;select CYS;color yellow");
415   }
416
417   public void zappoColour_actionPerformed(ActionEvent actionEvent)
418   {
419     setJalviewColourScheme(new ZappoColourScheme());
420   }
421
422   public void taylorColour_actionPerformed(ActionEvent actionEvent)
423   {
424     setJalviewColourScheme(new TaylorColourScheme());
425   }
426
427   public void hydroColour_actionPerformed(ActionEvent actionEvent)
428   {
429     setJalviewColourScheme(new HydrophobicColourScheme());
430   }
431
432   public void helixColour_actionPerformed(ActionEvent actionEvent)
433   {
434     setJalviewColourScheme(new HelixColourScheme());
435   }
436
437   public void strandColour_actionPerformed(ActionEvent actionEvent)
438   {
439     setJalviewColourScheme(new StrandColourScheme());
440   }
441
442   public void turnColour_actionPerformed(ActionEvent actionEvent)
443   {
444     setJalviewColourScheme(new TurnColourScheme());
445   }
446
447   public void buriedColour_actionPerformed(ActionEvent actionEvent)
448   {
449     setJalviewColourScheme(new BuriedColourScheme());
450   }
451
452   public void setJalviewColourScheme(ColourSchemeI cs)
453   {
454     colourBySequence = false;
455     seqColour.setSelected(false);
456
457     if(cs==null)
458       return;
459
460     String res;
461     int index;
462     Color col;
463
464     Enumeration en = ResidueProperties.aa3Hash.keys();
465     StringBuffer command = new StringBuffer("select *;color white;");
466     while(en.hasMoreElements())
467     {
468       res = en.nextElement().toString();
469       index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
470       if(index>20)
471         continue;
472
473       col = cs.findColour(ResidueProperties.aa[index].charAt(0));
474
475       command.append("select "+res+";color["
476                         + col.getRed() + ","
477                         + col.getGreen() + ","
478                         + col.getBlue() + "];");
479     }
480
481     viewer.evalStringQuiet(command.toString());
482   }
483
484   public void userColour_actionPerformed(ActionEvent actionEvent)
485   {
486     new UserDefinedColours(this, null);
487   }
488
489   public void backGround_actionPerformed(ActionEvent actionEvent)
490   {
491     java.awt.Color col = JColorChooser.showDialog(this,
492                                                   "Select Background Colour",
493                                                   null);
494
495     if (col != null)
496     {
497       viewer.evalStringQuiet("background ["
498                         + col.getRed() + ","
499                         + col.getGreen() + ","
500                         + col.getBlue() + "];");
501     }
502   }
503
504
505   public void jmolHelp_actionPerformed(ActionEvent actionEvent)
506   {
507        try{
508          jalview.util.BrowserLauncher.openURL(
509              "http://jmol.sourceforge.net/docs/JmolUserGuide/");
510        }catch(Exception ex){}
511    }
512
513
514   //////////////////////////////////
515   ///StructureListener
516   public String getPdbFile()
517   {
518     return pdbentry.getFile();
519   }
520
521   Pattern pattern = Pattern.compile(
522       "\\[(.*)\\]([0-9]+)(:[a-zA-Z]*)?\\.([a-zA-Z]+)(/[0-9]*)?"
523       );
524
525   String lastMessage;
526   public void mouseOverStructure(int atomIndex, String strInfo)
527   {
528     Matcher matcher = pattern.matcher(strInfo);
529     matcher.find();
530     matcher.group(1);
531     int pdbResNum = Integer.parseInt(matcher.group(2));
532     String chainId = matcher.group(3);
533
534     if (chainId != null)
535       chainId = chainId.substring(1, chainId.length());
536     else
537     {
538       chainId = " ";
539     }
540
541     if (lastMessage == null || !lastMessage.equals(strInfo))
542       ssm.mouseOverStructure(pdbResNum, chainId, pdbentry.getFile());
543
544     lastMessage = strInfo;
545   }
546
547   StringBuffer resetLastRes = new StringBuffer();
548   StringBuffer eval = new StringBuffer();
549
550   public void highlightAtom(int atomIndex, int pdbResNum, String chain, String pdbfile)
551   {
552     if (!pdbfile.equals(pdbentry.getFile()))
553       return;
554
555     if (resetLastRes.length() > 0)
556     {
557       viewer.evalStringQuiet(resetLastRes.toString());
558     }
559
560     eval.setLength(0);
561     eval.append("select " + pdbResNum);
562
563     resetLastRes.setLength(0);
564     resetLastRes.append("select " + pdbResNum);
565
566     if (!chain.equals(" "))
567     {
568       eval.append(":" + chain);
569       resetLastRes.append(":" + chain);
570     }
571
572     eval.append(";color gold;wireframe 100");
573
574     Color col = new Color(viewer.getAtomArgb(atomIndex));
575
576     resetLastRes.append(";color["
577                         + col.getRed() + ","
578                         + col.getGreen() + ","
579                         + col.getBlue() + "];wireframe 0");
580
581     viewer.evalStringQuiet(eval.toString());
582
583   }
584
585   public Color getColour(int atomIndex, int pdbResNum, String chain, String pdbfile)
586   {
587     if (!pdbfile.equals(pdbentry.getFile()))
588       return null;
589
590     return new Color(viewer.getAtomArgb(atomIndex));
591   }
592
593   public void updateColours(Object source)
594   {
595     colourBySequence( (AlignmentPanel) source);
596   }
597
598
599 //End StructureListener
600 ////////////////////////////
601
602   String lastCommand;
603   FeatureRenderer fr=null;
604   public void colourBySequence(AlignmentPanel ap)
605   {
606
607     if(ap.alignFrame.getCurrentView()!=ap.av)
608     {
609       System.out.println("RETURN");
610       return;
611     }
612
613     if(!colourBySequence)
614       return;
615
616
617     StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
618
619     if (mapping.length < 1)
620       return;
621
622     SequenceRenderer sr = new SequenceRenderer(ap.av);
623
624     boolean showFeatures = false;
625
626     if (ap.av.showSequenceFeatures)
627     {
628       showFeatures = true;
629       if (fr == null)
630       {
631         fr = new jalview.gui.FeatureRenderer(ap);
632       }
633
634       fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer());
635     }
636
637     StringBuffer command = new StringBuffer();
638
639     int lastPos = -1;
640     for (int s = 0; s < sequence.length; s++)
641     {
642       for (int m = 0; m < mapping.length; m++)
643       {
644         if (mapping[m].getSequence() == sequence[s]
645             && ap.av.alignment.findIndex(sequence[s])>-1)
646         {
647           for (int r = 0; r < sequence[s].getLength(); r++)
648           {
649             int pos = mapping[m].getPDBResNum(
650                 sequence[s].findPosition(r));
651
652             if (pos < 1 || pos==lastPos)
653               continue;
654
655             lastPos = pos;
656
657             Color col = sr.getResidueBoxColour(sequence[s], r);
658
659             if (showFeatures)
660               col = fr.findFeatureColour(col, sequence[s], r);
661
662             if (command.toString().endsWith(":" + mapping[m].getChain()+
663                                             ";color["
664                                             + col.getRed() + ","
665                                             + col.getGreen() + ","
666                                             + col.getBlue() + "]"))
667             {
668               command = condenseCommand(command, pos);
669               continue;
670             }
671
672             command.append(";select " + pos);
673
674             if (!mapping[m].getChain().equals(" "))
675             {
676               command.append(":" + mapping[m].getChain());
677             }
678
679             command.append(";color["
680                              + col.getRed() + ","
681                              + col.getGreen() + ","
682                              + col.getBlue() + "]");
683
684           }
685           break;
686         }
687       }
688     }
689
690     if (lastCommand != null && !lastCommand.equals(command.toString()))
691     {
692       viewer.evalStringQuiet(command.toString());
693     }
694     lastCommand = command.toString();
695   }
696
697   StringBuffer condenseCommand(StringBuffer command, int pos)
698   {
699     StringBuffer sb = new StringBuffer(command.substring(0, command.lastIndexOf("select")+7));
700
701     command.delete(0, sb.length());
702
703     String start;
704
705     if (command.indexOf("-") > -1)
706     {
707       start = command.substring(0,command.indexOf("-"));
708     }
709     else
710     {
711       start = command.substring(0, command.indexOf(":"));
712     }
713
714     sb.append(start+"-"+pos+command.substring(command.indexOf(":")));
715
716     return sb;
717   }
718
719   /////////////////////////////////
720   //JmolStatusListener
721
722   public String eval(String strEval)
723   {
724    // System.out.println(strEval);
725    //"# 'eval' is implemented only for the applet.";
726     return null;
727   }
728
729   public void createImage(String file, String type, int quality)
730   {
731     System.out.println("JMOL CREATE IMAGE");
732   }
733
734   public void setCallbackFunction(String callbackType,
735                                   String callbackFunction)
736   {}
737
738   public void notifyFileLoaded(String fullPathName, String fileName,
739                                String modelName, Object clientFile,
740                                String errorMsg)
741   {
742     if(errorMsg!=null)
743     {
744       fileLoadingError = errorMsg;
745       repaint();
746       return;
747     }
748
749     fileLoadingError = null;
750
751     if (fileName != null)
752     {
753
754       //FILE LOADED OK
755       ssm = StructureSelectionManager.getStructureSelectionManager();
756       MCview.PDBfile pdbFile = ssm.setMapping(sequence,chains,pdbentry.getFile(), AppletFormatAdapter.FILE);
757       ssm.addStructureViewerListener(this);
758       Vector chains = new Vector();
759       for(int i=0; i<pdbFile.chains.size(); i++)
760       {
761         chains.addElement(((MCview.PDBChain)pdbFile.chains.elementAt(i)).id);
762       }
763       setChainMenuItems(chains);
764
765       jmolpopup.updateComputedMenus();
766
767       if(!loadingFromArchive)
768       {
769         viewer.evalStringQuiet(
770              "select backbone;restrict;cartoon;wireframe off;spacefill off");
771
772         colourBySequence(ap);
773       }
774       if (fr!=null)
775         fr.featuresAdded();
776
777       loadingFromArchive = false;
778     }
779     else
780       return;
781   }
782
783   public void notifyFrameChanged(int frameNo)
784   {
785     boolean isAnimationRunning = (frameNo <= -2);
786   }
787
788   public void notifyScriptStart(String statusMessage, String additionalInfo)
789   {}
790
791   public void sendConsoleEcho(String strEcho)
792   {
793     if (scriptWindow != null)
794       scriptWindow.sendConsoleEcho(strEcho);
795   }
796
797   public void sendConsoleMessage(String strStatus)
798   {
799     if (scriptWindow != null)
800       scriptWindow.sendConsoleMessage(strStatus);
801   }
802
803   public void notifyScriptTermination(String strStatus, int msWalltime)
804   {
805     if (scriptWindow != null)
806       scriptWindow.notifyScriptTermination(strStatus, msWalltime);
807   }
808
809   public void handlePopupMenu(int x, int y)
810   {
811     jmolpopup.show(x, y);
812   }
813
814   public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
815   {
816     notifyAtomPicked(iatom, strMeasure);
817   }
818
819   public void notifyNewDefaultModeMeasurement(int count, String strInfo)
820   {}
821
822   public void notifyAtomPicked(int atomIndex, String strInfo)
823   {
824     Matcher matcher = pattern.matcher(strInfo);
825     matcher.find();
826
827     matcher.group(1);
828     String resnum = new String(matcher.group(2));
829     String chainId = matcher.group(3);
830
831     String picked = resnum;
832
833     if (chainId != null)
834       picked+=(":"+chainId.substring(1, chainId.length()));
835
836     picked+=".C";
837
838     if (!atomsPicked.contains(picked))
839     {
840       if(chainId!=null)
841       viewer.evalString("select "+picked+";label %n %r:%c");
842     else
843       viewer.evalString("select "+picked+";label %n %r");
844       atomsPicked.addElement(picked);
845     }
846     else
847     {
848       viewer.evalString("select "+picked+";label off");
849       atomsPicked.removeElement(picked);
850     }
851
852     if (scriptWindow != null)
853     {
854       scriptWindow.sendConsoleMessage(strInfo);
855       scriptWindow.sendConsoleMessage("\n");
856     }
857   }
858
859   public void notifyAtomHovered(int atomIndex, String strInfo)
860   {
861     mouseOverStructure(atomIndex, strInfo);
862   }
863
864   public void sendSyncScript(String script, String appletName)
865   {}
866
867   public void showUrl(String url)
868   {}
869
870   public void showConsole(boolean showConsole)
871   {
872     if (scriptWindow == null)
873       scriptWindow = new ScriptWindow(this);
874
875     if(showConsole)
876     {
877       if(splitPane==null)
878       {
879         splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
880         splitPane.setTopComponent(renderPanel);
881         splitPane.setBottomComponent(scriptWindow);
882         this.getContentPane().add(splitPane, BorderLayout.CENTER);
883       }
884
885       splitPane.setDividerLocation(getHeight()-200);
886       splitPane.validate();
887     }
888     else
889     {
890       if (splitPane != null)
891         splitPane.setVisible(false);
892
893       splitPane = null;
894
895       this.getContentPane().add(renderPanel, BorderLayout.CENTER);
896     }
897
898     validate();
899   }
900
901   public float functionXY(String functionName, int x, int y)
902   {
903     return 0;
904   }
905
906   ///End JmolStatusListener
907   ///////////////////////////////
908
909
910   class RenderPanel
911       extends JPanel
912   {
913     final Dimension currentSize = new Dimension();
914     final Rectangle rectClip = new Rectangle();
915
916     public void paintComponent(Graphics g)
917     {
918       getSize(currentSize);
919       g.getClipBounds(rectClip);
920
921       if (viewer == null)
922       {
923         g.setColor(Color.black);
924         g.fillRect(0, 0, currentSize.width, currentSize.height);
925         g.setColor(Color.white);
926         g.setFont(new Font("Verdana", Font.BOLD, 14));
927         g.drawString("Retrieving PDB data....", 20, currentSize.height / 2);
928       }
929       else if(fileLoadingError!=null)
930       {
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("Error loading file..." + pdbentry.getId(), 20,
936                      currentSize.height / 2);
937       }
938       else
939       {
940         viewer.renderScreenImage(g, currentSize, rectClip);
941       }
942     }
943   }
944
945 }