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