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