ensure console contains build details in header
[jalview.git] / src / jalview / gui / Desktop.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)
3  * Copyright (C) 2009 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 jalview.bin.Cache;
22 import jalview.io.*;
23
24 import java.awt.*;
25 import java.awt.datatransfer.*;
26 import java.awt.dnd.*;
27 import java.awt.event.*;
28 import java.io.BufferedInputStream;
29 import java.io.BufferedOutputStream;
30 import java.io.File;
31 import java.io.FileOutputStream;
32 import java.io.InputStream;
33 import java.lang.reflect.Constructor;
34 import java.net.URL;
35 import java.net.URLConnection;
36 import java.nio.channels.ReadableByteChannel;
37 import java.util.*;
38
39 import javax.swing.*;
40 import javax.swing.event.MenuEvent;
41 import javax.swing.event.MenuListener;
42
43 /**
44  * DOCUMENT ME!
45  * 
46  * @author $author$
47  * @version $Revision$
48  */
49 public class Desktop extends jalview.jbgui.GDesktop implements
50         DropTargetListener, ClipboardOwner, IProgressIndicator
51 {
52   /** DOCUMENT ME!! */
53   public static Desktop instance;
54
55   // Need to decide if the Memory Usage is to be included in
56   // Next release or not.
57   public static MyDesktopPane desktop;
58
59   // public static JDesktopPane desktop;
60
61   static int openFrameCount = 0;
62
63   static final int xOffset = 30;
64
65   static final int yOffset = 30;
66
67   public static jalview.ws.Discoverer discoverer;
68
69   public static Object[] jalviewClipboard;
70
71   public static boolean internalCopy = false;
72
73   static int fileLoadingCount = 0;
74
75   /**
76    * Creates a new Desktop object.
77    */
78   public Desktop()
79   {
80     /**
81      * A note to implementors. It is ESSENTIAL that any activities that might
82      * block are spawned off as threads rather than waited for during this
83      * constructor.
84      */
85     instance = this;
86     doVamsasClientCheck();
87     doGroovyCheck();
88
89     setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
90     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
91     boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
92             false);
93     boolean showjconsole = jalview.bin.Cache.getDefault(
94             "SHOW_JAVA_CONSOLE", false);
95     desktop = new MyDesktopPane(selmemusage);
96     showMemusage.setSelected(selmemusage);
97     desktop.setBackground(Color.white);
98     getContentPane().setLayout(new BorderLayout());
99     getContentPane().add(desktop, BorderLayout.CENTER);
100     desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
101
102     // This line prevents Windows Look&Feel resizing all new windows to maximum
103     // if previous window was maximised
104     desktop.setDesktopManager(new DefaultDesktopManager());
105
106     Rectangle dims = getLastKnownDimensions("");
107     if (dims!=null)
108     {      
109       setBounds(dims);
110     }
111     else
112     {
113       Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
114       setBounds((int) (screenSize.width - 900) / 2,
115               (int) (screenSize.height - 650) / 2, 900, 650);
116     }
117     jconsole = new Console(this);
118     // immediately output essential build information
119     System.out.println("Jalview Desktop "+jalview.bin.Cache.getProperty("VERSION")+"\n"
120             +"Build Date: "
121             + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")+"\n"
122             + "Java version: " + System.getProperty("java.version")
123             + "\n"+System.getProperty("os.arch") + " "
124             + System.getProperty("os.name") + " "
125             + System.getProperty("os.version"));
126     
127     showConsole(showjconsole);
128
129     this.addWindowListener(new WindowAdapter()
130     {
131       public void windowClosing(WindowEvent evt)
132       {
133         quit();
134       }
135     });
136
137     this.addMouseListener(new MouseAdapter()
138     {
139       public void mousePressed(MouseEvent evt)
140       {
141         if (SwingUtilities.isRightMouseButton(evt))
142         {
143           showPasteMenu(evt.getX(), evt.getY());
144         }
145       }
146     });
147
148     this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
149     // Spawn a thread that shows the splashscreen
150     SwingUtilities.invokeLater(new Runnable()
151     {
152       public void run()
153       {
154         new SplashScreen();
155       }
156     });
157
158     discoverer = new jalview.ws.Discoverer(); // Only gets started if gui is
159     // displayed.
160   }
161
162   /**
163    * recover the last known dimensions for a jalview window
164    * @param windowName
165    *          - empty string is desktop, all other windows have unique prefix
166    * @return null or last known dimensions scaled to current geometry (if last
167    *         window geom was known)
168    */
169   Rectangle getLastKnownDimensions(String windowName)
170   {
171     // TODO: lock aspect ratio for scaling desktop Bug #0058199
172     Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
173     String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
174     String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
175     String width = jalview.bin.Cache.getProperty(windowName
176             + "SCREEN_WIDTH");
177     String height = jalview.bin.Cache.getProperty(windowName
178             + "SCREEN_HEIGHT");
179     if ((x != null) && (y != null) && (width != null) && (height != null))
180     {
181       int ix = Integer.parseInt(x), iy = Integer.parseInt(y), iw = Integer
182               .parseInt(width), ih = Integer.parseInt(height);
183       if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
184       {
185         // attempt #1 - try to cope with change in screen geometry - this
186         // version doesn't preserve original jv aspect ratio.
187         // take ratio of current screen size vs original screen size.
188         double sw = ( (1f*screenSize.width)
189                 / (1f*Integer.parseInt(jalview.bin.Cache
190                         .getProperty("SCREENGEOMETRY_WIDTH"))))
191                         ;
192         double sh = ( (1f*screenSize.height)
193                 / (1f*Integer.parseInt(jalview.bin.Cache
194                         .getProperty("SCREENGEOMETRY_HEIGHT"))));
195         // rescale the bounds depending upon the current screen geometry.
196         ix = (int) (ix * sw);
197         iw = (int) (iw * sw);
198         iy = (int) (iy * sh);
199         ih = (int) (ih * sh);
200         jalview.bin.Cache.log.debug("Got last known dimensions for "+windowName+": x:"+ix + " y:"+iy + " width:"+iw+" height:"+ih);
201       }
202       // return dimensions for new instance 
203       return new Rectangle(ix, iy, iw, ih);
204     }
205     return null;
206   }
207
208   private void doVamsasClientCheck()
209   {
210     if (jalview.bin.Cache.vamsasJarsPresent())
211     {
212       setupVamsasDisconnectedGui();
213       VamsasMenu.setVisible(true);
214       final Desktop us = this;
215       VamsasMenu.addMenuListener(new MenuListener()
216       {
217         // this listener remembers when the menu was first selected, and
218         // doesn't rebuild the session list until it has been cleared and
219         // reselected again.
220         boolean refresh = true;
221
222         public void menuCanceled(MenuEvent e)
223         {
224           refresh = true;
225         }
226
227         public void menuDeselected(MenuEvent e)
228         {
229           refresh = true;
230         }
231
232         public void menuSelected(MenuEvent e)
233         {
234           if (refresh)
235           {
236             us.buildVamsasStMenu();
237             refresh = false;
238           }
239         }
240       });
241       vamsasStart.setVisible(true);
242     }
243   }
244
245   void showPasteMenu(int x, int y)
246   {
247     JPopupMenu popup = new JPopupMenu();
248     JMenuItem item = new JMenuItem("Paste To New Window");
249     item.addActionListener(new ActionListener()
250     {
251       public void actionPerformed(ActionEvent evt)
252       {
253         paste();
254       }
255     });
256
257     popup.add(item);
258     popup.show(this, x, y);
259   }
260
261   public void paste()
262   {
263     try
264     {
265       Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
266       Transferable contents = c.getContents(this);
267
268       if (contents != null)
269       {
270         String file = (String) contents
271                 .getTransferData(DataFlavor.stringFlavor);
272
273         String format = new IdentifyFile().Identify(file,
274                 FormatAdapter.PASTE);
275
276         new FileLoader().LoadFile(file, FormatAdapter.PASTE, format);
277
278       }
279     } catch (Exception ex)
280     {
281       System.out
282               .println("Unable to paste alignment from system clipboard:\n"
283                       + ex);
284     }
285   }
286
287   /**
288    * DOCUMENT ME!
289    * 
290    * @param frame
291    *          DOCUMENT ME!
292    * @param title
293    *          DOCUMENT ME!
294    * @param w
295    *          DOCUMENT ME!
296    * @param h
297    *          DOCUMENT ME!
298    */
299   public static synchronized void addInternalFrame(
300           final JInternalFrame frame, String title, int w, int h)
301   {
302     addInternalFrame(frame, title, w, h, true);
303   }
304
305   /**
306    * DOCUMENT ME!
307    * 
308    * @param frame
309    *          DOCUMENT ME!
310    * @param title
311    *          DOCUMENT ME!
312    * @param w
313    *          DOCUMENT ME!
314    * @param h
315    *          DOCUMENT ME!
316    * @param resizable
317    *          DOCUMENT ME!
318    */
319   public static synchronized void addInternalFrame(
320           final JInternalFrame frame, String title, int w, int h,
321           boolean resizable)
322   {
323
324     // TODO: consider fixing method to update entries in the window submenu with
325     // the current window title
326
327     frame.setTitle(title);
328     if (frame.getWidth() < 1 || frame.getHeight() < 1)
329     {
330       frame.setSize(w, h);
331     }
332     // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
333     // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
334     // IF JALVIEW IS RUNNING HEADLESS
335     // ///////////////////////////////////////////////
336     if (System.getProperty("java.awt.headless") != null
337             && System.getProperty("java.awt.headless").equals("true"))
338     {
339       return;
340     }
341
342     openFrameCount++;
343
344     frame.setVisible(true);
345     frame.setClosable(true);
346     frame.setResizable(resizable);
347     frame.setMaximizable(resizable);
348     frame.setIconifiable(resizable);
349     frame.setFrameIcon(null);
350
351     if (frame.getX() < 1 && frame.getY() < 1)
352     {
353       frame.setLocation(xOffset * openFrameCount, yOffset
354               * ((openFrameCount - 1) % 10) + yOffset);
355     }
356
357     final JMenuItem menuItem = new JMenuItem(title);
358     frame
359             .addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
360             {
361               public void internalFrameActivated(
362                       javax.swing.event.InternalFrameEvent evt)
363               {
364                 JInternalFrame itf = desktop.getSelectedFrame();
365                 if (itf != null)
366                 {
367                   itf.requestFocus();
368                 }
369
370               }
371
372               public void internalFrameClosed(
373                       javax.swing.event.InternalFrameEvent evt)
374               {
375                 PaintRefresher.RemoveComponent(frame);
376                 openFrameCount--;
377                 windowMenu.remove(menuItem);
378                 JInternalFrame itf = desktop.getSelectedFrame();
379                 if (itf != null)
380                 {
381                   itf.requestFocus();
382                 }
383                 System.gc();
384               };
385             });
386
387     menuItem.addActionListener(new ActionListener()
388     {
389       public void actionPerformed(ActionEvent e)
390       {
391         try
392         {
393           frame.setSelected(true);
394           frame.setIcon(false);
395         } catch (java.beans.PropertyVetoException ex)
396         {
397
398         }
399       }
400     });
401
402     windowMenu.add(menuItem);
403
404     desktop.add(frame);
405     frame.toFront();
406     try
407     {
408       frame.setSelected(true);
409       frame.requestFocus();
410     } catch (java.beans.PropertyVetoException ve)
411     {
412     }
413   }
414
415   public void lostOwnership(Clipboard clipboard, Transferable contents)
416   {
417     if (!internalCopy)
418     {
419       Desktop.jalviewClipboard = null;
420     }
421
422     internalCopy = false;
423   }
424
425   public void dragEnter(DropTargetDragEvent evt)
426   {
427   }
428
429   public void dragExit(DropTargetEvent evt)
430   {
431   }
432
433   public void dragOver(DropTargetDragEvent evt)
434   {
435   }
436
437   public void dropActionChanged(DropTargetDragEvent evt)
438   {
439   }
440
441   /**
442    * DOCUMENT ME!
443    * 
444    * @param evt
445    *          DOCUMENT ME!
446    */
447   public void drop(DropTargetDropEvent evt)
448   {
449     Transferable t = evt.getTransferable();
450     java.util.List files = null;
451     java.util.List protocols = null;
452
453     try
454     {
455       DataFlavor uriListFlavor = new DataFlavor(
456               "text/uri-list;class=java.lang.String");
457       if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
458       {
459         // Works on Windows and MacOSX
460         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
461         files = (java.util.List) t
462                 .getTransferData(DataFlavor.javaFileListFlavor);
463       }
464       else if (t.isDataFlavorSupported(uriListFlavor))
465       {
466         // This is used by Unix drag system
467         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
468         String data = (String) t.getTransferData(uriListFlavor);
469         files = new java.util.ArrayList(1);
470         protocols = new java.util.ArrayList(1);
471         for (java.util.StringTokenizer st = new java.util.StringTokenizer(
472                 data, "\r\n"); st.hasMoreTokens();)
473         {
474           String s = st.nextToken();
475           if (s.startsWith("#"))
476           {
477             // the line is a comment (as per the RFC 2483)
478             continue;
479           }
480           java.net.URI uri = new java.net.URI(s);
481           if (uri.getScheme().toLowerCase().startsWith("http"))
482           {
483             protocols.add(FormatAdapter.URL);
484             files.add(uri.toString());
485           }
486           else
487           {
488             // otherwise preserve old behaviour: catch all for file objects
489             java.io.File file = new java.io.File(uri);
490             protocols.add(FormatAdapter.FILE);
491             files.add(file.toString());
492           }
493         }
494       }
495     } catch (Exception e)
496     {
497     }
498
499     if (files != null)
500     {
501       try
502       {
503         for (int i = 0; i < files.size(); i++)
504         {
505           String file = files.get(i).toString();
506           String protocol = (protocols == null) ? FormatAdapter.FILE
507                   : (String) protocols.get(i);
508           String format = null;
509
510           if (file.endsWith(".jar"))
511           {
512             format = "Jalview";
513
514           }
515           else
516           {
517             format = new IdentifyFile().Identify(file, protocol);
518           }
519
520           new FileLoader().LoadFile(file, protocol, format);
521
522         }
523       } catch (Exception ex)
524       {
525       }
526     }
527   }
528
529   /**
530    * DOCUMENT ME!
531    * 
532    * @param e
533    *          DOCUMENT ME!
534    */
535   public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
536   {
537     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
538             .getProperty("LAST_DIRECTORY"),
539             jalview.io.AppletFormatAdapter.READABLE_EXTENSIONS,
540             jalview.io.AppletFormatAdapter.READABLE_FNAMES,
541             jalview.bin.Cache.getProperty("DEFAULT_FILE_FORMAT"));
542
543     chooser.setFileView(new JalviewFileView());
544     chooser.setDialogTitle("Open local file");
545     chooser.setToolTipText("Open");
546
547     int value = chooser.showOpenDialog(this);
548
549     if (value == JalviewFileChooser.APPROVE_OPTION)
550     {
551       String choice = chooser.getSelectedFile().getPath();
552       jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
553               .getSelectedFile().getParent());
554
555       String format = null;
556       if (chooser.getSelectedFormat().equals("Jalview"))
557       {
558         format = "Jalview";
559       }
560       else
561       {
562         format = new IdentifyFile().Identify(choice, FormatAdapter.FILE);
563       }
564
565       if (viewport != null)
566       {
567         new FileLoader().LoadFile(viewport, choice, FormatAdapter.FILE,
568                 format);
569       }
570       else
571       {
572         new FileLoader().LoadFile(choice, FormatAdapter.FILE, format);
573       }
574     }
575   }
576
577   /**
578    * DOCUMENT ME!
579    * 
580    * @param e
581    *          DOCUMENT ME!
582    */
583   public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
584   {
585     // This construct allows us to have a wider textfield
586     // for viewing
587     JLabel label = new JLabel("Enter URL of Input File");
588     final JComboBox history = new JComboBox();
589
590     JPanel panel = new JPanel(new GridLayout(2, 1));
591     panel.add(label);
592     panel.add(history);
593     history.setPreferredSize(new Dimension(400, 20));
594     history.setEditable(true);
595     history.addItem("http://www.");
596
597     String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
598
599     StringTokenizer st;
600
601     if (historyItems != null)
602     {
603       st = new StringTokenizer(historyItems, "\t");
604
605       while (st.hasMoreTokens())
606       {
607         history.addItem(st.nextElement());
608       }
609     }
610
611     int reply = JOptionPane.showInternalConfirmDialog(desktop, panel,
612             "Input Alignment From URL", JOptionPane.OK_CANCEL_OPTION);
613
614     if (reply != JOptionPane.OK_OPTION)
615     {
616       return;
617     }
618
619     String url = history.getSelectedItem().toString();
620
621     if (url.toLowerCase().endsWith(".jar"))
622     {
623       if (viewport != null)
624       {
625         new FileLoader().LoadFile(viewport, url, FormatAdapter.URL,
626                 "Jalview");
627       }
628       else
629       {
630         new FileLoader().LoadFile(url, FormatAdapter.URL, "Jalview");
631       }
632     }
633     else
634     {
635       String format = new IdentifyFile().Identify(url, FormatAdapter.URL);
636
637       if (format.equals("URL NOT FOUND"))
638       {
639         JOptionPane.showInternalMessageDialog(Desktop.desktop,
640                 "Couldn't locate " + url, "URL not found",
641                 JOptionPane.WARNING_MESSAGE);
642
643         return;
644       }
645
646       if (viewport != null)
647       {
648         new FileLoader().LoadFile(viewport, url, FormatAdapter.URL, format);
649       }
650       else
651       {
652         new FileLoader().LoadFile(url, FormatAdapter.URL, format);
653       }
654     }
655   }
656
657   /**
658    * DOCUMENT ME!
659    * 
660    * @param e
661    *          DOCUMENT ME!
662    */
663   public void inputTextboxMenuItem_actionPerformed(AlignViewport viewport)
664   {
665     CutAndPasteTransfer cap = new CutAndPasteTransfer();
666     cap.setForInput(viewport);
667     Desktop.addInternalFrame(cap, "Cut & Paste Alignment File", 600, 500);
668   }
669
670   /*
671    * Exit the program
672    */
673   public void quit()
674   {
675     Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
676     jalview.bin.Cache
677             .setProperty("SCREENGEOMETRY_WIDTH", screen.width + "");
678     jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT", screen.height
679             + "");
680     storeLastKnownDimensions("",new Rectangle(getBounds().x,getBounds().y, getWidth(), getHeight()));
681
682     if (jconsole != null)
683     {
684       storeLastKnownDimensions("JAVA_CONSOLE_",jconsole.getBounds());
685       jconsole.stopConsole();
686     }
687     System.exit(0);
688   }
689
690   private void storeLastKnownDimensions(String string, Rectangle jc)
691   {
692     jalview.bin.Cache.log.debug("Storing last known dimensions for "+string+": x:"+jc.x + " y:"+jc.y + " width:"+jc.width+" height:"+jc.height);
693     
694     jalview.bin.Cache.setProperty(string+"SCREEN_X",jc.x + "");
695     jalview.bin.Cache.setProperty(string+"SCREEN_Y", jc.y + "");
696     jalview.bin.Cache.setProperty(string+"SCREEN_WIDTH", jc.width + "");
697     jalview.bin.Cache.setProperty(string+"SCREEN_HEIGHT", jc.height
698             + "");
699   }
700
701   /**
702    * DOCUMENT ME!
703    * 
704    * @param e
705    *          DOCUMENT ME!
706    */
707   public void aboutMenuItem_actionPerformed(ActionEvent e)
708   {
709     StringBuffer message = new StringBuffer("Jalview version "
710             + jalview.bin.Cache.getProperty("VERSION") + "; last updated: "
711             + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
712
713     if (!jalview.bin.Cache.getProperty("LATEST_VERSION").equals(
714             jalview.bin.Cache.getProperty("VERSION")))
715     {
716       message
717               .append("\n\n!! Jalview version "
718                       + jalview.bin.Cache.getProperty("LATEST_VERSION")
719                       + " is available for download from http://www.jalview.org !!\n");
720
721     }
722     // TODO: update this text for each release or centrally store it for lite
723     // and application
724     message
725             .append("\nAuthors:  Andrew Waterhouse, Jim Procter, Michele Clamp, James Cuff, Steve Searle,\n    David Martin & Geoff Barton."
726                     + "\nDevelopment managed by The Barton Group, University of Dundee, Scotland, UK.\n"
727                     + "\nFor help, see the FAQ at www.jalview.org and/or join the jalview-discuss@jalview.org mailing list\n"
728                     + "\nIf  you use Jalview, please cite:"
729                     + "\nWaterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
730                     + "\nJalview Version 2 - a multiple sequence alignment editor and analysis workbench"
731                     + "\nBioinformatics doi: 10.1093/bioinformatics/btp033");
732     JOptionPane.showInternalMessageDialog(Desktop.desktop,
733
734     message.toString(), "About Jalview", JOptionPane.INFORMATION_MESSAGE);
735   }
736
737   /**
738    * DOCUMENT ME!
739    * 
740    * @param e
741    *          DOCUMENT ME!
742    */
743   public void documentationMenuItem_actionPerformed(ActionEvent e)
744   {
745     try
746     {
747       ClassLoader cl = jalview.gui.Desktop.class.getClassLoader();
748       java.net.URL url = javax.help.HelpSet.findHelpSet(cl, "help/help");
749       javax.help.HelpSet hs = new javax.help.HelpSet(cl, url);
750
751       javax.help.HelpBroker hb = hs.createHelpBroker();
752       hb.setCurrentID("home");
753       hb.setDisplayed(true);
754     } catch (Exception ex)
755     {
756     }
757   }
758
759   public void closeAll_actionPerformed(ActionEvent e)
760   {
761     JInternalFrame[] frames = desktop.getAllFrames();
762     for (int i = 0; i < frames.length; i++)
763     {
764       try
765       {
766         frames[i].setClosed(true);
767       } catch (java.beans.PropertyVetoException ex)
768       {
769       }
770     }
771     System.out.println("ALL CLOSED");
772     if (v_client != null)
773     {
774       // TODO clear binding to vamsas document objects on close_all
775
776     }
777   }
778
779   public void raiseRelated_actionPerformed(ActionEvent e)
780   {
781     reorderAssociatedWindows(false, false);
782   }
783
784   public void minimizeAssociated_actionPerformed(ActionEvent e)
785   {
786     reorderAssociatedWindows(true, false);
787   }
788
789   void closeAssociatedWindows()
790   {
791     reorderAssociatedWindows(false, true);
792   }
793
794   /*
795    * (non-Javadoc)
796    * 
797    * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
798    * ActionEvent)
799    */
800   protected void garbageCollect_actionPerformed(ActionEvent e)
801   {
802     // We simply collect the garbage
803     jalview.bin.Cache.log.debug("Collecting garbage...");
804     System.gc();
805     jalview.bin.Cache.log.debug("Finished garbage collection.");
806   }
807
808   /*
809    * (non-Javadoc)
810    * 
811    * @see
812    * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
813    * )
814    */
815   protected void showMemusage_actionPerformed(ActionEvent e)
816   {
817     desktop.showMemoryUsage(showMemusage.isSelected());
818   }
819
820   /*
821    * (non-Javadoc)
822    * 
823    * @see
824    * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
825    * )
826    */
827   protected void showConsole_actionPerformed(ActionEvent e)
828   {
829     showConsole(showConsole.isSelected());
830   }
831
832   Console jconsole = null;
833
834   /**
835    * control whether the java console is visible or not
836    * 
837    * @param selected
838    */
839   void showConsole(boolean selected)
840   {
841     showConsole.setSelected(selected);
842     // TODO: decide if we should update properties file
843     Cache.setProperty("SHOW_JAVA_CONSOLE", Boolean.valueOf(selected)
844             .toString());
845     jconsole.setVisible(selected);
846   }
847
848   void reorderAssociatedWindows(boolean minimize, boolean close)
849   {
850     JInternalFrame[] frames = desktop.getAllFrames();
851     if (frames == null || frames.length < 1)
852     {
853       return;
854     }
855
856     AlignViewport source = null, target = null;
857     if (frames[0] instanceof AlignFrame)
858     {
859       source = ((AlignFrame) frames[0]).getCurrentView();
860     }
861     else if (frames[0] instanceof TreePanel)
862     {
863       source = ((TreePanel) frames[0]).getViewPort();
864     }
865     else if (frames[0] instanceof PCAPanel)
866     {
867       source = ((PCAPanel) frames[0]).av;
868     }
869     else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
870     {
871       source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
872     }
873
874     if (source != null)
875     {
876       for (int i = 0; i < frames.length; i++)
877       {
878         target = null;
879         if (frames[i] == null)
880         {
881           continue;
882         }
883         if (frames[i] instanceof AlignFrame)
884         {
885           target = ((AlignFrame) frames[i]).getCurrentView();
886         }
887         else if (frames[i] instanceof TreePanel)
888         {
889           target = ((TreePanel) frames[i]).getViewPort();
890         }
891         else if (frames[i] instanceof PCAPanel)
892         {
893           target = ((PCAPanel) frames[i]).av;
894         }
895         else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
896         {
897           target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
898         }
899
900         if (source == target)
901         {
902           try
903           {
904             if (close)
905             {
906               frames[i].setClosed(true);
907             }
908             else
909             {
910               frames[i].setIcon(minimize);
911               if (!minimize)
912               {
913                 frames[i].toFront();
914               }
915             }
916
917           } catch (java.beans.PropertyVetoException ex)
918           {
919           }
920         }
921       }
922     }
923   }
924
925   /**
926    * DOCUMENT ME!
927    * 
928    * @param e
929    *          DOCUMENT ME!
930    */
931   protected void preferences_actionPerformed(ActionEvent e)
932   {
933     new Preferences();
934   }
935
936   /**
937    * DOCUMENT ME!
938    * 
939    * @param e
940    *          DOCUMENT ME!
941    */
942   public void saveState_actionPerformed(ActionEvent e)
943   {
944     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
945             .getProperty("LAST_DIRECTORY"), new String[]
946     { "jar" }, new String[]
947     { "Jalview Project" }, "Jalview Project");
948
949     chooser.setFileView(new JalviewFileView());
950     chooser.setDialogTitle("Save State");
951
952     int value = chooser.showSaveDialog(this);
953
954     if (value == JalviewFileChooser.APPROVE_OPTION)
955     {
956       java.io.File choice = chooser.getSelectedFile();
957       JProgressBar progpanel = addProgressPanel("Saving jalview project "
958               + choice.getName());
959       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice.getParent());
960       // TODO catch and handle errors for savestate
961       new Jalview2XML().SaveState(choice);
962       removeProgressPanel(progpanel);
963
964     }
965   }
966
967   /**
968    * DOCUMENT ME!
969    * 
970    * @param e
971    *          DOCUMENT ME!
972    */
973   public void loadState_actionPerformed(ActionEvent e)
974   {
975     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
976             .getProperty("LAST_DIRECTORY"), new String[]
977     { "jar" }, new String[]
978     { "Jalview Project" }, "Jalview Project");
979     chooser.setFileView(new JalviewFileView());
980     chooser.setDialogTitle("Restore state");
981
982     int value = chooser.showOpenDialog(this);
983
984     if (value == JalviewFileChooser.APPROVE_OPTION)
985     {
986       String choice = chooser.getSelectedFile().getAbsolutePath();
987       setProgressBar("loading jalview project "
988               + chooser.getSelectedFile().getName(), choice.hashCode());
989       jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
990               .getSelectedFile().getParent());
991       new Jalview2XML().LoadJalviewAlign(choice);
992       setProgressBar(null, choice.hashCode());
993     }
994   }
995
996   public void inputSequence_actionPerformed(ActionEvent e)
997   {
998     new SequenceFetcher(this);
999   }
1000
1001   JPanel progressPanel;
1002
1003   public void startLoading(final String fileName)
1004   {
1005     if (fileLoadingCount == 0)
1006     {
1007       addProgressPanel("Loading File: " + fileName + "   ");
1008
1009     }
1010     fileLoadingCount++;
1011   }
1012
1013   private JProgressBar addProgressPanel(String string)
1014   {
1015     if (progressPanel == null)
1016     {
1017       progressPanel = new JPanel(new BorderLayout());
1018       totalProgressCount = 0;
1019     }
1020     JProgressBar progressBar = new JProgressBar();
1021     progressBar.setIndeterminate(true);
1022
1023     progressPanel.add(new JLabel(string), BorderLayout.WEST);
1024
1025     progressPanel.add(progressBar, BorderLayout.CENTER);
1026
1027     instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1028     totalProgressCount++;
1029     validate();
1030     return progressBar;
1031   }
1032
1033   int totalProgressCount = 0;
1034
1035   private void removeProgressPanel(JProgressBar progbar)
1036   {
1037     if (progressPanel != null)
1038     {
1039       progressPanel.remove(progbar);
1040       if (--totalProgressCount < 1)
1041       {
1042         this.getContentPane().remove(progressPanel);
1043         progressPanel = null;
1044       }
1045     }
1046     validate();
1047   }
1048
1049   public void stopLoading()
1050   {
1051     fileLoadingCount--;
1052     if (fileLoadingCount < 1)
1053     {
1054       if (progressPanel != null)
1055       {
1056         this.getContentPane().remove(progressPanel);
1057         progressPanel = null;
1058       }
1059       fileLoadingCount = 0;
1060     }
1061     validate();
1062   }
1063
1064   public static int getViewCount(String viewId)
1065   {
1066     AlignViewport[] aps = getViewports(viewId);
1067     return (aps == null) ? 0 : aps.length;
1068   }
1069
1070   /**
1071    * 
1072    * @param viewId
1073    * @return all AlignmentPanels concerning the viewId sequence set
1074    */
1075   public static AlignmentPanel[] getAlignmentPanels(String viewId)
1076   {
1077     int count = 0;
1078     if (Desktop.desktop == null)
1079     {
1080       // no frames created and in headless mode
1081       // TODO: verify that frames are recoverable when in headless mode
1082       return null;
1083     }
1084     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1085     ArrayList aps = new ArrayList();
1086     for (int t = 0; t < frames.length; t++)
1087     {
1088       if (frames[t] instanceof AlignFrame)
1089       {
1090         AlignFrame af = (AlignFrame) frames[t];
1091         for (int a = 0; a < af.alignPanels.size(); a++)
1092         {
1093           if (viewId
1094                   .equals(((AlignmentPanel) af.alignPanels.elementAt(a)).av
1095                           .getSequenceSetId()))
1096           {
1097             aps.add(af.alignPanels.elementAt(a));
1098           }
1099         }
1100       }
1101     }
1102     if (aps.size() == 0)
1103     {
1104       return null;
1105     }
1106     AlignmentPanel[] vap = new AlignmentPanel[aps.size()];
1107     for (int t = 0; t < vap.length; t++)
1108     {
1109       vap[t] = (AlignmentPanel) aps.get(t);
1110     }
1111     return vap;
1112   }
1113
1114   /**
1115    * get all the viewports on an alignment.
1116    * 
1117    * @param sequenceSetId
1118    *          unique alignment id
1119    * @return all viewports on the alignment bound to sequenceSetId
1120    */
1121   public static AlignViewport[] getViewports(String sequenceSetId)
1122   {
1123     Vector viewp = new Vector();
1124     if (desktop != null)
1125     {
1126       javax.swing.JInternalFrame[] frames = instance.getAllFrames();
1127
1128       for (int t = 0; t < frames.length; t++)
1129       {
1130         if (frames[t] instanceof AlignFrame)
1131         {
1132           AlignFrame afr = ((AlignFrame) frames[t]);
1133           if (afr.getViewport().getSequenceSetId().equals(sequenceSetId))
1134           {
1135             if (afr.alignPanels != null)
1136             {
1137               for (int a = 0; a < afr.alignPanels.size(); a++)
1138               {
1139                 if (sequenceSetId.equals(((AlignmentPanel) afr.alignPanels
1140                         .elementAt(a)).av.getSequenceSetId()))
1141                 {
1142                   viewp.addElement(((AlignmentPanel) afr.alignPanels
1143                           .elementAt(a)).av);
1144                 }
1145               }
1146             }
1147             else
1148             {
1149               viewp.addElement(((AlignFrame) frames[t]).getViewport());
1150             }
1151           }
1152         }
1153       }
1154       if (viewp.size() > 0)
1155       {
1156         AlignViewport[] vp = new AlignViewport[viewp.size()];
1157         viewp.copyInto(vp);
1158         return vp;
1159       }
1160     }
1161     return null;
1162   }
1163
1164   public void explodeViews(AlignFrame af)
1165   {
1166     int size = af.alignPanels.size();
1167     if (size < 2)
1168     {
1169       return;
1170     }
1171
1172     for (int i = 0; i < size; i++)
1173     {
1174       AlignmentPanel ap = (AlignmentPanel) af.alignPanels.elementAt(i);
1175       AlignFrame newaf = new AlignFrame(ap);
1176       if (ap.av.explodedPosition != null
1177               && !ap.av.explodedPosition.equals(af.getBounds()))
1178       {
1179         newaf.setBounds(ap.av.explodedPosition);
1180       }
1181
1182       ap.av.gatherViewsHere = false;
1183
1184       addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1185               AlignFrame.DEFAULT_HEIGHT);
1186     }
1187
1188     af.alignPanels.clear();
1189     af.closeMenuItem_actionPerformed(true);
1190
1191   }
1192
1193   public void gatherViews(AlignFrame source)
1194   {
1195     source.viewport.gatherViewsHere = true;
1196     source.viewport.explodedPosition = source.getBounds();
1197     JInternalFrame[] frames = desktop.getAllFrames();
1198     String viewId = source.viewport.sequenceSetID;
1199
1200     for (int t = 0; t < frames.length; t++)
1201     {
1202       if (frames[t] instanceof AlignFrame && frames[t] != source)
1203       {
1204         AlignFrame af = (AlignFrame) frames[t];
1205         boolean gatherThis = false;
1206         for (int a = 0; a < af.alignPanels.size(); a++)
1207         {
1208           AlignmentPanel ap = (AlignmentPanel) af.alignPanels.elementAt(a);
1209           if (viewId.equals(ap.av.getSequenceSetId()))
1210           {
1211             gatherThis = true;
1212             ap.av.gatherViewsHere = false;
1213             ap.av.explodedPosition = af.getBounds();
1214             source.addAlignmentPanel(ap, false);
1215           }
1216         }
1217
1218         if (gatherThis)
1219         {
1220           af.alignPanels.clear();
1221           af.closeMenuItem_actionPerformed(true);
1222         }
1223       }
1224     }
1225
1226   }
1227
1228   jalview.gui.VamsasApplication v_client = null;
1229
1230   public void vamsasImport_actionPerformed(ActionEvent e)
1231   {
1232     if (v_client == null)
1233     {
1234       // Load and try to start a session.
1235       JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
1236               .getProperty("LAST_DIRECTORY"));
1237
1238       chooser.setFileView(new JalviewFileView());
1239       chooser.setDialogTitle("Open a saved VAMSAS session");
1240       chooser
1241               .setToolTipText("select a vamsas session to be opened as a new vamsas session.");
1242
1243       int value = chooser.showOpenDialog(this);
1244
1245       if (value == JalviewFileChooser.APPROVE_OPTION)
1246       {
1247         String fle = chooser.getSelectedFile().toString();
1248         if (!vamsasImport(chooser.getSelectedFile()))
1249         {
1250           JOptionPane.showInternalMessageDialog(Desktop.desktop,
1251                   "Couldn't import '" + fle + "' as a new vamsas session.",
1252                   "Vamsas Document Import Failed",
1253                   JOptionPane.ERROR_MESSAGE);
1254         }
1255       }
1256     }
1257     else
1258     {
1259       jalview.bin.Cache.log
1260               .error("Implementation error - load session from a running session is not supported.");
1261     }
1262   }
1263
1264   /**
1265    * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
1266    * 
1267    * @param file
1268    * @return true if import was a success and a session was started.
1269    */
1270   public boolean vamsasImport(URL url)
1271   {
1272     // TODO: create progress bar
1273     if (v_client != null)
1274     {
1275
1276       jalview.bin.Cache.log
1277               .error("Implementation error - load session from a running session is not supported.");
1278       return false;
1279     }
1280
1281     try
1282     {
1283       // copy the URL content to a temporary local file
1284       // TODO: be a bit cleverer here with nio (?!)
1285       File file = File.createTempFile("vdocfromurl", ".vdj");
1286       FileOutputStream fos = new FileOutputStream(file);
1287       BufferedInputStream bis = new BufferedInputStream(url.openStream());
1288       byte[] buffer = new byte[2048];
1289       int ln;
1290       while ((ln = bis.read(buffer)) > -1)
1291       {
1292         fos.write(buffer, 0, ln);
1293       }
1294       bis.close();
1295       fos.close();
1296       v_client = new jalview.gui.VamsasApplication(this, file, url
1297               .toExternalForm());
1298     } catch (Exception ex)
1299     {
1300       jalview.bin.Cache.log.error(
1301               "Failed to create new vamsas session from contents of URL "
1302                       + url, ex);
1303       return false;
1304     }
1305     setupVamsasConnectedGui();
1306     v_client.initial_update(); // TODO: thread ?
1307     return v_client.inSession();
1308   }
1309
1310   /**
1311    * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
1312    * 
1313    * @param file
1314    * @return true if import was a success and a session was started.
1315    */
1316   public boolean vamsasImport(File file)
1317   {
1318     if (v_client != null)
1319     {
1320
1321       jalview.bin.Cache.log
1322               .error("Implementation error - load session from a running session is not supported.");
1323       return false;
1324     }
1325
1326     setProgressBar("Importing VAMSAS session from " + file.getName(), file
1327             .hashCode());
1328     try
1329     {
1330       v_client = new jalview.gui.VamsasApplication(this, file, null);
1331     } catch (Exception ex)
1332     {
1333       setProgressBar("Importing VAMSAS session from " + file.getName(),
1334               file.hashCode());
1335       jalview.bin.Cache.log.error(
1336               "New vamsas session from existing session file failed:", ex);
1337       return false;
1338     }
1339     setupVamsasConnectedGui();
1340     v_client.initial_update(); // TODO: thread ?
1341     setProgressBar("Importing VAMSAS session from " + file.getName(), file
1342             .hashCode());
1343     return v_client.inSession();
1344   }
1345
1346   public boolean joinVamsasSession(String mysesid)
1347   {
1348     if (v_client != null)
1349     {
1350       throw new Error(
1351               "Trying to join a vamsas session when another is already connected.");
1352     }
1353     if (mysesid == null)
1354     {
1355       throw new Error("Invalid vamsas session id.");
1356     }
1357     v_client = new VamsasApplication(this, mysesid);
1358     setupVamsasConnectedGui();
1359     v_client.initial_update();
1360     return (v_client.inSession());
1361   }
1362
1363   public void vamsasStart_actionPerformed(ActionEvent e)
1364   {
1365     if (v_client == null)
1366     {
1367       // Start a session.
1368       // we just start a default session for moment.
1369       /*
1370        * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
1371        * getProperty("LAST_DIRECTORY"));
1372        * 
1373        * chooser.setFileView(new JalviewFileView());
1374        * chooser.setDialogTitle("Load Vamsas file");
1375        * chooser.setToolTipText("Import");
1376        * 
1377        * int value = chooser.showOpenDialog(this);
1378        * 
1379        * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
1380        * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
1381        */
1382       v_client = new VamsasApplication(this);
1383       setupVamsasConnectedGui();
1384       v_client.initial_update(); // TODO: thread ?
1385     }
1386     else
1387     {
1388       // store current data in session.
1389       v_client.push_update(); // TODO: thread
1390     }
1391   }
1392
1393   protected void setupVamsasConnectedGui()
1394   {
1395     vamsasStart.setText("Session Update");
1396     vamsasSave.setVisible(true);
1397     vamsasStop.setVisible(true);
1398     vamsasImport.setVisible(false); // Document import to existing session is
1399     // not possible for vamsas-client-1.0.
1400   }
1401
1402   protected void setupVamsasDisconnectedGui()
1403   {
1404     vamsasSave.setVisible(false);
1405     vamsasStop.setVisible(false);
1406     vamsasImport.setVisible(true);
1407     vamsasStart.setText("New Vamsas Session");
1408   }
1409
1410   public void vamsasStop_actionPerformed(ActionEvent e)
1411   {
1412     if (v_client != null)
1413     {
1414       v_client.end_session();
1415       v_client = null;
1416       setupVamsasDisconnectedGui();
1417     }
1418   }
1419
1420   protected void buildVamsasStMenu()
1421   {
1422     if (v_client == null)
1423     {
1424       String[] sess = null;
1425       try
1426       {
1427         sess = VamsasApplication.getSessionList();
1428       } catch (Exception e)
1429       {
1430         jalview.bin.Cache.log.warn(
1431                 "Problem getting current sessions list.", e);
1432         sess = null;
1433       }
1434       if (sess != null)
1435       {
1436         jalview.bin.Cache.log.debug("Got current sessions list: "
1437                 + sess.length + " entries.");
1438         VamsasStMenu.removeAll();
1439         for (int i = 0; i < sess.length; i++)
1440         {
1441           JMenuItem sessit = new JMenuItem();
1442           sessit.setText(sess[i]);
1443           sessit.setToolTipText("Connect to session " + sess[i]);
1444           final Desktop dsktp = this;
1445           final String mysesid = sess[i];
1446           sessit.addActionListener(new ActionListener()
1447           {
1448
1449             public void actionPerformed(ActionEvent e)
1450             {
1451               if (dsktp.v_client == null)
1452               {
1453                 Thread rthr = new Thread(new Runnable()
1454                 {
1455
1456                   public void run()
1457                   {
1458                     dsktp.v_client = new VamsasApplication(dsktp, mysesid);
1459                     dsktp.setupVamsasConnectedGui();
1460                     dsktp.v_client.initial_update();
1461                   }
1462
1463                 });
1464                 rthr.start();
1465               }
1466             };
1467           });
1468           VamsasStMenu.add(sessit);
1469         }
1470         // don't show an empty menu.
1471         VamsasStMenu.setVisible(sess.length > 0);
1472
1473       }
1474       else
1475       {
1476         jalview.bin.Cache.log.debug("No current vamsas sessions.");
1477         VamsasStMenu.removeAll();
1478         VamsasStMenu.setVisible(false);
1479       }
1480     }
1481     else
1482     {
1483       // Not interested in the content. Just hide ourselves.
1484       VamsasStMenu.setVisible(false);
1485     }
1486   }
1487
1488   public void vamsasSave_actionPerformed(ActionEvent e)
1489   {
1490     if (v_client != null)
1491     {
1492       JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
1493               .getProperty("LAST_DIRECTORY"), new String[]
1494       { "vdj" }, // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
1495               new String[]
1496               { "Vamsas Document" }, "Vamsas Document");
1497
1498       chooser.setFileView(new JalviewFileView());
1499       chooser.setDialogTitle("Save Vamsas Document Archive");
1500
1501       int value = chooser.showSaveDialog(this);
1502
1503       if (value == JalviewFileChooser.APPROVE_OPTION)
1504       {
1505         java.io.File choice = chooser.getSelectedFile();
1506         JProgressBar progpanel = addProgressPanel("Saving VAMSAS Document to "
1507                 + choice.getName());
1508         jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice.getParent());
1509         String warnmsg = null;
1510         String warnttl = null;
1511         try
1512         {
1513           v_client.vclient.storeDocument(choice);
1514         } catch (Error ex)
1515         {
1516           warnttl = "Serious Problem saving Vamsas Document";
1517           warnmsg = ex.toString();
1518           jalview.bin.Cache.log.error("Error Whilst saving document to "
1519                   + choice, ex);
1520
1521         } catch (Exception ex)
1522         {
1523           warnttl = "Problem saving Vamsas Document.";
1524           warnmsg = ex.toString();
1525           jalview.bin.Cache.log.warn("Exception Whilst saving document to "
1526                   + choice, ex);
1527
1528         }
1529         removeProgressPanel(progpanel);
1530         if (warnmsg != null)
1531         {
1532           JOptionPane.showInternalMessageDialog(Desktop.desktop,
1533
1534           warnmsg, warnttl, JOptionPane.ERROR_MESSAGE);
1535         }
1536       }
1537     }
1538   }
1539
1540   JProgressBar vamUpdate = null;
1541
1542   /**
1543    * hide vamsas user gui bits when a vamsas document event is being handled.
1544    * 
1545    * @param b
1546    *          true to hide gui, false to reveal gui
1547    */
1548   public void setVamsasUpdate(boolean b)
1549   {
1550     jalview.bin.Cache.log.debug("Setting gui for Vamsas update "
1551             + (b ? "in progress" : "finished"));
1552
1553     if (vamUpdate != null)
1554     {
1555       this.removeProgressPanel(vamUpdate);
1556     }
1557     if (b)
1558     {
1559       vamUpdate = this.addProgressPanel("Updating vamsas session");
1560     }
1561     vamsasStart.setVisible(!b);
1562     vamsasStop.setVisible(!b);
1563     vamsasSave.setVisible(!b);
1564   }
1565
1566   public JInternalFrame[] getAllFrames()
1567   {
1568     return desktop.getAllFrames();
1569   }
1570
1571   /**
1572    * Checks the given url to see if it gives a response indicating that the user
1573    * should be informed of a new questionnaire.
1574    * 
1575    * @param url
1576    */
1577   public void checkForQuestionnaire(String url)
1578   {
1579     UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
1580     // javax.swing.SwingUtilities.invokeLater(jvq);
1581     new Thread(jvq).start();
1582   }
1583
1584   /**
1585    * Proxy class for JDesktopPane which optionally displays the current memory
1586    * usage and highlights the desktop area with a red bar if free memory runs
1587    * low.
1588    * 
1589    * @author AMW
1590    */
1591   public class MyDesktopPane extends JDesktopPane implements Runnable
1592   {
1593
1594     boolean showMemoryUsage = false;
1595
1596     Runtime runtime;
1597
1598     java.text.NumberFormat df;
1599
1600     float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
1601             percentUsage;
1602
1603     public MyDesktopPane(boolean showMemoryUsage)
1604     {
1605       showMemoryUsage(showMemoryUsage);
1606     }
1607
1608     public void showMemoryUsage(boolean showMemoryUsage)
1609     {
1610       this.showMemoryUsage = showMemoryUsage;
1611       if (showMemoryUsage)
1612       {
1613         Thread worker = new Thread(this);
1614         worker.start();
1615       }
1616     }
1617
1618     public boolean isShowMemoryUsage()
1619     {
1620       return showMemoryUsage;
1621     }
1622
1623     public void run()
1624     {
1625       df = java.text.NumberFormat.getNumberInstance();
1626       df.setMaximumFractionDigits(2);
1627       runtime = Runtime.getRuntime();
1628
1629       while (showMemoryUsage)
1630       {
1631         try
1632         {
1633           maxMemory = runtime.maxMemory() / 1048576f;
1634           allocatedMemory = runtime.totalMemory() / 1048576f;
1635           freeMemory = runtime.freeMemory() / 1048576f;
1636           totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
1637
1638           percentUsage = (totalFreeMemory / maxMemory) * 100;
1639
1640           // if (percentUsage < 20)
1641           {
1642             // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
1643             // Color.red);
1644             // instance.set.setBorder(border1);
1645           }
1646           repaint();
1647           // sleep after showing usage
1648           Thread.sleep(3000);
1649         } catch (Exception ex)
1650         {
1651           ex.printStackTrace();
1652         }
1653       }
1654     }
1655
1656     public void paintComponent(Graphics g)
1657     {
1658       if (showMemoryUsage && g != null)
1659       {
1660         if (percentUsage < 20)
1661           g.setColor(Color.red);
1662         FontMetrics fm = g.getFontMetrics();
1663         if (fm!=null)
1664         { g.drawString("Total Free Memory: " + df.format(totalFreeMemory)
1665                 + "MB; Max Memory: " + df.format(maxMemory) + "MB; "
1666                 + df.format(percentUsage) + "%", 10, getHeight()
1667                 - fm.getHeight());
1668         }
1669       }
1670     }
1671
1672   }
1673
1674   protected JMenuItem groovyShell;
1675
1676   public void doGroovyCheck()
1677   {
1678     if (jalview.bin.Cache.groovyJarsPresent())
1679     {
1680       groovyShell = new JMenuItem();
1681       groovyShell.setText("Groovy Console...");
1682       groovyShell.addActionListener(new ActionListener()
1683       {
1684         public void actionPerformed(ActionEvent e)
1685         {
1686           groovyShell_actionPerformed(e);
1687         }
1688       });
1689       toolsMenu.add(groovyShell);
1690       groovyShell.setVisible(true);
1691     }
1692   }
1693
1694   /**
1695    * Accessor method to quickly get all the AlignmentFrames loaded.
1696    */
1697   public static AlignFrame[] getAlignframes()
1698   {
1699     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1700
1701     if (frames == null)
1702     {
1703       return null;
1704     }
1705     Vector avp = new Vector();
1706     try
1707     {
1708       // REVERSE ORDER
1709       for (int i = frames.length - 1; i > -1; i--)
1710       {
1711         if (frames[i] instanceof AlignFrame)
1712         {
1713           AlignFrame af = (AlignFrame) frames[i];
1714           avp.addElement(af);
1715         }
1716       }
1717     } catch (Exception ex)
1718     {
1719       ex.printStackTrace();
1720     }
1721     if (avp.size() == 0)
1722     {
1723       return null;
1724     }
1725     AlignFrame afs[] = new AlignFrame[avp.size()];
1726     for (int i = 0, j = avp.size(); i < j; i++)
1727     {
1728       afs[i] = (AlignFrame) avp.elementAt(i);
1729     }
1730     avp.clear();
1731     return afs;
1732   }
1733
1734   /**
1735    * Add Groovy Support to Jalview
1736    */
1737   public void groovyShell_actionPerformed(ActionEvent e)
1738   {
1739     // use reflection to avoid creating compilation dependency.
1740     if (!jalview.bin.Cache.groovyJarsPresent())
1741     {
1742       throw new Error(
1743               "Implementation Error. Cannot create groovyShell without Groovy on the classpath!");
1744     }
1745     try
1746     {
1747       Class gcClass = Desktop.class.getClassLoader().loadClass(
1748               "groovy.ui.Console");
1749       Constructor gccons = gcClass.getConstructor(null);
1750       java.lang.reflect.Method setvar = gcClass.getMethod("setVariable",
1751               new Class[]
1752               { String.class, Object.class });
1753       java.lang.reflect.Method run = gcClass.getMethod("run", null);
1754       Object gc = gccons.newInstance(null);
1755       setvar.invoke(gc, new Object[]
1756       { "Jalview", this });
1757       run.invoke(gc, null);
1758     } catch (Exception ex)
1759     {
1760       jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
1761       JOptionPane
1762               .showInternalMessageDialog(
1763                       Desktop.desktop,
1764
1765                       "Couldn't create the groovy Shell. Check the error log for the details of what went wrong.",
1766                       "Jalview Groovy Support Failed",
1767                       JOptionPane.ERROR_MESSAGE);
1768     }
1769   }
1770
1771   /**
1772    * Progress bars managed by the IProgressIndicator method.
1773    */
1774   private Hashtable progressBars, progressBarHandlers;
1775
1776   /*
1777    * (non-Javadoc)
1778    * 
1779    * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
1780    */
1781   public void setProgressBar(String message, long id)
1782   {
1783     if (progressBars == null)
1784     {
1785       progressBars = new Hashtable();
1786       progressBarHandlers = new Hashtable();
1787     }
1788
1789     if (progressBars.get(new Long(id)) != null)
1790     {
1791       JProgressBar progressPanel = (JProgressBar) progressBars
1792               .remove(new Long(id));
1793       if (progressBarHandlers.contains(new Long(id)))
1794       {
1795         progressBarHandlers.remove(new Long(id));
1796       }
1797       removeProgressPanel(progressPanel);
1798     }
1799     else
1800     {
1801       progressBars.put(new Long(id), addProgressPanel(message));
1802     }
1803   }
1804
1805   /*
1806    * (non-Javadoc)
1807    * 
1808    * @see jalview.gui.IProgressIndicator#registerHandler(long,
1809    * jalview.gui.IProgressIndicatorHandler)
1810    */
1811   public void registerHandler(final long id,
1812           final IProgressIndicatorHandler handler)
1813   {
1814     if (progressBarHandlers == null || !progressBars.contains(new Long(id)))
1815     {
1816       throw new Error(
1817               "call setProgressBar before registering the progress bar's handler.");
1818     }
1819     progressBarHandlers.put(new Long(id), handler);
1820     final JPanel progressPanel = (JPanel) progressBars.get(new Long(id));
1821     if (handler.canCancel())
1822     {
1823       JButton cancel = new JButton("Cancel");
1824       final IProgressIndicator us = this;
1825       cancel.addActionListener(new ActionListener()
1826       {
1827
1828         public void actionPerformed(ActionEvent e)
1829         {
1830           handler.cancelActivity(id);
1831           us.setProgressBar("Cancelled "
1832                   + ((JLabel) progressPanel.getComponent(0)).getText(), id);
1833         }
1834       });
1835       progressPanel.add(cancel, BorderLayout.EAST);
1836     }
1837   }
1838
1839   /**
1840    * This will return the first AlignFrame viewing AlignViewport av. It will
1841    * break if there are more than one AlignFrames viewing a particular av. This
1842    * 
1843    * @param av
1844    * @return alignFrame for av
1845    */
1846   public static AlignFrame getAlignFrameFor(AlignViewport av)
1847   {
1848     if (desktop != null)
1849     {
1850       AlignmentPanel[] aps = getAlignmentPanels(av.getSequenceSetId());
1851       for (int panel = 0; aps != null && panel < aps.length; panel++)
1852       {
1853         if (aps[panel] != null && aps[panel].av == av)
1854         {
1855           return aps[panel].alignFrame;
1856         }
1857       }
1858     }
1859     return null;
1860   }
1861
1862   public VamsasApplication getVamsasApplication()
1863   {
1864     return v_client;
1865
1866   }
1867 }