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