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