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