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