apply jalview code style
[jalview.git] / src / jalview / gui / AppJmol.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
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.gui;
19
20 import java.util.regex.*;
21 import java.util.*;
22 import java.awt.*;
23 import javax.swing.*;
24 import javax.swing.event.*;
25 import java.awt.event.*;
26 import java.io.*;
27
28 import jalview.jbgui.GStructureViewer;
29 import jalview.api.SequenceStructureBinding;
30 import jalview.bin.Cache;
31 import jalview.datamodel.*;
32 import jalview.gui.*;
33 import jalview.structure.*;
34 import jalview.datamodel.PDBEntry;
35 import jalview.io.*;
36 import jalview.schemes.*;
37 import jalview.ws.ebi.EBIFetchClient;
38
39 import org.jmol.api.*;
40 import org.jmol.adapter.smarter.SmarterJmolAdapter;
41 import org.jmol.popup.*;
42 import org.jmol.viewer.JmolConstants;
43 import org.openscience.jmol.app.jmolpanel.AppConsole;
44
45 public class AppJmol extends GStructureViewer implements Runnable,
46         SequenceStructureBinding
47
48 {
49   AppJmolBinding jmb;
50
51   JPanel scriptWindow;
52
53   JSplitPane splitPane;
54
55   RenderPanel renderPanel;
56
57   AlignmentPanel ap;
58
59   Vector atomsPicked = new Vector();
60
61   private boolean addingStructures = false;
62
63   /**
64    * 
65    * @param file
66    * @param id
67    * @param seq
68    * @param ap
69    * @param loadStatus
70    * @param bounds
71    * @deprecated defaults to AppJmol(String[] files, ... , viewid);
72    */
73   public AppJmol(String file, String id, SequenceI[] seq,
74           AlignmentPanel ap, String loadStatus, Rectangle bounds)
75   {
76     this(file, id, seq, ap, loadStatus, bounds, null);
77   }
78
79   /**
80    * @deprecated
81    */
82   public AppJmol(String file, String id, SequenceI[] seq,
83           AlignmentPanel ap, String loadStatus, Rectangle bounds,
84           String viewid)
85   {
86     this(new String[]
87     { file }, new String[]
88     { id }, new SequenceI[][]
89     { seq }, ap, loadStatus, bounds, viewid);
90   }
91
92   /**
93    * 
94    * @param files
95    * @param ids
96    * @param seqs
97    * @param ap
98    * @param loadStatus
99    * @param bounds
100    * @param viewid
101    */
102   public AppJmol(String[] files, String[] ids, SequenceI[][] seqs,
103           AlignmentPanel ap, String loadStatus, Rectangle bounds,
104           String viewid)
105   {
106     PDBEntry[] pdbentrys = new PDBEntry[files.length];
107     for (int i = 0; i < pdbentrys.length; i++)
108     {
109       PDBEntry pdbentry = new PDBEntry();
110       pdbentry.setFile(files[i]);
111       pdbentry.setId(ids[i]);
112       pdbentrys[i] = pdbentry;
113     }
114     // / TODO: check if protocol is needed to be set, and if chains are
115     // autodiscovered.
116     jmb = new AppJmolBinding(this, pdbentrys, seqs, null, null);
117
118     jmb.setLoadingFromArchive(true);
119     this.ap = ap;
120     this.setBounds(bounds);
121     jmb.setColourBySequence(false);
122     seqColour.setSelected(false);
123     viewId = viewid;
124     // jalview.gui.Desktop.addInternalFrame(this, "Loading File",
125     // bounds.width,bounds.height);
126
127     this.addInternalFrameListener(new InternalFrameAdapter()
128     {
129       public void internalFrameClosing(InternalFrameEvent internalFrameEvent)
130       {
131         closeViewer();
132       }
133     });
134     initJmol(loadStatus); // pdbentry, seq, JBPCHECK!
135
136   }
137
138   IProgressIndicator progressBar = null;
139
140   public AppJmol(PDBEntry pdbentry, SequenceI[] seq, String[] chains,
141           AlignmentPanel ap)
142   {
143     progressBar = ap.alignFrame;
144     // ////////////////////////////////
145     // Is the pdb file already loaded?
146     String alreadyMapped = StructureSelectionManager
147             .getStructureSelectionManager().alreadyMappedToFile(
148                     pdbentry.getId());
149
150     if (alreadyMapped != null)
151     {
152       int option = JOptionPane.showInternalConfirmDialog(Desktop.desktop,
153               pdbentry.getId() + " is already displayed."
154                       + "\nDo you want to re-use this viewer ?",
155               "Map Sequences to Visible Window: " + pdbentry.getId(),
156               JOptionPane.YES_NO_OPTION);
157
158       if (option == JOptionPane.YES_OPTION)
159       {
160         StructureSelectionManager.getStructureSelectionManager()
161                 .setMapping(seq, chains, alreadyMapped,
162                         AppletFormatAdapter.FILE);
163         if (ap.seqPanel.seqCanvas.fr != null)
164         {
165           ap.seqPanel.seqCanvas.fr.featuresAdded();
166           ap.paintAlignment(true);
167         }
168
169         // Now this AppJmol is mapped to new sequences. We must add them to
170         // the exisiting array
171         JInternalFrame[] frames = Desktop.instance.getAllFrames();
172
173         for (int i = 0; i < frames.length; i++)
174         {
175           if (frames[i] instanceof AppJmol)
176           {
177             AppJmol topJmol = ((AppJmol) frames[i]);
178             // JBPNOTE: this looks like a binding routine, rather than a gui
179             // routine
180             for (int pe = 0; pe < topJmol.jmb.pdbentry.length; pe++)
181             {
182               if (topJmol.jmb.pdbentry[pe].getFile().equals(alreadyMapped))
183               {
184                 topJmol.jmb.addSequence(pe, seq);
185                 break;
186               }
187             }
188           }
189         }
190
191         return;
192       }
193     }
194     // /////////////////////////////////
195     // Check if there are other Jmol views involving this alignment
196     // and prompt user about adding this molecule to one of them
197     Vector existingViews = getJmolsFor(ap);
198     if (existingViews.size() > 0)
199     {
200       Enumeration jm = existingViews.elements();
201       while (jm.hasMoreElements())
202       {
203         AppJmol topJmol = (AppJmol) jm.nextElement();
204         // TODO: highlight topJmol in view somehow
205         int option = JOptionPane.showInternalConfirmDialog(Desktop.desktop,
206                 "Do you want to add " + pdbentry.getId()
207                         + " to the view called\n'" + topJmol.getTitle()
208                         + "'\n", "Align to existing structure view",
209                 JOptionPane.YES_NO_OPTION);
210         if (option == JOptionPane.YES_OPTION)
211         {
212           topJmol.addStructure(pdbentry, seq, chains, true, ap.alignFrame);
213           return;
214         }
215       }
216     }
217     // /////////////////////////////////
218
219     jmb = new AppJmolBinding(this, new PDBEntry[]
220     { pdbentry }, new SequenceI[][]
221     { seq }, null, null);
222     this.ap = ap;
223     setSize(400, 400); // probably should be a configurable/dynamic default here
224
225     if (pdbentry.getFile() != null)
226     {
227       initJmol("load \"" + pdbentry.getFile() + "\"");
228     }
229     else
230     {
231       addingStructures = false;
232       worker = new Thread(this);
233       worker.start();
234     }
235
236     this.addInternalFrameListener(new InternalFrameAdapter()
237     {
238       public void internalFrameClosing(InternalFrameEvent internalFrameEvent)
239       {
240         closeViewer();
241       }
242     });
243
244   }
245
246   /**
247    * pdb retrieval thread.
248    */
249   private Thread worker = null;
250
251   /**
252    * add a new structure (with associated sequences and chains) to this viewer,
253    * retrieving it if necessary first.
254    * 
255    * @param pdbentry
256    * @param seq
257    * @param chains
258    * @param alignFrame
259    * @param align
260    *          if true, new structure(s) will be align using associated alignment
261    */
262   private void addStructure(final PDBEntry pdbentry, final SequenceI[] seq,
263           final String[] chains, final boolean b,
264           final IProgressIndicator alignFrame)
265   {
266     if (pdbentry.getFile() == null)
267     {
268       if (worker != null && worker.isAlive())
269       {
270         // a retrieval is in progress, wait around and add ourselves to the
271         // queue.
272         new Thread(new Runnable()
273         {
274           public void run()
275           {
276             while (worker != null && worker.isAlive() && _started)
277             {
278               try
279               {
280                 Thread.sleep(100 + ((int) Math.random() * 100));
281
282               } catch (Exception e)
283               {
284               }
285
286             }
287             // and call ourselves again.
288             addStructure(pdbentry, seq, chains, b, alignFrame);
289           }
290         }).start();
291         return;
292       }
293     }
294     // otherwise, start adding the structure.
295     jmb.addSequenceAndChain(new PDBEntry[]
296     { pdbentry }, new SequenceI[][]
297     { seq }, new String[][]
298     { chains });
299     addingStructures = true;
300     _started = false;
301     alignAddedStructures = b;
302     progressBar = alignFrame; // visual indication happens on caller frame.
303     (worker = new Thread(this)).start();
304     return;
305   }
306
307   private Vector getJmolsFor(AlignmentPanel ap2)
308   {
309     Vector otherJmols = new Vector();
310     // Now this AppJmol is mapped to new sequences. We must add them to
311     // the exisiting array
312     JInternalFrame[] frames = Desktop.instance.getAllFrames();
313
314     for (int i = 0; i < frames.length; i++)
315     {
316       if (frames[i] instanceof AppJmol)
317       {
318         AppJmol topJmol = ((AppJmol) frames[i]);
319         if (topJmol.ap == ap2)
320         {
321           otherJmols.addElement(topJmol);
322         }
323       }
324     }
325     return otherJmols;
326   }
327
328   void initJmol(String command)
329   {
330     jmb.setFinishedInit(false);
331     renderPanel = new RenderPanel();
332     // TODO: consider waiting until the structure/view is fully loaded before
333     // displaying
334     this.getContentPane().add(renderPanel, java.awt.BorderLayout.CENTER);
335     jalview.gui.Desktop.addInternalFrame(this, jmb.getViewerTitle(),
336             getBounds().width, getBounds().height);
337     if (scriptWindow == null)
338     {
339       BorderLayout bl = new BorderLayout();
340       bl.setHgap(0);
341       bl.setVgap(0);
342       scriptWindow = new JPanel(bl);
343       scriptWindow.setVisible(false);
344     }
345     ;
346     jmb.allocateViewer(renderPanel, true, "", null, null, "", scriptWindow,
347             null);
348     jmb.newJmolPopup(true, "Jmol", true);
349     jmb.evalStateCommand(command);
350     jmb.setFinishedInit(true);
351   }
352
353   void setChainMenuItems(Vector chains)
354   {
355     chainMenu.removeAll();
356     if (chains == null)
357     {
358       return;
359     }
360     JMenuItem menuItem = new JMenuItem("All");
361     menuItem.addActionListener(new ActionListener()
362     {
363       public void actionPerformed(ActionEvent evt)
364       {
365         allChainsSelected = true;
366         for (int i = 0; i < chainMenu.getItemCount(); i++)
367         {
368           if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
369             ((JCheckBoxMenuItem) chainMenu.getItem(i)).setSelected(true);
370         }
371         centerViewer();
372         allChainsSelected = false;
373       }
374     });
375
376     chainMenu.add(menuItem);
377
378     for (int c = 0; c < chains.size(); c++)
379     {
380       menuItem = new JCheckBoxMenuItem(chains.elementAt(c).toString(), true);
381       menuItem.addItemListener(new ItemListener()
382       {
383         public void itemStateChanged(ItemEvent evt)
384         {
385           if (!allChainsSelected)
386             centerViewer();
387         }
388       });
389
390       chainMenu.add(menuItem);
391     }
392   }
393
394   boolean allChainsSelected = false;
395
396   private boolean alignAddedStructures = false;
397
398   void centerViewer()
399   {
400     Vector toshow = new Vector();
401     String lbl;
402     int mlength, p, mnum;
403     for (int i = 0; i < chainMenu.getItemCount(); i++)
404     {
405       if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
406       {
407         JCheckBoxMenuItem item = (JCheckBoxMenuItem) chainMenu.getItem(i);
408         if (item.isSelected())
409         {
410           toshow.addElement(item.getText());
411         }
412       }
413     }
414     jmb.centerViewer(toshow);
415   }
416
417   void closeViewer()
418   {
419     jmb.closeViewer();
420
421     // TODO: check for memory leaks where instance isn't finalised because jmb
422     // holds a reference to the window
423     jmb = null;
424   }
425
426   /**
427    * state flag for PDB retrieval thread
428    */
429   private boolean _started = false;
430
431   public void run()
432   {
433     _started = true;
434     String pdbid = "";
435     // todo - record which pdbids were successfuly imported.
436     StringBuffer errormsgs = new StringBuffer(), files = new StringBuffer();
437     try
438     {
439       String[] curfiles = jmb.getPdbFile(); // files currently in viewer
440       // TODO: replace with reference fetching/transfer code (validate PDBentry
441       // as a DBRef?)
442       jalview.ws.dbsources.Pdb pdbclient = new jalview.ws.dbsources.Pdb();
443       for (int pi = 0; pi < jmb.pdbentry.length; pi++)
444       {
445         String file = jmb.pdbentry[pi].getFile();
446         if (file == null)
447         {
448           // retrieve the pdb and store it locally
449           AlignmentI pdbseq = null;
450           pdbid = jmb.pdbentry[pi].getId();
451           long hdl = pdbid.hashCode() - System.currentTimeMillis();
452           if (progressBar != null)
453           {
454             progressBar.setProgressBar("Fetching PDB " + pdbid, hdl);
455           }
456           try
457           {
458             pdbseq = pdbclient.getSequenceRecords(pdbid = jmb.pdbentry[pi]
459                     .getId());
460           } catch (OutOfMemoryError oomerror)
461           {
462             new OOMWarning("Retrieving PDB id " + pdbid, oomerror);
463           } catch (Exception ex)
464           {
465             ex.printStackTrace();
466             errormsgs.append("'" + pdbid + "'");
467           }
468           if (progressBar != null)
469           {
470             progressBar.setProgressBar("Finished.", hdl);
471           }
472           if (pdbseq != null)
473           {
474             // just transfer the file name from the first sequence's first
475             // PDBEntry
476             jmb.pdbentry[pi].setFile(file = ((PDBEntry) pdbseq
477                     .getSequenceAt(0).getPDBId().elementAt(0)).getFile());
478             files.append(" \"" + file + "\"");
479           }
480           else
481           {
482             errormsgs.append("'" + pdbid + "' ");
483           }
484         }
485         else
486         {
487           if (curfiles != null && curfiles.length > 0)
488           {
489             addingStructures = true; // already files loaded.
490             for (int c = 0; c < curfiles.length; c++)
491             {
492               if (curfiles[c].equals(file))
493               {
494                 file = null;
495                 break;
496               }
497             }
498           }
499           if (file != null)
500           {
501             files.append(" \"" + file + "\"");
502           }
503         }
504       }
505     } catch (OutOfMemoryError oomerror)
506     {
507       new OOMWarning("Retrieving PDB files: " + pdbid, oomerror);
508     } catch (Exception ex)
509     {
510       ex.printStackTrace();
511       errormsgs.append("When retrieving pdbfiles : current was: '" + pdbid
512               + "'");
513     }
514     if (errormsgs.length() > 0)
515     {
516
517       JOptionPane.showInternalMessageDialog(Desktop.desktop,
518               "The following pdb entries could not be retrieved from the PDB:\n"
519                       + errormsgs.toString()
520                       + "\nPlease try downloading them manually.",
521               "Couldn't load file", JOptionPane.ERROR_MESSAGE);
522
523     }
524     if (files.length() > 0)
525     {
526       if (!addingStructures)
527       {
528
529         try
530         {
531           initJmol("load FILES " + files.toString());
532         } catch (OutOfMemoryError oomerror)
533         {
534           new OOMWarning("When trying to open the Jmol viewer!", oomerror);
535           Cache.log.debug("File locations are " + files);
536         } catch (Exception ex)
537         {
538           Cache.log.error("Couldn't open Jmol viewer!", ex);
539         }
540       }
541       else
542       {
543         StringBuffer cmd = new StringBuffer();
544         cmd.append("loadingJalviewdata=true\nload APPEND ");
545         cmd.append(files.toString());
546         cmd.append("\nloadingJalviewdata=null");
547         final String command = cmd.toString();
548         cmd = null;
549         try
550         {
551           jmb.evalStateCommand(command);
552         } catch (OutOfMemoryError oomerror)
553         {
554           new OOMWarning(
555                   "When trying to add structures to the Jmol viewer!",
556                   oomerror);
557           Cache.log.debug("File locations are " + files);
558         } catch (Exception ex)
559         {
560           Cache.log.error("Couldn't add files to Jmol viewer!", ex);
561         }
562         long lastnotify = jmb.getLoadNotifiesHandled();
563         // need to wait around until script has finished
564         while (lastnotify >= jmb.getLoadNotifiesHandled())
565           ;
566         {
567           try
568           {
569             Thread.sleep(35);
570           } catch (Exception e)
571           {
572           }
573         }
574         // refresh the sequence colours for the new structure(s)
575         jmb.updateColours(ap);
576         // do superposition if asked to
577         if (alignAddedStructures)
578         {
579           javax.swing.SwingUtilities.invokeLater(new Runnable()
580           {
581             public void run()
582             {
583               jmb.superposeStructures(ap.av.getAlignment(), -1, null);
584             }
585           });
586           alignAddedStructures = false;
587         }
588         addingStructures = false;
589       }
590     }
591     _started = false;
592     worker = null;
593   }
594
595   public void pdbFile_actionPerformed(ActionEvent actionEvent)
596   {
597     JalviewFileChooser chooser = new JalviewFileChooser(
598             jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
599
600     chooser.setFileView(new JalviewFileView());
601     chooser.setDialogTitle("Save PDB File");
602     chooser.setToolTipText("Save");
603
604     int value = chooser.showSaveDialog(this);
605
606     if (value == JalviewFileChooser.APPROVE_OPTION)
607     {
608       try
609       {
610         // TODO: cope with multiple PDB files in view
611         BufferedReader in = new BufferedReader(new FileReader(
612                 jmb.getPdbFile()[0]));
613         File outFile = chooser.getSelectedFile();
614
615         PrintWriter out = new PrintWriter(new FileOutputStream(outFile));
616         String data;
617         while ((data = in.readLine()) != null)
618         {
619           if (!(data.indexOf("<PRE>") > -1 || data.indexOf("</PRE>") > -1))
620           {
621             out.println(data);
622           }
623         }
624         out.close();
625       } catch (Exception ex)
626       {
627         ex.printStackTrace();
628       }
629     }
630   }
631
632   public void viewMapping_actionPerformed(ActionEvent actionEvent)
633   {
634     jalview.gui.CutAndPasteTransfer cap = new jalview.gui.CutAndPasteTransfer();
635     try
636     {
637       for (int pdbe = 0; pdbe < jmb.pdbentry.length; pdbe++)
638       {
639         cap.appendText(StructureSelectionManager
640                 .getStructureSelectionManager().printMapping(
641                         jmb.pdbentry[pdbe].getFile()));
642         cap.appendText("\n");
643       }
644     } catch (OutOfMemoryError e)
645     {
646       new OOMWarning(
647               "composing sequence-structure alignments for display in text box.",
648               e);
649       cap.dispose();
650       return;
651     }
652     jalview.gui.Desktop.addInternalFrame(cap, "PDB - Sequence Mapping",
653             550, 600);
654   }
655
656   /**
657    * DOCUMENT ME!
658    * 
659    * @param e
660    *          DOCUMENT ME!
661    */
662   public void eps_actionPerformed(ActionEvent e)
663   {
664     makePDBImage(jalview.util.ImageMaker.EPS);
665   }
666
667   /**
668    * DOCUMENT ME!
669    * 
670    * @param e
671    *          DOCUMENT ME!
672    */
673   public void png_actionPerformed(ActionEvent e)
674   {
675     makePDBImage(jalview.util.ImageMaker.PNG);
676   }
677
678   void makePDBImage(int type)
679   {
680     int width = getWidth();
681     int height = getHeight();
682
683     jalview.util.ImageMaker im;
684
685     if (type == jalview.util.ImageMaker.PNG)
686     {
687       im = new jalview.util.ImageMaker(this, jalview.util.ImageMaker.PNG,
688               "Make PNG image from view", width, height, null, null);
689     }
690     else
691     {
692       im = new jalview.util.ImageMaker(this, jalview.util.ImageMaker.EPS,
693               "Make EPS file from view", width, height, null,
694               this.getTitle());
695     }
696
697     if (im.getGraphics() != null)
698     {
699       Rectangle rect = new Rectangle(width, height);
700       jmb.viewer.renderScreenImage(im.getGraphics(), rect.getSize(), rect);
701       im.writeImage();
702     }
703   }
704
705   public void seqColour_actionPerformed(ActionEvent actionEvent)
706   {
707     jmb.setColourBySequence(seqColour.isSelected());
708     // Set the colour using the current view for the associated alignframe
709     jmb.colourBySequence(ap.alignFrame.viewport.showSequenceFeatures,
710             ap.alignFrame.viewport.alignment);
711   }
712
713   public void chainColour_actionPerformed(ActionEvent actionEvent)
714   {
715     chainColour.setSelected(true);
716     jmb.colourByChain();
717   }
718
719   public void chargeColour_actionPerformed(ActionEvent actionEvent)
720   {
721     chargeColour.setSelected(true);
722     jmb.colourByCharge();
723   }
724
725   public void zappoColour_actionPerformed(ActionEvent actionEvent)
726   {
727     zappoColour.setSelected(true);
728     jmb.setJalviewColourScheme(new ZappoColourScheme());
729   }
730
731   public void taylorColour_actionPerformed(ActionEvent actionEvent)
732   {
733     taylorColour.setSelected(true);
734     jmb.setJalviewColourScheme(new TaylorColourScheme());
735   }
736
737   public void hydroColour_actionPerformed(ActionEvent actionEvent)
738   {
739     hydroColour.setSelected(true);
740     jmb.setJalviewColourScheme(new HydrophobicColourScheme());
741   }
742
743   public void helixColour_actionPerformed(ActionEvent actionEvent)
744   {
745     helixColour.setSelected(true);
746     jmb.setJalviewColourScheme(new HelixColourScheme());
747   }
748
749   public void strandColour_actionPerformed(ActionEvent actionEvent)
750   {
751     strandColour.setSelected(true);
752     jmb.setJalviewColourScheme(new StrandColourScheme());
753   }
754
755   public void turnColour_actionPerformed(ActionEvent actionEvent)
756   {
757     turnColour.setSelected(true);
758     jmb.setJalviewColourScheme(new TurnColourScheme());
759   }
760
761   public void buriedColour_actionPerformed(ActionEvent actionEvent)
762   {
763     buriedColour.setSelected(true);
764     jmb.setJalviewColourScheme(new BuriedColourScheme());
765   }
766
767   public void userColour_actionPerformed(ActionEvent actionEvent)
768   {
769     userColour.setSelected(true);
770     new UserDefinedColours(this, null);
771   }
772
773   public void backGround_actionPerformed(ActionEvent actionEvent)
774   {
775     java.awt.Color col = JColorChooser.showDialog(this,
776             "Select Background Colour", null);
777     if (col != null)
778     {
779       jmb.setBackgroundColour(col);
780     }
781   }
782
783   public void jmolHelp_actionPerformed(ActionEvent actionEvent)
784   {
785     try
786     {
787       jalview.util.BrowserLauncher
788               .openURL("http://jmol.sourceforge.net/docs/JmolUserGuide/");
789     } catch (Exception ex)
790     {
791     }
792   }
793
794   public void showConsole(boolean showConsole)
795   {
796
797     if (showConsole)
798     {
799       if (splitPane == null)
800       {
801         splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
802         splitPane.setTopComponent(renderPanel);
803         splitPane.setBottomComponent(scriptWindow);
804         this.getContentPane().add(splitPane, BorderLayout.CENTER);
805         splitPane.setDividerLocation(getHeight() - 200);
806         scriptWindow.setVisible(true);
807         scriptWindow.validate();
808         splitPane.validate();
809       }
810
811     }
812     else
813     {
814       if (splitPane != null)
815       {
816         splitPane.setVisible(false);
817       }
818
819       splitPane = null;
820
821       this.getContentPane().add(renderPanel, BorderLayout.CENTER);
822     }
823
824     validate();
825   }
826
827   class RenderPanel extends JPanel
828   {
829     final Dimension currentSize = new Dimension();
830
831     final Rectangle rectClip = new Rectangle();
832
833     public void paintComponent(Graphics g)
834     {
835       getSize(currentSize);
836       g.getClipBounds(rectClip);
837
838       if (jmb.fileLoadingError != null)
839       {
840         g.setColor(Color.black);
841         g.fillRect(0, 0, currentSize.width, currentSize.height);
842         g.setColor(Color.white);
843         g.setFont(new Font("Verdana", Font.BOLD, 14));
844         g.drawString("Error loading file...", 20, currentSize.height / 2);
845         StringBuffer sb = new StringBuffer();
846         int lines = 0;
847         for (int e = 0; e < jmb.pdbentry.length; e++)
848         {
849           sb.append(jmb.pdbentry[e].getId());
850           if (e < jmb.pdbentry.length - 1)
851           {
852             sb.append(",");
853           }
854
855           if (e == jmb.pdbentry.length - 1 || sb.length() > 20)
856           {
857             lines++;
858             g.drawString(sb.toString(), 20, currentSize.height / 2 - lines
859                     * g.getFontMetrics().getHeight());
860           }
861         }
862       }
863       else if (jmb == null || jmb.viewer == null || !jmb.isFinishedInit())
864       {
865         g.setColor(Color.black);
866         g.fillRect(0, 0, currentSize.width, currentSize.height);
867         g.setColor(Color.white);
868         g.setFont(new Font("Verdana", Font.BOLD, 14));
869         g.drawString("Retrieving PDB data....", 20, currentSize.height / 2);
870       }
871       else
872       {
873         jmb.viewer.renderScreenImage(g, currentSize, rectClip);
874       }
875     }
876   }
877
878   String viewId = null;
879
880   public String getViewId()
881   {
882     if (viewId == null)
883     {
884       viewId = System.currentTimeMillis() + "." + this.hashCode();
885     }
886     return viewId;
887   }
888
889   public void updateTitleAndMenus()
890   {
891     if (jmb.fileLoadingError != null && jmb.fileLoadingError.length() > 0)
892     {
893       repaint();
894       return;
895     }
896     setChainMenuItems(jmb.chainNames);
897     jmb.colourBySequence(ap.av.getShowSequenceFeatures(), ap.av.alignment);
898
899     this.setTitle(jmb.getViewerTitle());
900     if (jmb.getPdbFile().length > 1 && jmb.sequence.length > 1)
901     {
902       jmolActionMenu.setVisible(true);
903     }
904   }
905
906   /*
907    * (non-Javadoc)
908    * 
909    * @see
910    * jalview.jbgui.GStructureViewer#alignStructs_actionPerformed(java.awt.event
911    * .ActionEvent)
912    */
913   @Override
914   protected void alignStructs_actionPerformed(ActionEvent actionEvent)
915   {
916
917     try
918     {
919       jmb.superposeStructures(ap.av.getAlignment(), -1,
920               ap.av.getColumnSelection());
921     } catch (Exception e)
922     {
923       Cache.log.info("Couldn't align structures in alignframe "
924               + ap.alignFrame.getTitle(), e);
925
926     }
927   }
928
929   public void setJalviewColourScheme(ColourSchemeI ucs)
930   {
931     jmb.setJalviewColourScheme(ucs);
932
933   }
934
935 }