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