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