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