progress bars (still need to be threaded properly) and URI drag'n'dropping
[jalview.git] / src / jalview / gui / Desktop.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)
3  * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.gui;
20
21 import jalview.io.*;
22
23 import java.awt.*;
24 import java.awt.datatransfer.*;
25 import java.awt.dnd.*;
26 import java.awt.event.*;
27 import java.io.BufferedInputStream;
28 import java.io.BufferedOutputStream;
29 import java.io.File;
30 import java.io.FileOutputStream;
31 import java.io.InputStream;
32 import java.lang.reflect.Constructor;
33 import java.net.URL;
34 import java.net.URLConnection;
35 import java.nio.channels.ReadableByteChannel;
36 import java.util.*;
37
38 import javax.swing.*;
39 import javax.swing.event.MenuEvent;
40 import javax.swing.event.MenuListener;
41
42 /**
43  * DOCUMENT ME!
44  * 
45  * @author $author$
46  * @version $Revision$
47  */
48 public class Desktop extends jalview.jbgui.GDesktop implements
49         DropTargetListener, ClipboardOwner, IProgressIndicator
50 {
51   /** DOCUMENT ME!! */
52   public static Desktop instance;
53
54   // Need to decide if the Memory Usage is to be included in
55   // Next release or not.
56   public static MyDesktopPane desktop;
57
58   // public static JDesktopPane desktop;
59
60   static int openFrameCount = 0;
61
62   static final int xOffset = 30;
63
64   static final int yOffset = 30;
65
66   public static jalview.ws.Discoverer discoverer;
67
68   public static Object[] jalviewClipboard;
69
70   public static boolean internalCopy = false;
71
72   static int fileLoadingCount = 0;
73
74   /**
75    * Creates a new Desktop object.
76    */
77   public Desktop()
78   {
79     /**
80      * A note to implementors. It is ESSENTIAL that any activities that might
81      * block are spawned off as threads rather than waited for during this
82      * constructor.
83      */
84     instance = this;
85     doVamsasClientCheck();
86     doGroovyCheck();
87
88     setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
89     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
90     boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
91             false);
92     desktop = new MyDesktopPane(selmemusage);
93     showMemusage.setSelected(selmemusage);
94     desktop.setBackground(Color.white);
95     getContentPane().setLayout(new BorderLayout());
96     getContentPane().add(desktop, BorderLayout.CENTER);
97     desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
98
99     // This line prevents Windows Look&Feel resizing all new windows to maximum
100     // if previous window was maximised
101     desktop.setDesktopManager(new DefaultDesktopManager());
102
103     Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
104     String x = jalview.bin.Cache.getProperty("SCREEN_X");
105     String y = jalview.bin.Cache.getProperty("SCREEN_Y");
106     String width = jalview.bin.Cache.getProperty("SCREEN_WIDTH");
107     String height = jalview.bin.Cache.getProperty("SCREEN_HEIGHT");
108
109     if ((x != null) && (y != null) && (width != null) && (height != null))
110     {
111       setBounds(Integer.parseInt(x), Integer.parseInt(y), Integer
112               .parseInt(width), Integer.parseInt(height));
113     }
114     else
115     {
116       setBounds((int) (screenSize.width - 900) / 2,
117               (int) (screenSize.height - 650) / 2, 900, 650);
118     }
119
120     this.addWindowListener(new WindowAdapter()
121     {
122       public void windowClosing(WindowEvent evt)
123       {
124         quit();
125       }
126     });
127
128     this.addMouseListener(new MouseAdapter()
129     {
130       public void mousePressed(MouseEvent evt)
131       {
132         if (SwingUtilities.isRightMouseButton(evt))
133         {
134           showPasteMenu(evt.getX(), evt.getY());
135         }
136       }
137     });
138
139     this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
140     // Spawn a thread that shows the splashscreen
141     new SplashScreen();
142
143     discoverer = new jalview.ws.Discoverer(); // Only gets started if gui is
144     // displayed.
145   }
146
147   private void doVamsasClientCheck()
148   {
149     if (jalview.bin.Cache.vamsasJarsPresent())
150     {
151       setupVamsasDisconnectedGui();
152       VamsasMenu.setVisible(true);
153       final Desktop us = this;
154       VamsasMenu.addMenuListener(new MenuListener()
155       {
156         // this listener remembers when the menu was first selected, and
157         // doesn't rebuild the session list until it has been cleared and
158         // reselected again.
159         boolean refresh = true;
160
161         public void menuCanceled(MenuEvent e)
162         {
163           refresh = true;
164         }
165
166         public void menuDeselected(MenuEvent e)
167         {
168           refresh = true;
169         }
170
171         public void menuSelected(MenuEvent e)
172         {
173           if (refresh)
174           {
175             us.buildVamsasStMenu();
176             refresh = false;
177           }
178         }
179       });
180       vamsasStart.setVisible(true);
181     }
182   }
183
184   void showPasteMenu(int x, int y)
185   {
186     JPopupMenu popup = new JPopupMenu();
187     JMenuItem item = new JMenuItem("Paste To New Window");
188     item.addActionListener(new ActionListener()
189     {
190       public void actionPerformed(ActionEvent evt)
191       {
192         paste();
193       }
194     });
195
196     popup.add(item);
197     popup.show(this, x, y);
198   }
199
200   public void paste()
201   {
202     try
203     {
204       Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
205       Transferable contents = c.getContents(this);
206
207       if (contents != null)
208       {
209         String file = (String) contents
210                 .getTransferData(DataFlavor.stringFlavor);
211
212         String format = new IdentifyFile().Identify(file,
213                 FormatAdapter.PASTE);
214
215         new FileLoader().LoadFile(file, FormatAdapter.PASTE, format);
216
217       }
218     } catch (Exception ex)
219     {
220       System.out
221               .println("Unable to paste alignment from system clipboard:\n"
222                       + ex);
223     }
224   }
225
226   /**
227    * DOCUMENT ME!
228    * 
229    * @param frame
230    *          DOCUMENT ME!
231    * @param title
232    *          DOCUMENT ME!
233    * @param w
234    *          DOCUMENT ME!
235    * @param h
236    *          DOCUMENT ME!
237    */
238   public static synchronized void addInternalFrame(
239           final JInternalFrame frame, String title, int w, int h)
240   {
241     addInternalFrame(frame, title, w, h, true);
242   }
243
244   /**
245    * DOCUMENT ME!
246    * 
247    * @param frame
248    *          DOCUMENT ME!
249    * @param title
250    *          DOCUMENT ME!
251    * @param w
252    *          DOCUMENT ME!
253    * @param h
254    *          DOCUMENT ME!
255    * @param resizable
256    *          DOCUMENT ME!
257    */
258   public static synchronized void addInternalFrame(
259           final JInternalFrame frame, String title, int w, int h,
260           boolean resizable)
261   {
262
263     // TODO: consider fixing method to update entries in the window submenu with
264     // the current window title
265
266     frame.setTitle(title);
267     if (frame.getWidth() < 1 || frame.getHeight() < 1)
268     {
269       frame.setSize(w, h);
270     }
271     // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
272     // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
273     // IF JALVIEW IS RUNNING HEADLESS
274     // ///////////////////////////////////////////////
275     if (System.getProperty("java.awt.headless") != null
276             && System.getProperty("java.awt.headless").equals("true"))
277     {
278       return;
279     }
280
281     openFrameCount++;
282
283     frame.setVisible(true);
284     frame.setClosable(true);
285     frame.setResizable(resizable);
286     frame.setMaximizable(resizable);
287     frame.setIconifiable(resizable);
288     frame.setFrameIcon(null);
289
290     if (frame.getX() < 1 && frame.getY() < 1)
291     {
292       frame.setLocation(xOffset * openFrameCount, yOffset
293               * ((openFrameCount - 1) % 10) + yOffset);
294     }
295
296     final JMenuItem menuItem = new JMenuItem(title);
297     frame
298             .addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
299             {
300               public void internalFrameActivated(
301                       javax.swing.event.InternalFrameEvent evt)
302               {
303                 JInternalFrame itf = desktop.getSelectedFrame();
304                 if (itf != null)
305                 {
306                   itf.requestFocus();
307                 }
308
309               }
310
311               public void internalFrameClosed(
312                       javax.swing.event.InternalFrameEvent evt)
313               {
314                 PaintRefresher.RemoveComponent(frame);
315                 openFrameCount--;
316                 windowMenu.remove(menuItem);
317                 JInternalFrame itf = desktop.getSelectedFrame();
318                 if (itf != null)
319                 {
320                   itf.requestFocus();
321                 }
322                 System.gc();
323               };
324             });
325
326     menuItem.addActionListener(new ActionListener()
327     {
328       public void actionPerformed(ActionEvent e)
329       {
330         try
331         {
332           frame.setSelected(true);
333           frame.setIcon(false);
334         } catch (java.beans.PropertyVetoException ex)
335         {
336
337         }
338       }
339     });
340
341     windowMenu.add(menuItem);
342
343     desktop.add(frame);
344     frame.toFront();
345     try
346     {
347       frame.setSelected(true);
348       frame.requestFocus();
349     } catch (java.beans.PropertyVetoException ve)
350     {
351     }
352   }
353
354   public void lostOwnership(Clipboard clipboard, Transferable contents)
355   {
356     if (!internalCopy)
357     {
358       Desktop.jalviewClipboard = null;
359     }
360
361     internalCopy = false;
362   }
363
364   public void dragEnter(DropTargetDragEvent evt)
365   {
366   }
367
368   public void dragExit(DropTargetEvent evt)
369   {
370   }
371
372   public void dragOver(DropTargetDragEvent evt)
373   {
374   }
375
376   public void dropActionChanged(DropTargetDragEvent evt)
377   {
378   }
379
380   /**
381    * DOCUMENT ME!
382    * 
383    * @param evt
384    *          DOCUMENT ME!
385    */
386   public void drop(DropTargetDropEvent evt)
387   {
388     Transferable t = evt.getTransferable();
389     java.util.List files = null;
390     java.util.List protocols = null;
391
392     try
393     {
394       DataFlavor uriListFlavor = new DataFlavor(
395               "text/uri-list;class=java.lang.String");
396       if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
397       {
398         // Works on Windows and MacOSX
399         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
400         files = (java.util.List) t
401                 .getTransferData(DataFlavor.javaFileListFlavor);
402       }
403       else if (t.isDataFlavorSupported(uriListFlavor))
404       {
405         // This is used by Unix drag system
406         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
407         String data = (String) t.getTransferData(uriListFlavor);
408         files = new java.util.ArrayList(1);
409         protocols = new java.util.ArrayList(1);
410         for (java.util.StringTokenizer st = new java.util.StringTokenizer(
411                 data, "\r\n"); st.hasMoreTokens();)
412         {
413           String s = st.nextToken();
414           if (s.startsWith("#"))
415           {
416             // the line is a comment (as per the RFC 2483)
417             continue;
418           }
419           java.net.URI uri = new java.net.URI(s);
420           if (uri.getScheme().toLowerCase().startsWith("http"))
421           {
422             protocols.add(FormatAdapter.URL);
423             files.add(uri.toString());
424           }
425           else
426           {
427             // otherwise preserve old behaviour: catch all for file objects
428             java.io.File file = new java.io.File(uri);
429             protocols.add(FormatAdapter.FILE);
430             files.add(file.toString());
431           }
432         }
433       }
434     } catch (Exception e)
435     {
436     }
437
438     if (files != null)
439     {
440       try
441       {
442         for (int i = 0; i < files.size(); i++)
443         {
444           String file = files.get(i).toString();
445           String protocol = (protocols==null) ? FormatAdapter.FILE : (String) protocols.get(i);
446           String format = null;
447
448           if (file.endsWith(".jar"))
449           {
450             format = "Jalview";
451
452           }
453           else
454           {
455             format = new IdentifyFile().Identify(file, protocol);
456           }
457
458           new FileLoader().LoadFile(file, protocol, format);
459
460         }
461       } catch (Exception ex)
462       {
463       }
464     }
465   }
466
467   /**
468    * DOCUMENT ME!
469    * 
470    * @param e
471    *          DOCUMENT ME!
472    */
473   public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
474   {
475     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
476             .getProperty("LAST_DIRECTORY"),
477             jalview.io.AppletFormatAdapter.READABLE_EXTENSIONS,
478             jalview.io.AppletFormatAdapter.READABLE_FNAMES,
479             jalview.bin.Cache.getProperty("DEFAULT_FILE_FORMAT"));
480
481     chooser.setFileView(new JalviewFileView());
482     chooser.setDialogTitle("Open local file");
483     chooser.setToolTipText("Open");
484
485     int value = chooser.showOpenDialog(this);
486
487     if (value == JalviewFileChooser.APPROVE_OPTION)
488     {
489       String choice = chooser.getSelectedFile().getPath();
490       jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
491               .getSelectedFile().getParent());
492
493       String format = null;
494       if (chooser.getSelectedFormat().equals("Jalview"))
495       {
496         format = "Jalview";
497       }
498       else
499       {
500         format = new IdentifyFile().Identify(choice, FormatAdapter.FILE);
501       }
502
503       if (viewport != null)
504       {
505         new FileLoader().LoadFile(viewport, choice, FormatAdapter.FILE,
506                 format);
507       }
508       else
509       {
510         new FileLoader().LoadFile(choice, FormatAdapter.FILE, format);
511       }
512     }
513   }
514
515   /**
516    * DOCUMENT ME!
517    * 
518    * @param e
519    *          DOCUMENT ME!
520    */
521   public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
522   {
523     // This construct allows us to have a wider textfield
524     // for viewing
525     JLabel label = new JLabel("Enter URL of Input File");
526     final JComboBox history = new JComboBox();
527
528     JPanel panel = new JPanel(new GridLayout(2, 1));
529     panel.add(label);
530     panel.add(history);
531     history.setPreferredSize(new Dimension(400, 20));
532     history.setEditable(true);
533     history.addItem("http://www.");
534
535     String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
536
537     StringTokenizer st;
538
539     if (historyItems != null)
540     {
541       st = new StringTokenizer(historyItems, "\t");
542
543       while (st.hasMoreTokens())
544       {
545         history.addItem(st.nextElement());
546       }
547     }
548
549     int reply = JOptionPane.showInternalConfirmDialog(desktop, panel,
550             "Input Alignment From URL", JOptionPane.OK_CANCEL_OPTION);
551
552     if (reply != JOptionPane.OK_OPTION)
553     {
554       return;
555     }
556
557     String url = history.getSelectedItem().toString();
558
559     if (url.toLowerCase().endsWith(".jar"))
560     {
561       if (viewport != null)
562       {
563         new FileLoader().LoadFile(viewport, url, FormatAdapter.URL,
564                 "Jalview");
565       }
566       else
567       {
568         new FileLoader().LoadFile(url, FormatAdapter.URL, "Jalview");
569       }
570     }
571     else
572     {
573       String format = new IdentifyFile().Identify(url, FormatAdapter.URL);
574
575       if (format.equals("URL NOT FOUND"))
576       {
577         JOptionPane.showInternalMessageDialog(Desktop.desktop,
578                 "Couldn't locate " + url, "URL not found",
579                 JOptionPane.WARNING_MESSAGE);
580
581         return;
582       }
583
584       if (viewport != null)
585       {
586         new FileLoader().LoadFile(viewport, url, FormatAdapter.URL, format);
587       }
588       else
589       {
590         new FileLoader().LoadFile(url, FormatAdapter.URL, format);
591       }
592     }
593   }
594
595   /**
596    * DOCUMENT ME!
597    * 
598    * @param e
599    *          DOCUMENT ME!
600    */
601   public void inputTextboxMenuItem_actionPerformed(AlignViewport viewport)
602   {
603     CutAndPasteTransfer cap = new CutAndPasteTransfer();
604     cap.setForInput(viewport);
605     Desktop.addInternalFrame(cap, "Cut & Paste Alignment File", 600, 500);
606   }
607
608   /*
609    * Exit the program
610    */
611   public void quit()
612   {
613     jalview.bin.Cache.setProperty("SCREEN_X", getBounds().x + "");
614     jalview.bin.Cache.setProperty("SCREEN_Y", getBounds().y + "");
615     jalview.bin.Cache.setProperty("SCREEN_WIDTH", getWidth() + "");
616     jalview.bin.Cache.setProperty("SCREEN_HEIGHT", getHeight() + "");
617     System.exit(0);
618   }
619
620   /**
621    * DOCUMENT ME!
622    * 
623    * @param e
624    *          DOCUMENT ME!
625    */
626   public void aboutMenuItem_actionPerformed(ActionEvent e)
627   {
628     StringBuffer message = new StringBuffer("Jalview version "
629             + jalview.bin.Cache.getProperty("VERSION") + "; last updated: "
630             + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
631
632     if (!jalview.bin.Cache.getProperty("LATEST_VERSION").equals(
633             jalview.bin.Cache.getProperty("VERSION")))
634     {
635       message
636               .append("\n\n!! Jalview version "
637                       + jalview.bin.Cache.getProperty("LATEST_VERSION")
638                       + " is available for download from http://www.jalview.org !!\n");
639
640     }
641     // TODO: update this text for each release or centrally store it for lite
642     // and application
643     message
644             .append("\nAuthors:  Andrew Waterhouse, Jim Procter, Michele Clamp, James Cuff, Steve Searle,\n    David Martin & Geoff Barton."
645                     + "\nDevelopment managed by The Barton Group, University of Dundee, Scotland, UK.\n"
646                     + "\nFor help, see the FAQ at www.jalview.org and/or join the jalview-discuss@jalview.org mailing list\n"
647                     + "\nIf  you use Jalview, please cite:"
648                     + "\nWaterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
649                     + "\nJalview Version 2 - a multiple sequence alignment editor and analysis workbench"
650                     + "\nBioinformatics doi: 10.1093/bioinformatics/btp033");
651     JOptionPane.showInternalMessageDialog(Desktop.desktop,
652
653     message.toString(), "About Jalview", JOptionPane.INFORMATION_MESSAGE);
654   }
655
656   /**
657    * DOCUMENT ME!
658    * 
659    * @param e
660    *          DOCUMENT ME!
661    */
662   public void documentationMenuItem_actionPerformed(ActionEvent e)
663   {
664     try
665     {
666       ClassLoader cl = jalview.gui.Desktop.class.getClassLoader();
667       java.net.URL url = javax.help.HelpSet.findHelpSet(cl, "help/help");
668       javax.help.HelpSet hs = new javax.help.HelpSet(cl, url);
669
670       javax.help.HelpBroker hb = hs.createHelpBroker();
671       hb.setCurrentID("home");
672       hb.setDisplayed(true);
673     } catch (Exception ex)
674     {
675     }
676   }
677
678   public void closeAll_actionPerformed(ActionEvent e)
679   {
680     JInternalFrame[] frames = desktop.getAllFrames();
681     for (int i = 0; i < frames.length; i++)
682     {
683       try
684       {
685         frames[i].setClosed(true);
686       } catch (java.beans.PropertyVetoException ex)
687       {
688       }
689     }
690     System.out.println("ALL CLOSED");
691     if (v_client != null)
692     {
693       // TODO clear binding to vamsas document objects on close_all
694
695     }
696   }
697
698   public void raiseRelated_actionPerformed(ActionEvent e)
699   {
700     reorderAssociatedWindows(false, false);
701   }
702
703   public void minimizeAssociated_actionPerformed(ActionEvent e)
704   {
705     reorderAssociatedWindows(true, false);
706   }
707
708   void closeAssociatedWindows()
709   {
710     reorderAssociatedWindows(false, true);
711   }
712
713   /*
714    * (non-Javadoc)
715    * 
716    * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
717    * ActionEvent)
718    */
719   protected void garbageCollect_actionPerformed(ActionEvent e)
720   {
721     // We simply collect the garbage
722     jalview.bin.Cache.log.debug("Collecting garbage...");
723     System.gc();
724     jalview.bin.Cache.log.debug("Finished garbage collection.");
725   }
726
727   /*
728    * (non-Javadoc)
729    * 
730    * @see
731    * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
732    * )
733    */
734   protected void showMemusage_actionPerformed(ActionEvent e)
735   {
736     desktop.showMemoryUsage(showMemusage.isSelected());
737   }
738
739   void reorderAssociatedWindows(boolean minimize, boolean close)
740   {
741     JInternalFrame[] frames = desktop.getAllFrames();
742     if (frames == null || frames.length < 1)
743     {
744       return;
745     }
746
747     AlignViewport source = null, target = null;
748     if (frames[0] instanceof AlignFrame)
749     {
750       source = ((AlignFrame) frames[0]).getCurrentView();
751     }
752     else if (frames[0] instanceof TreePanel)
753     {
754       source = ((TreePanel) frames[0]).getViewPort();
755     }
756     else if (frames[0] instanceof PCAPanel)
757     {
758       source = ((PCAPanel) frames[0]).av;
759     }
760     else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
761     {
762       source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
763     }
764
765     if (source != null)
766     {
767       for (int i = 0; i < frames.length; i++)
768       {
769         target = null;
770         if (frames[i] == null)
771         {
772           continue;
773         }
774         if (frames[i] instanceof AlignFrame)
775         {
776           target = ((AlignFrame) frames[i]).getCurrentView();
777         }
778         else if (frames[i] instanceof TreePanel)
779         {
780           target = ((TreePanel) frames[i]).getViewPort();
781         }
782         else if (frames[i] instanceof PCAPanel)
783         {
784           target = ((PCAPanel) frames[i]).av;
785         }
786         else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
787         {
788           target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
789         }
790
791         if (source == target)
792         {
793           try
794           {
795             if (close)
796             {
797               frames[i].setClosed(true);
798             }
799             else
800             {
801               frames[i].setIcon(minimize);
802               if (!minimize)
803               {
804                 frames[i].toFront();
805               }
806             }
807
808           } catch (java.beans.PropertyVetoException ex)
809           {
810           }
811         }
812       }
813     }
814   }
815
816   /**
817    * DOCUMENT ME!
818    * 
819    * @param e
820    *          DOCUMENT ME!
821    */
822   protected void preferences_actionPerformed(ActionEvent e)
823   {
824     new Preferences();
825   }
826
827   /**
828    * DOCUMENT ME!
829    * 
830    * @param e
831    *          DOCUMENT ME!
832    */
833   public void saveState_actionPerformed(ActionEvent e)
834   {
835     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
836             .getProperty("LAST_DIRECTORY"), new String[]
837     { "jar" }, new String[]
838     { "Jalview Project" }, "Jalview Project");
839
840     chooser.setFileView(new JalviewFileView());
841     chooser.setDialogTitle("Save State");
842
843     int value = chooser.showSaveDialog(this);
844
845     if (value == JalviewFileChooser.APPROVE_OPTION)
846     {
847       java.io.File choice = chooser.getSelectedFile();
848       JProgressBar progpanel = addProgressPanel("Saving jalview project "+choice.getName());
849       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice.getParent());
850       // TODO catch and handle errors for savestate
851       new Jalview2XML().SaveState(choice);
852       removeProgressPanel(progpanel);
853
854     }
855   }
856
857   /**
858    * DOCUMENT ME!
859    * 
860    * @param e
861    *          DOCUMENT ME!
862    */
863   public void loadState_actionPerformed(ActionEvent e)
864   {
865     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
866             .getProperty("LAST_DIRECTORY"), new String[]
867     { "jar" }, new String[]
868     { "Jalview Project" }, "Jalview Project");
869     chooser.setFileView(new JalviewFileView());
870     chooser.setDialogTitle("Restore state");
871
872     int value = chooser.showOpenDialog(this);
873
874     if (value == JalviewFileChooser.APPROVE_OPTION)
875     {
876       String choice = chooser.getSelectedFile().getAbsolutePath();
877       setProgressBar("loading jalview project "+chooser.getSelectedFile().getName(),choice.hashCode());
878       jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
879               .getSelectedFile().getParent());
880       new Jalview2XML().LoadJalviewAlign(choice);
881       setProgressBar(null,choice.hashCode());
882     }
883   }
884
885   public void inputSequence_actionPerformed(ActionEvent e)
886   {
887     new SequenceFetcher(this);
888   }
889
890   JPanel progressPanel;
891
892   public void startLoading(final String fileName)
893   {
894     if (fileLoadingCount == 0)
895     {
896       addProgressPanel("Loading File: " + fileName + "   ");
897
898     }
899     fileLoadingCount++;
900   }
901
902   private JProgressBar addProgressPanel(String string)
903   {
904     if (progressPanel == null)
905     {
906       progressPanel = new JPanel(new BorderLayout());
907       totalProgressCount = 0;
908     }
909     JProgressBar progressBar = new JProgressBar();
910     progressBar.setIndeterminate(true);
911
912     progressPanel.add(new JLabel(string), BorderLayout.WEST);
913
914     progressPanel.add(progressBar, BorderLayout.CENTER);
915
916     instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
917     totalProgressCount++;
918     validate();
919     return progressBar;
920   }
921
922   int totalProgressCount = 0;
923
924   private void removeProgressPanel(JProgressBar progbar)
925   {
926     if (progressPanel != null)
927     {
928       progressPanel.remove(progbar);
929       if (--totalProgressCount < 1)
930       {
931         this.getContentPane().remove(progressPanel);
932         progressPanel = null;
933       }
934     }
935     validate();
936   }
937
938   public void stopLoading()
939   {
940     fileLoadingCount--;
941     if (fileLoadingCount < 1)
942     {
943       if (progressPanel != null)
944       {
945         this.getContentPane().remove(progressPanel);
946         progressPanel = null;
947       }
948       fileLoadingCount = 0;
949     }
950     validate();
951   }
952
953   public static int getViewCount(String viewId)
954   {
955     AlignViewport[] aps = getViewports(viewId);
956     return (aps == null) ? 0 : aps.length;
957   }
958
959   /**
960    * 
961    * @param viewId
962    * @return all AlignmentPanels concerning the viewId sequence set
963    */
964   public static AlignmentPanel[] getAlignmentPanels(String viewId)
965   {
966     int count = 0;
967     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
968     ArrayList aps = new ArrayList();
969     for (int t = 0; t < frames.length; t++)
970     {
971       if (frames[t] instanceof AlignFrame)
972       {
973         AlignFrame af = (AlignFrame) frames[t];
974         for (int a = 0; a < af.alignPanels.size(); a++)
975         {
976           if (viewId
977                   .equals(((AlignmentPanel) af.alignPanels.elementAt(a)).av
978                           .getSequenceSetId()))
979           {
980             aps.add(af.alignPanels.elementAt(a));
981           }
982         }
983       }
984     }
985     if (aps.size() == 0)
986     {
987       return null;
988     }
989     AlignmentPanel[] vap = new AlignmentPanel[aps.size()];
990     for (int t = 0; t < vap.length; t++)
991     {
992       vap[t] = (AlignmentPanel) aps.get(t);
993     }
994     return vap;
995   }
996
997   /**
998    * get all the viewports on an alignment.
999    * 
1000    * @param sequenceSetId
1001    *          unique alignment id
1002    * @return all viewports on the alignment bound to sequenceSetId
1003    */
1004   public static AlignViewport[] getViewports(String sequenceSetId)
1005   {
1006     Vector viewp = new Vector();
1007     if (desktop != null)
1008     {
1009       javax.swing.JInternalFrame[] frames = instance.getAllFrames();
1010
1011       for (int t = 0; t < frames.length; t++)
1012       {
1013         if (frames[t] instanceof AlignFrame)
1014         {
1015           AlignFrame afr = ((AlignFrame) frames[t]);
1016           if (afr.getViewport().getSequenceSetId().equals(sequenceSetId))
1017           {
1018             if (afr.alignPanels != null)
1019             {
1020               for (int a = 0; a < afr.alignPanels.size(); a++)
1021               {
1022                 if (sequenceSetId.equals(((AlignmentPanel) afr.alignPanels
1023                         .elementAt(a)).av.getSequenceSetId()))
1024                 {
1025                   viewp.addElement(((AlignmentPanel) afr.alignPanels
1026                           .elementAt(a)).av);
1027                 }
1028               }
1029             }
1030             else
1031             {
1032               viewp.addElement(((AlignFrame) frames[t]).getViewport());
1033             }
1034           }
1035         }
1036       }
1037       if (viewp.size() > 0)
1038       {
1039         AlignViewport[] vp = new AlignViewport[viewp.size()];
1040         viewp.copyInto(vp);
1041         return vp;
1042       }
1043     }
1044     return null;
1045   }
1046
1047   public void explodeViews(AlignFrame af)
1048   {
1049     int size = af.alignPanels.size();
1050     if (size < 2)
1051     {
1052       return;
1053     }
1054
1055     for (int i = 0; i < size; i++)
1056     {
1057       AlignmentPanel ap = (AlignmentPanel) af.alignPanels.elementAt(i);
1058       AlignFrame newaf = new AlignFrame(ap);
1059       if (ap.av.explodedPosition != null
1060               && !ap.av.explodedPosition.equals(af.getBounds()))
1061       {
1062         newaf.setBounds(ap.av.explodedPosition);
1063       }
1064
1065       ap.av.gatherViewsHere = false;
1066
1067       addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1068               AlignFrame.DEFAULT_HEIGHT);
1069     }
1070
1071     af.alignPanels.clear();
1072     af.closeMenuItem_actionPerformed(true);
1073
1074   }
1075
1076   public void gatherViews(AlignFrame source)
1077   {
1078     source.viewport.gatherViewsHere = true;
1079     source.viewport.explodedPosition = source.getBounds();
1080     JInternalFrame[] frames = desktop.getAllFrames();
1081     String viewId = source.viewport.sequenceSetID;
1082
1083     for (int t = 0; t < frames.length; t++)
1084     {
1085       if (frames[t] instanceof AlignFrame && frames[t] != source)
1086       {
1087         AlignFrame af = (AlignFrame) frames[t];
1088         boolean gatherThis = false;
1089         for (int a = 0; a < af.alignPanels.size(); a++)
1090         {
1091           AlignmentPanel ap = (AlignmentPanel) af.alignPanels.elementAt(a);
1092           if (viewId.equals(ap.av.getSequenceSetId()))
1093           {
1094             gatherThis = true;
1095             ap.av.gatherViewsHere = false;
1096             ap.av.explodedPosition = af.getBounds();
1097             source.addAlignmentPanel(ap, false);
1098           }
1099         }
1100
1101         if (gatherThis)
1102         {
1103           af.alignPanels.clear();
1104           af.closeMenuItem_actionPerformed(true);
1105         }
1106       }
1107     }
1108
1109   }
1110
1111   jalview.gui.VamsasApplication v_client = null;
1112
1113   public void vamsasImport_actionPerformed(ActionEvent e)
1114   {
1115     if (v_client == null)
1116     {
1117       // Load and try to start a session.
1118       JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
1119               .getProperty("LAST_DIRECTORY"));
1120
1121       chooser.setFileView(new JalviewFileView());
1122       chooser.setDialogTitle("Open a saved VAMSAS session");
1123       chooser
1124               .setToolTipText("select a vamsas session to be opened as a new vamsas session.");
1125
1126       int value = chooser.showOpenDialog(this);
1127
1128       if (value == JalviewFileChooser.APPROVE_OPTION)
1129       {
1130         String fle = chooser.getSelectedFile().toString();
1131         if (!vamsasImport(chooser.getSelectedFile()))
1132         {
1133           JOptionPane.showInternalMessageDialog(Desktop.desktop,
1134                   "Couldn't import '" + fle + "' as a new vamsas session.",
1135                   "Vamsas Document Import Failed",
1136                   JOptionPane.ERROR_MESSAGE);
1137         }
1138       }
1139     }
1140     else
1141     {
1142       jalview.bin.Cache.log
1143               .error("Implementation error - load session from a running session is not supported.");
1144     }
1145   }
1146
1147   /**
1148    * import file into a new vamsas session (uses jalview.gui.VamsasApplication) 
1149    * @param file 
1150    * @return true if import was a success and a session was started.
1151    */
1152   public boolean vamsasImport(URL url)
1153   {
1154     // TODO: create progress bar
1155     if (v_client != null)
1156     {
1157       
1158       jalview.bin.Cache.log
1159       .error("Implementation error - load session from a running session is not supported.");
1160       return false;     
1161     }
1162     
1163     try
1164       {
1165       // copy the URL content to a temporary local file
1166       // TODO: be a bit cleverer here with nio (?!)
1167       File file = File.createTempFile("vdocfromurl", ".vdj");
1168       FileOutputStream fos = new FileOutputStream(file);
1169       BufferedInputStream bis = new BufferedInputStream(url.openStream());
1170       byte[] buffer = new byte[2048];
1171       int ln;
1172       while ((ln = bis.read(buffer))>-1)
1173       {
1174         fos.write(buffer,0,ln);
1175       }
1176       bis.close();
1177       fos.close();
1178       v_client = new jalview.gui.VamsasApplication(this, file, url.toExternalForm());
1179       } catch (Exception ex)
1180       {
1181         jalview.bin.Cache.log.error(
1182                 "Failed to create new vamsas session from contents of URL "+url,ex);
1183         return false;
1184       }
1185       setupVamsasConnectedGui();
1186       v_client.initial_update(); // TODO: thread ?
1187       return v_client.inSession();
1188     }
1189
1190   /**
1191    * import file into a new vamsas session (uses jalview.gui.VamsasApplication) 
1192    * @param file 
1193    * @return true if import was a success and a session was started.
1194    */
1195   public boolean vamsasImport(File file)
1196   {
1197     if (v_client != null)
1198     {
1199
1200       jalview.bin.Cache.log
1201               .error("Implementation error - load session from a running session is not supported.");
1202       return false;
1203     }
1204
1205     setProgressBar("Importing VAMSAS session from "+file.getName(),file.hashCode());
1206     try
1207     {
1208       v_client = new jalview.gui.VamsasApplication(this, file,null);
1209     } catch (Exception ex)
1210     {
1211       setProgressBar("Importing VAMSAS session from "+file.getName(),file.hashCode());
1212       jalview.bin.Cache.log.error(
1213               "New vamsas session from existing session file failed:", ex);
1214       return false;
1215     }
1216     setupVamsasConnectedGui();
1217     v_client.initial_update(); // TODO: thread ?
1218     setProgressBar("Importing VAMSAS session from "+file.getName(),file.hashCode());
1219     return v_client.inSession();
1220   }
1221   public boolean joinVamsasSession(String mysesid) {
1222     if (v_client!=null)
1223     {
1224       throw new Error("Trying to join a vamsas session when another is already connected.");
1225     }
1226     if (mysesid==null)
1227     {
1228       throw new Error("Invalid vamsas session id.");
1229     }
1230     v_client = new VamsasApplication(this, mysesid);
1231     setupVamsasConnectedGui();
1232     v_client.initial_update();
1233     return (v_client.inSession());
1234   }
1235
1236   public void vamsasStart_actionPerformed(ActionEvent e)
1237   {
1238     if (v_client == null)
1239     {
1240       // Start a session.
1241       // we just start a default session for moment.
1242       /*
1243        * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
1244        * getProperty("LAST_DIRECTORY"));
1245        * 
1246        * chooser.setFileView(new JalviewFileView());
1247        * chooser.setDialogTitle("Load Vamsas file");
1248        * chooser.setToolTipText("Import");
1249        * 
1250        * int value = chooser.showOpenDialog(this);
1251        * 
1252        * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
1253        * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
1254        */
1255       v_client = new VamsasApplication(this);
1256       setupVamsasConnectedGui();
1257       v_client.initial_update(); // TODO: thread ?
1258     }
1259     else
1260     {
1261       // store current data in session.
1262       v_client.push_update(); // TODO: thread
1263     }
1264   }
1265
1266   protected void setupVamsasConnectedGui()
1267   {
1268     vamsasStart.setText("Session Update");
1269     vamsasSave.setVisible(true);
1270     vamsasStop.setVisible(true);
1271     vamsasImport.setVisible(false); // Document import to existing session is
1272     // not possible for vamsas-client-1.0.
1273   }
1274
1275   protected void setupVamsasDisconnectedGui()
1276   {
1277     vamsasSave.setVisible(false);
1278     vamsasStop.setVisible(false);
1279     vamsasImport.setVisible(true);
1280     vamsasStart.setText("New Vamsas Session");
1281   }
1282
1283   public void vamsasStop_actionPerformed(ActionEvent e)
1284   {
1285     if (v_client != null)
1286     {
1287       v_client.end_session();
1288       v_client = null;
1289       setupVamsasDisconnectedGui();
1290     }
1291   }
1292
1293   protected void buildVamsasStMenu()
1294   {
1295     if (v_client == null)
1296     {
1297       String[] sess = null;
1298       try
1299       {
1300         sess = VamsasApplication.getSessionList();
1301       } catch (Exception e)
1302       {
1303         jalview.bin.Cache.log.warn(
1304                 "Problem getting current sessions list.", e);
1305         sess = null;
1306       }
1307       if (sess != null)
1308       {
1309         jalview.bin.Cache.log.debug("Got current sessions list: "
1310                 + sess.length + " entries.");
1311         VamsasStMenu.removeAll();
1312         for (int i = 0; i < sess.length; i++)
1313         {
1314           JMenuItem sessit = new JMenuItem();
1315           sessit.setText(sess[i]);
1316           sessit.setToolTipText("Connect to session " + sess[i]);
1317           final Desktop dsktp = this;
1318           final String mysesid = sess[i];
1319           sessit.addActionListener(new ActionListener()
1320           {
1321
1322             public void actionPerformed(ActionEvent e)
1323             {
1324               if (dsktp.v_client == null)
1325               {
1326                 Thread rthr = new Thread(new Runnable()
1327                 {
1328
1329                   public void run()
1330                   {
1331                     dsktp.v_client = new VamsasApplication(dsktp, mysesid);
1332                     dsktp.setupVamsasConnectedGui();
1333                     dsktp.v_client.initial_update();
1334                   }
1335
1336                 });
1337                 rthr.start();
1338               }
1339             };
1340           });
1341           VamsasStMenu.add(sessit);
1342         }
1343         // don't show an empty menu.
1344         VamsasStMenu.setVisible(sess.length > 0);
1345
1346       }
1347       else
1348       {
1349         jalview.bin.Cache.log.debug("No current vamsas sessions.");
1350         VamsasStMenu.removeAll();
1351         VamsasStMenu.setVisible(false);
1352       }
1353     }
1354     else
1355     {
1356       // Not interested in the content. Just hide ourselves.
1357       VamsasStMenu.setVisible(false);
1358     }
1359   }
1360
1361   public void vamsasSave_actionPerformed(ActionEvent e)
1362   {
1363     if (v_client != null)
1364     {
1365       JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
1366               .getProperty("LAST_DIRECTORY"), new String[]
1367       { "vdj" }, // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
1368               new String[]
1369               { "Vamsas Document" }, "Vamsas Document");
1370
1371       chooser.setFileView(new JalviewFileView());
1372       chooser.setDialogTitle("Save Vamsas Document Archive");
1373
1374       int value = chooser.showSaveDialog(this);
1375
1376       if (value == JalviewFileChooser.APPROVE_OPTION)
1377       {
1378         java.io.File choice = chooser.getSelectedFile();
1379         JProgressBar progpanel = addProgressPanel("Saving VAMSAS Document to "+choice.getName());
1380         jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice.getParent());
1381         String warnmsg = null;
1382         String warnttl = null;
1383         try
1384         {
1385           v_client.vclient.storeDocument(choice);
1386         } catch (Error ex)
1387         {
1388           warnttl = "Serious Problem saving Vamsas Document";
1389           warnmsg = ex.toString();
1390           jalview.bin.Cache.log.error("Error Whilst saving document to "
1391                   + choice, ex);
1392
1393         } catch (Exception ex)
1394         {
1395           warnttl = "Problem saving Vamsas Document.";
1396           warnmsg = ex.toString();
1397           jalview.bin.Cache.log.warn("Exception Whilst saving document to "
1398                   + choice, ex);
1399
1400         }
1401         removeProgressPanel(progpanel);
1402         if (warnmsg != null)
1403         {
1404           JOptionPane.showInternalMessageDialog(Desktop.desktop,
1405
1406           warnmsg, warnttl, JOptionPane.ERROR_MESSAGE);
1407         }
1408       }
1409     }
1410   }
1411
1412   JProgressBar vamUpdate = null;
1413
1414   /**
1415    * hide vamsas user gui bits when a vamsas document event is being handled.
1416    * 
1417    * @param b
1418    *          true to hide gui, false to reveal gui
1419    */
1420   public void setVamsasUpdate(boolean b)
1421   {
1422     jalview.bin.Cache.log.debug("Setting gui for Vamsas update "
1423             + (b ? "in progress" : "finished"));
1424
1425     if (vamUpdate != null)
1426     {
1427       this.removeProgressPanel(vamUpdate);
1428     }
1429     if (b)
1430     {
1431       vamUpdate = this.addProgressPanel("Updating vamsas session");
1432     }
1433     vamsasStart.setVisible(!b);
1434     vamsasStop.setVisible(!b);
1435     vamsasSave.setVisible(!b);
1436   }
1437
1438   public JInternalFrame[] getAllFrames()
1439   {
1440     return desktop.getAllFrames();
1441   }
1442
1443   /**
1444    * Checks the given url to see if it gives a response indicating that the user
1445    * should be informed of a new questionnaire.
1446    * 
1447    * @param url
1448    */
1449   public void checkForQuestionnaire(String url)
1450   {
1451     UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
1452     // javax.swing.SwingUtilities.invokeLater(jvq);
1453     new Thread(jvq).start();
1454   }
1455
1456   /**
1457    * Proxy class for JDesktopPane which optionally displays the current memory
1458    * usage and highlights the desktop area with a red bar if free memory runs
1459    * low.
1460    * 
1461    * @author AMW
1462    */
1463   public class MyDesktopPane extends JDesktopPane implements Runnable
1464   {
1465
1466     boolean showMemoryUsage = false;
1467
1468     Runtime runtime;
1469
1470     java.text.NumberFormat df;
1471
1472     float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
1473             percentUsage;
1474
1475     public MyDesktopPane(boolean showMemoryUsage)
1476     {
1477       showMemoryUsage(showMemoryUsage);
1478     }
1479
1480     public void showMemoryUsage(boolean showMemoryUsage)
1481     {
1482       this.showMemoryUsage = showMemoryUsage;
1483       if (showMemoryUsage)
1484       {
1485         Thread worker = new Thread(this);
1486         worker.start();
1487       }
1488     }
1489
1490     public boolean isShowMemoryUsage()
1491     {
1492       return showMemoryUsage;
1493     }
1494
1495     public void run()
1496     {
1497       df = java.text.NumberFormat.getNumberInstance();
1498       df.setMaximumFractionDigits(2);
1499       runtime = Runtime.getRuntime();
1500
1501       while (showMemoryUsage)
1502       {
1503         try
1504         {
1505           Thread.sleep(3000);
1506           maxMemory = runtime.maxMemory() / 1048576f;
1507           allocatedMemory = runtime.totalMemory() / 1048576f;
1508           freeMemory = runtime.freeMemory() / 1048576f;
1509           totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
1510
1511           percentUsage = (totalFreeMemory / maxMemory) * 100;
1512
1513           // if (percentUsage < 20)
1514           {
1515             // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
1516             // Color.red);
1517             // instance.set.setBorder(border1);
1518           }
1519           repaint();
1520
1521         } catch (Exception ex)
1522         {
1523           ex.printStackTrace();
1524         }
1525       }
1526     }
1527
1528     public void paintComponent(Graphics g)
1529     {
1530       if (showMemoryUsage)
1531       {
1532         if (percentUsage < 20)
1533           g.setColor(Color.red);
1534
1535         g.drawString("Total Free Memory: " + df.format(totalFreeMemory)
1536                 + "MB; Max Memory: " + df.format(maxMemory) + "MB; "
1537                 + df.format(percentUsage) + "%", 10, getHeight()
1538                 - g.getFontMetrics().getHeight());
1539       }
1540     }
1541
1542   }
1543
1544   protected JMenuItem groovyShell;
1545
1546   public void doGroovyCheck()
1547   {
1548     if (jalview.bin.Cache.groovyJarsPresent())
1549     {
1550       groovyShell = new JMenuItem();
1551       groovyShell.setText("Groovy Console...");
1552       groovyShell.addActionListener(new ActionListener()
1553       {
1554         public void actionPerformed(ActionEvent e)
1555         {
1556           groovyShell_actionPerformed(e);
1557         }
1558       });
1559       toolsMenu.add(groovyShell);
1560       groovyShell.setVisible(true);
1561     }
1562   }
1563
1564   /**
1565    * Accessor method to quickly get all the AlignmentFrames loaded.
1566    */
1567   public static AlignFrame[] getAlignframes()
1568   {
1569     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1570
1571     if (frames == null)
1572     {
1573       return null;
1574     }
1575     Vector avp = new Vector();
1576     try
1577     {
1578       // REVERSE ORDER
1579       for (int i = frames.length - 1; i > -1; i--)
1580       {
1581         if (frames[i] instanceof AlignFrame)
1582         {
1583           AlignFrame af = (AlignFrame) frames[i];
1584           avp.addElement(af);
1585         }
1586       }
1587     } catch (Exception ex)
1588     {
1589       ex.printStackTrace();
1590     }
1591     if (avp.size() == 0)
1592     {
1593       return null;
1594     }
1595     AlignFrame afs[] = new AlignFrame[avp.size()];
1596     for (int i = 0, j = avp.size(); i < j; i++)
1597     {
1598       afs[i] = (AlignFrame) avp.elementAt(i);
1599     }
1600     avp.clear();
1601     return afs;
1602   }
1603
1604   /**
1605    * Add Groovy Support to Jalview
1606    */
1607   public void groovyShell_actionPerformed(ActionEvent e)
1608   {
1609     // use reflection to avoid creating compilation dependency.
1610     if (!jalview.bin.Cache.groovyJarsPresent())
1611     {
1612       throw new Error(
1613               "Implementation Error. Cannot create groovyShell without Groovy on the classpath!");
1614     }
1615     try
1616     {
1617       Class gcClass = Desktop.class.getClassLoader().loadClass(
1618               "groovy.ui.Console");
1619       Constructor gccons = gcClass.getConstructor(null);
1620       java.lang.reflect.Method setvar = gcClass.getMethod("setVariable",
1621               new Class[]
1622               { String.class, Object.class });
1623       java.lang.reflect.Method run = gcClass.getMethod("run", null);
1624       Object gc = gccons.newInstance(null);
1625       setvar.invoke(gc, new Object[]
1626       { "Jalview", this });
1627       run.invoke(gc, null);
1628     } catch (Exception ex)
1629     {
1630       jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
1631       JOptionPane
1632               .showInternalMessageDialog(
1633                       Desktop.desktop,
1634
1635                       "Couldn't create the groovy Shell. Check the error log for the details of what went wrong.",
1636                       "Jalview Groovy Support Failed",
1637                       JOptionPane.ERROR_MESSAGE);
1638     }
1639   }
1640
1641   /**
1642    * Progress bars managed by the IProgressIndicator method.
1643    */
1644   private Hashtable progressBars, progressBarHandlers;
1645
1646   /*
1647    * (non-Javadoc)
1648    * 
1649    * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
1650    */
1651   public void setProgressBar(String message, long id)
1652   {
1653     if (progressBars == null)
1654     {
1655       progressBars = new Hashtable();
1656       progressBarHandlers = new Hashtable();
1657     }
1658
1659     if (progressBars.get(new Long(id)) != null)
1660     {
1661       JProgressBar progressPanel = (JProgressBar) progressBars
1662               .remove(new Long(id));
1663       if (progressBarHandlers.contains(new Long(id)))
1664       {
1665         progressBarHandlers.remove(new Long(id));
1666       }
1667       removeProgressPanel(progressPanel);
1668     }
1669     else
1670     {
1671       progressBars.put(new Long(id), addProgressPanel(message));
1672     }
1673   }
1674
1675   /*
1676    * (non-Javadoc)
1677    * 
1678    * @see jalview.gui.IProgressIndicator#registerHandler(long,
1679    * jalview.gui.IProgressIndicatorHandler)
1680    */
1681   public void registerHandler(final long id,
1682           final IProgressIndicatorHandler handler)
1683   {
1684     if (progressBarHandlers == null || !progressBars.contains(new Long(id)))
1685     {
1686       throw new Error(
1687               "call setProgressBar before registering the progress bar's handler.");
1688     }
1689     progressBarHandlers.put(new Long(id), handler);
1690     final JPanel progressPanel = (JPanel) progressBars.get(new Long(id));
1691     if (handler.canCancel())
1692     {
1693       JButton cancel = new JButton("Cancel");
1694       final IProgressIndicator us = this;
1695       cancel.addActionListener(new ActionListener()
1696       {
1697
1698         public void actionPerformed(ActionEvent e)
1699         {
1700           handler.cancelActivity(id);
1701           us.setProgressBar("Cancelled "
1702                   + ((JLabel) progressPanel.getComponent(0)).getText(), id);
1703         }
1704       });
1705       progressPanel.add(cancel, BorderLayout.EAST);
1706     }
1707   }
1708
1709   /**
1710    * This will return the first AlignFrame viewing AlignViewport av. It will
1711    * break if there are more than one AlignFrames viewing a particular av. This
1712    * 
1713    * @param av
1714    * @return alignFrame for av
1715    */
1716   public static AlignFrame getAlignFrameFor(AlignViewport av)
1717   {
1718     if (desktop != null)
1719     {
1720       AlignmentPanel[] aps = getAlignmentPanels(av.getSequenceSetId());
1721       for (int panel = 0; aps != null && panel < aps.length; panel++)
1722       {
1723         if (aps[panel] != null && aps[panel].av == av)
1724         {
1725           return aps[panel].alignFrame;
1726         }
1727       }
1728     }
1729     return null;
1730   }
1731
1732   public VamsasApplication getVamsasApplication()
1733   {
1734     return v_client;
1735
1736   }
1737 }