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