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