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