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