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