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