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