immediately show memory usage
[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     if (Desktop.desktop==null)
968     {
969       // no frames created and in headless mode
970       // TODO: verify that frames are recoverable when in headless mode
971       return null;
972     }
973     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
974     ArrayList aps = new ArrayList();
975     for (int t = 0; t < frames.length; t++)
976     {
977       if (frames[t] instanceof AlignFrame)
978       {
979         AlignFrame af = (AlignFrame) frames[t];
980         for (int a = 0; a < af.alignPanels.size(); a++)
981         {
982           if (viewId
983                   .equals(((AlignmentPanel) af.alignPanels.elementAt(a)).av
984                           .getSequenceSetId()))
985           {
986             aps.add(af.alignPanels.elementAt(a));
987           }
988         }
989       }
990     }
991     if (aps.size() == 0)
992     {
993       return null;
994     }
995     AlignmentPanel[] vap = new AlignmentPanel[aps.size()];
996     for (int t = 0; t < vap.length; t++)
997     {
998       vap[t] = (AlignmentPanel) aps.get(t);
999     }
1000     return vap;
1001   }
1002
1003   /**
1004    * get all the viewports on an alignment.
1005    * 
1006    * @param sequenceSetId
1007    *          unique alignment id
1008    * @return all viewports on the alignment bound to sequenceSetId
1009    */
1010   public static AlignViewport[] getViewports(String sequenceSetId)
1011   {
1012     Vector viewp = new Vector();
1013     if (desktop != null)
1014     {
1015       javax.swing.JInternalFrame[] frames = instance.getAllFrames();
1016
1017       for (int t = 0; t < frames.length; t++)
1018       {
1019         if (frames[t] instanceof AlignFrame)
1020         {
1021           AlignFrame afr = ((AlignFrame) frames[t]);
1022           if (afr.getViewport().getSequenceSetId().equals(sequenceSetId))
1023           {
1024             if (afr.alignPanels != null)
1025             {
1026               for (int a = 0; a < afr.alignPanels.size(); a++)
1027               {
1028                 if (sequenceSetId.equals(((AlignmentPanel) afr.alignPanels
1029                         .elementAt(a)).av.getSequenceSetId()))
1030                 {
1031                   viewp.addElement(((AlignmentPanel) afr.alignPanels
1032                           .elementAt(a)).av);
1033                 }
1034               }
1035             }
1036             else
1037             {
1038               viewp.addElement(((AlignFrame) frames[t]).getViewport());
1039             }
1040           }
1041         }
1042       }
1043       if (viewp.size() > 0)
1044       {
1045         AlignViewport[] vp = new AlignViewport[viewp.size()];
1046         viewp.copyInto(vp);
1047         return vp;
1048       }
1049     }
1050     return null;
1051   }
1052
1053   public void explodeViews(AlignFrame af)
1054   {
1055     int size = af.alignPanels.size();
1056     if (size < 2)
1057     {
1058       return;
1059     }
1060
1061     for (int i = 0; i < size; i++)
1062     {
1063       AlignmentPanel ap = (AlignmentPanel) af.alignPanels.elementAt(i);
1064       AlignFrame newaf = new AlignFrame(ap);
1065       if (ap.av.explodedPosition != null
1066               && !ap.av.explodedPosition.equals(af.getBounds()))
1067       {
1068         newaf.setBounds(ap.av.explodedPosition);
1069       }
1070
1071       ap.av.gatherViewsHere = false;
1072
1073       addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1074               AlignFrame.DEFAULT_HEIGHT);
1075     }
1076
1077     af.alignPanels.clear();
1078     af.closeMenuItem_actionPerformed(true);
1079
1080   }
1081
1082   public void gatherViews(AlignFrame source)
1083   {
1084     source.viewport.gatherViewsHere = true;
1085     source.viewport.explodedPosition = source.getBounds();
1086     JInternalFrame[] frames = desktop.getAllFrames();
1087     String viewId = source.viewport.sequenceSetID;
1088
1089     for (int t = 0; t < frames.length; t++)
1090     {
1091       if (frames[t] instanceof AlignFrame && frames[t] != source)
1092       {
1093         AlignFrame af = (AlignFrame) frames[t];
1094         boolean gatherThis = false;
1095         for (int a = 0; a < af.alignPanels.size(); a++)
1096         {
1097           AlignmentPanel ap = (AlignmentPanel) af.alignPanels.elementAt(a);
1098           if (viewId.equals(ap.av.getSequenceSetId()))
1099           {
1100             gatherThis = true;
1101             ap.av.gatherViewsHere = false;
1102             ap.av.explodedPosition = af.getBounds();
1103             source.addAlignmentPanel(ap, false);
1104           }
1105         }
1106
1107         if (gatherThis)
1108         {
1109           af.alignPanels.clear();
1110           af.closeMenuItem_actionPerformed(true);
1111         }
1112       }
1113     }
1114
1115   }
1116
1117   jalview.gui.VamsasApplication v_client = null;
1118
1119   public void vamsasImport_actionPerformed(ActionEvent e)
1120   {
1121     if (v_client == null)
1122     {
1123       // Load and try to start a session.
1124       JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
1125               .getProperty("LAST_DIRECTORY"));
1126
1127       chooser.setFileView(new JalviewFileView());
1128       chooser.setDialogTitle("Open a saved VAMSAS session");
1129       chooser
1130               .setToolTipText("select a vamsas session to be opened as a new vamsas session.");
1131
1132       int value = chooser.showOpenDialog(this);
1133
1134       if (value == JalviewFileChooser.APPROVE_OPTION)
1135       {
1136         String fle = chooser.getSelectedFile().toString();
1137         if (!vamsasImport(chooser.getSelectedFile()))
1138         {
1139           JOptionPane.showInternalMessageDialog(Desktop.desktop,
1140                   "Couldn't import '" + fle + "' as a new vamsas session.",
1141                   "Vamsas Document Import Failed",
1142                   JOptionPane.ERROR_MESSAGE);
1143         }
1144       }
1145     }
1146     else
1147     {
1148       jalview.bin.Cache.log
1149               .error("Implementation error - load session from a running session is not supported.");
1150     }
1151   }
1152
1153   /**
1154    * import file into a new vamsas session (uses jalview.gui.VamsasApplication) 
1155    * @param file 
1156    * @return true if import was a success and a session was started.
1157    */
1158   public boolean vamsasImport(URL url)
1159   {
1160     // TODO: create progress bar
1161     if (v_client != null)
1162     {
1163       
1164       jalview.bin.Cache.log
1165       .error("Implementation error - load session from a running session is not supported.");
1166       return false;     
1167     }
1168     
1169     try
1170       {
1171       // copy the URL content to a temporary local file
1172       // TODO: be a bit cleverer here with nio (?!)
1173       File file = File.createTempFile("vdocfromurl", ".vdj");
1174       FileOutputStream fos = new FileOutputStream(file);
1175       BufferedInputStream bis = new BufferedInputStream(url.openStream());
1176       byte[] buffer = new byte[2048];
1177       int ln;
1178       while ((ln = bis.read(buffer))>-1)
1179       {
1180         fos.write(buffer,0,ln);
1181       }
1182       bis.close();
1183       fos.close();
1184       v_client = new jalview.gui.VamsasApplication(this, file, url.toExternalForm());
1185       } catch (Exception ex)
1186       {
1187         jalview.bin.Cache.log.error(
1188                 "Failed to create new vamsas session from contents of URL "+url,ex);
1189         return false;
1190       }
1191       setupVamsasConnectedGui();
1192       v_client.initial_update(); // TODO: thread ?
1193       return v_client.inSession();
1194     }
1195
1196   /**
1197    * import file into a new vamsas session (uses jalview.gui.VamsasApplication) 
1198    * @param file 
1199    * @return true if import was a success and a session was started.
1200    */
1201   public boolean vamsasImport(File file)
1202   {
1203     if (v_client != null)
1204     {
1205
1206       jalview.bin.Cache.log
1207               .error("Implementation error - load session from a running session is not supported.");
1208       return false;
1209     }
1210
1211     setProgressBar("Importing VAMSAS session from "+file.getName(),file.hashCode());
1212     try
1213     {
1214       v_client = new jalview.gui.VamsasApplication(this, file,null);
1215     } catch (Exception ex)
1216     {
1217       setProgressBar("Importing VAMSAS session from "+file.getName(),file.hashCode());
1218       jalview.bin.Cache.log.error(
1219               "New vamsas session from existing session file failed:", ex);
1220       return false;
1221     }
1222     setupVamsasConnectedGui();
1223     v_client.initial_update(); // TODO: thread ?
1224     setProgressBar("Importing VAMSAS session from "+file.getName(),file.hashCode());
1225     return v_client.inSession();
1226   }
1227   public boolean joinVamsasSession(String mysesid) {
1228     if (v_client!=null)
1229     {
1230       throw new Error("Trying to join a vamsas session when another is already connected.");
1231     }
1232     if (mysesid==null)
1233     {
1234       throw new Error("Invalid vamsas session id.");
1235     }
1236     v_client = new VamsasApplication(this, mysesid);
1237     setupVamsasConnectedGui();
1238     v_client.initial_update();
1239     return (v_client.inSession());
1240   }
1241
1242   public void vamsasStart_actionPerformed(ActionEvent e)
1243   {
1244     if (v_client == null)
1245     {
1246       // Start a session.
1247       // we just start a default session for moment.
1248       /*
1249        * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
1250        * getProperty("LAST_DIRECTORY"));
1251        * 
1252        * chooser.setFileView(new JalviewFileView());
1253        * chooser.setDialogTitle("Load Vamsas file");
1254        * chooser.setToolTipText("Import");
1255        * 
1256        * int value = chooser.showOpenDialog(this);
1257        * 
1258        * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
1259        * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
1260        */
1261       v_client = new VamsasApplication(this);
1262       setupVamsasConnectedGui();
1263       v_client.initial_update(); // TODO: thread ?
1264     }
1265     else
1266     {
1267       // store current data in session.
1268       v_client.push_update(); // TODO: thread
1269     }
1270   }
1271
1272   protected void setupVamsasConnectedGui()
1273   {
1274     vamsasStart.setText("Session Update");
1275     vamsasSave.setVisible(true);
1276     vamsasStop.setVisible(true);
1277     vamsasImport.setVisible(false); // Document import to existing session is
1278     // not possible for vamsas-client-1.0.
1279   }
1280
1281   protected void setupVamsasDisconnectedGui()
1282   {
1283     vamsasSave.setVisible(false);
1284     vamsasStop.setVisible(false);
1285     vamsasImport.setVisible(true);
1286     vamsasStart.setText("New Vamsas Session");
1287   }
1288
1289   public void vamsasStop_actionPerformed(ActionEvent e)
1290   {
1291     if (v_client != null)
1292     {
1293       v_client.end_session();
1294       v_client = null;
1295       setupVamsasDisconnectedGui();
1296     }
1297   }
1298
1299   protected void buildVamsasStMenu()
1300   {
1301     if (v_client == null)
1302     {
1303       String[] sess = null;
1304       try
1305       {
1306         sess = VamsasApplication.getSessionList();
1307       } catch (Exception e)
1308       {
1309         jalview.bin.Cache.log.warn(
1310                 "Problem getting current sessions list.", e);
1311         sess = null;
1312       }
1313       if (sess != null)
1314       {
1315         jalview.bin.Cache.log.debug("Got current sessions list: "
1316                 + sess.length + " entries.");
1317         VamsasStMenu.removeAll();
1318         for (int i = 0; i < sess.length; i++)
1319         {
1320           JMenuItem sessit = new JMenuItem();
1321           sessit.setText(sess[i]);
1322           sessit.setToolTipText("Connect to session " + sess[i]);
1323           final Desktop dsktp = this;
1324           final String mysesid = sess[i];
1325           sessit.addActionListener(new ActionListener()
1326           {
1327
1328             public void actionPerformed(ActionEvent e)
1329             {
1330               if (dsktp.v_client == null)
1331               {
1332                 Thread rthr = new Thread(new Runnable()
1333                 {
1334
1335                   public void run()
1336                   {
1337                     dsktp.v_client = new VamsasApplication(dsktp, mysesid);
1338                     dsktp.setupVamsasConnectedGui();
1339                     dsktp.v_client.initial_update();
1340                   }
1341
1342                 });
1343                 rthr.start();
1344               }
1345             };
1346           });
1347           VamsasStMenu.add(sessit);
1348         }
1349         // don't show an empty menu.
1350         VamsasStMenu.setVisible(sess.length > 0);
1351
1352       }
1353       else
1354       {
1355         jalview.bin.Cache.log.debug("No current vamsas sessions.");
1356         VamsasStMenu.removeAll();
1357         VamsasStMenu.setVisible(false);
1358       }
1359     }
1360     else
1361     {
1362       // Not interested in the content. Just hide ourselves.
1363       VamsasStMenu.setVisible(false);
1364     }
1365   }
1366
1367   public void vamsasSave_actionPerformed(ActionEvent e)
1368   {
1369     if (v_client != null)
1370     {
1371       JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
1372               .getProperty("LAST_DIRECTORY"), new String[]
1373       { "vdj" }, // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
1374               new String[]
1375               { "Vamsas Document" }, "Vamsas Document");
1376
1377       chooser.setFileView(new JalviewFileView());
1378       chooser.setDialogTitle("Save Vamsas Document Archive");
1379
1380       int value = chooser.showSaveDialog(this);
1381
1382       if (value == JalviewFileChooser.APPROVE_OPTION)
1383       {
1384         java.io.File choice = chooser.getSelectedFile();
1385         JProgressBar progpanel = addProgressPanel("Saving VAMSAS Document to "+choice.getName());
1386         jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice.getParent());
1387         String warnmsg = null;
1388         String warnttl = null;
1389         try
1390         {
1391           v_client.vclient.storeDocument(choice);
1392         } catch (Error ex)
1393         {
1394           warnttl = "Serious Problem saving Vamsas Document";
1395           warnmsg = ex.toString();
1396           jalview.bin.Cache.log.error("Error Whilst saving document to "
1397                   + choice, ex);
1398
1399         } catch (Exception ex)
1400         {
1401           warnttl = "Problem saving Vamsas Document.";
1402           warnmsg = ex.toString();
1403           jalview.bin.Cache.log.warn("Exception Whilst saving document to "
1404                   + choice, ex);
1405
1406         }
1407         removeProgressPanel(progpanel);
1408         if (warnmsg != null)
1409         {
1410           JOptionPane.showInternalMessageDialog(Desktop.desktop,
1411
1412           warnmsg, warnttl, JOptionPane.ERROR_MESSAGE);
1413         }
1414       }
1415     }
1416   }
1417
1418   JProgressBar vamUpdate = null;
1419
1420   /**
1421    * hide vamsas user gui bits when a vamsas document event is being handled.
1422    * 
1423    * @param b
1424    *          true to hide gui, false to reveal gui
1425    */
1426   public void setVamsasUpdate(boolean b)
1427   {
1428     jalview.bin.Cache.log.debug("Setting gui for Vamsas update "
1429             + (b ? "in progress" : "finished"));
1430
1431     if (vamUpdate != null)
1432     {
1433       this.removeProgressPanel(vamUpdate);
1434     }
1435     if (b)
1436     {
1437       vamUpdate = this.addProgressPanel("Updating vamsas session");
1438     }
1439     vamsasStart.setVisible(!b);
1440     vamsasStop.setVisible(!b);
1441     vamsasSave.setVisible(!b);
1442   }
1443
1444   public JInternalFrame[] getAllFrames()
1445   {
1446     return desktop.getAllFrames();
1447   }
1448
1449   /**
1450    * Checks the given url to see if it gives a response indicating that the user
1451    * should be informed of a new questionnaire.
1452    * 
1453    * @param url
1454    */
1455   public void checkForQuestionnaire(String url)
1456   {
1457     UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
1458     // javax.swing.SwingUtilities.invokeLater(jvq);
1459     new Thread(jvq).start();
1460   }
1461
1462   /**
1463    * Proxy class for JDesktopPane which optionally displays the current memory
1464    * usage and highlights the desktop area with a red bar if free memory runs
1465    * low.
1466    * 
1467    * @author AMW
1468    */
1469   public class MyDesktopPane extends JDesktopPane implements Runnable
1470   {
1471
1472     boolean showMemoryUsage = false;
1473
1474     Runtime runtime;
1475
1476     java.text.NumberFormat df;
1477
1478     float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
1479             percentUsage;
1480
1481     public MyDesktopPane(boolean showMemoryUsage)
1482     {
1483       showMemoryUsage(showMemoryUsage);
1484     }
1485
1486     public void showMemoryUsage(boolean showMemoryUsage)
1487     {
1488       this.showMemoryUsage = showMemoryUsage;
1489       if (showMemoryUsage)
1490       {
1491         Thread worker = new Thread(this);
1492         worker.start();
1493       }
1494     }
1495
1496     public boolean isShowMemoryUsage()
1497     {
1498       return showMemoryUsage;
1499     }
1500
1501     public void run()
1502     {
1503       df = java.text.NumberFormat.getNumberInstance();
1504       df.setMaximumFractionDigits(2);
1505       runtime = Runtime.getRuntime();
1506
1507       while (showMemoryUsage)
1508       {
1509         try
1510         {
1511           maxMemory = runtime.maxMemory() / 1048576f;
1512           allocatedMemory = runtime.totalMemory() / 1048576f;
1513           freeMemory = runtime.freeMemory() / 1048576f;
1514           totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
1515
1516           percentUsage = (totalFreeMemory / maxMemory) * 100;
1517
1518           // if (percentUsage < 20)
1519           {
1520             // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
1521             // Color.red);
1522             // instance.set.setBorder(border1);
1523           }
1524           repaint();
1525           // sleep after showing usage
1526           Thread.sleep(3000);
1527         } catch (Exception ex)
1528         {
1529           ex.printStackTrace();
1530         }
1531       }
1532     }
1533
1534     public void paintComponent(Graphics g)
1535     {
1536       if (showMemoryUsage && g!=null)
1537       {
1538         if (percentUsage < 20)
1539           g.setColor(Color.red);
1540
1541         g.drawString("Total Free Memory: " + df.format(totalFreeMemory)
1542                 + "MB; Max Memory: " + df.format(maxMemory) + "MB; "
1543                 + df.format(percentUsage) + "%", 10, getHeight()
1544                 - g.getFontMetrics().getHeight());
1545       }
1546     }
1547
1548   }
1549
1550   protected JMenuItem groovyShell;
1551
1552   public void doGroovyCheck()
1553   {
1554     if (jalview.bin.Cache.groovyJarsPresent())
1555     {
1556       groovyShell = new JMenuItem();
1557       groovyShell.setText("Groovy Console...");
1558       groovyShell.addActionListener(new ActionListener()
1559       {
1560         public void actionPerformed(ActionEvent e)
1561         {
1562           groovyShell_actionPerformed(e);
1563         }
1564       });
1565       toolsMenu.add(groovyShell);
1566       groovyShell.setVisible(true);
1567     }
1568   }
1569
1570   /**
1571    * Accessor method to quickly get all the AlignmentFrames loaded.
1572    */
1573   public static AlignFrame[] getAlignframes()
1574   {
1575     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1576
1577     if (frames == null)
1578     {
1579       return null;
1580     }
1581     Vector avp = new Vector();
1582     try
1583     {
1584       // REVERSE ORDER
1585       for (int i = frames.length - 1; i > -1; i--)
1586       {
1587         if (frames[i] instanceof AlignFrame)
1588         {
1589           AlignFrame af = (AlignFrame) frames[i];
1590           avp.addElement(af);
1591         }
1592       }
1593     } catch (Exception ex)
1594     {
1595       ex.printStackTrace();
1596     }
1597     if (avp.size() == 0)
1598     {
1599       return null;
1600     }
1601     AlignFrame afs[] = new AlignFrame[avp.size()];
1602     for (int i = 0, j = avp.size(); i < j; i++)
1603     {
1604       afs[i] = (AlignFrame) avp.elementAt(i);
1605     }
1606     avp.clear();
1607     return afs;
1608   }
1609
1610   /**
1611    * Add Groovy Support to Jalview
1612    */
1613   public void groovyShell_actionPerformed(ActionEvent e)
1614   {
1615     // use reflection to avoid creating compilation dependency.
1616     if (!jalview.bin.Cache.groovyJarsPresent())
1617     {
1618       throw new Error(
1619               "Implementation Error. Cannot create groovyShell without Groovy on the classpath!");
1620     }
1621     try
1622     {
1623       Class gcClass = Desktop.class.getClassLoader().loadClass(
1624               "groovy.ui.Console");
1625       Constructor gccons = gcClass.getConstructor(null);
1626       java.lang.reflect.Method setvar = gcClass.getMethod("setVariable",
1627               new Class[]
1628               { String.class, Object.class });
1629       java.lang.reflect.Method run = gcClass.getMethod("run", null);
1630       Object gc = gccons.newInstance(null);
1631       setvar.invoke(gc, new Object[]
1632       { "Jalview", this });
1633       run.invoke(gc, null);
1634     } catch (Exception ex)
1635     {
1636       jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
1637       JOptionPane
1638               .showInternalMessageDialog(
1639                       Desktop.desktop,
1640
1641                       "Couldn't create the groovy Shell. Check the error log for the details of what went wrong.",
1642                       "Jalview Groovy Support Failed",
1643                       JOptionPane.ERROR_MESSAGE);
1644     }
1645   }
1646
1647   /**
1648    * Progress bars managed by the IProgressIndicator method.
1649    */
1650   private Hashtable progressBars, progressBarHandlers;
1651
1652   /*
1653    * (non-Javadoc)
1654    * 
1655    * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
1656    */
1657   public void setProgressBar(String message, long id)
1658   {
1659     if (progressBars == null)
1660     {
1661       progressBars = new Hashtable();
1662       progressBarHandlers = new Hashtable();
1663     }
1664
1665     if (progressBars.get(new Long(id)) != null)
1666     {
1667       JProgressBar progressPanel = (JProgressBar) progressBars
1668               .remove(new Long(id));
1669       if (progressBarHandlers.contains(new Long(id)))
1670       {
1671         progressBarHandlers.remove(new Long(id));
1672       }
1673       removeProgressPanel(progressPanel);
1674     }
1675     else
1676     {
1677       progressBars.put(new Long(id), addProgressPanel(message));
1678     }
1679   }
1680
1681   /*
1682    * (non-Javadoc)
1683    * 
1684    * @see jalview.gui.IProgressIndicator#registerHandler(long,
1685    * jalview.gui.IProgressIndicatorHandler)
1686    */
1687   public void registerHandler(final long id,
1688           final IProgressIndicatorHandler handler)
1689   {
1690     if (progressBarHandlers == null || !progressBars.contains(new Long(id)))
1691     {
1692       throw new Error(
1693               "call setProgressBar before registering the progress bar's handler.");
1694     }
1695     progressBarHandlers.put(new Long(id), handler);
1696     final JPanel progressPanel = (JPanel) progressBars.get(new Long(id));
1697     if (handler.canCancel())
1698     {
1699       JButton cancel = new JButton("Cancel");
1700       final IProgressIndicator us = this;
1701       cancel.addActionListener(new ActionListener()
1702       {
1703
1704         public void actionPerformed(ActionEvent e)
1705         {
1706           handler.cancelActivity(id);
1707           us.setProgressBar("Cancelled "
1708                   + ((JLabel) progressPanel.getComponent(0)).getText(), id);
1709         }
1710       });
1711       progressPanel.add(cancel, BorderLayout.EAST);
1712     }
1713   }
1714
1715   /**
1716    * This will return the first AlignFrame viewing AlignViewport av. It will
1717    * break if there are more than one AlignFrames viewing a particular av. This
1718    * 
1719    * @param av
1720    * @return alignFrame for av
1721    */
1722   public static AlignFrame getAlignFrameFor(AlignViewport av)
1723   {
1724     if (desktop != null)
1725     {
1726       AlignmentPanel[] aps = getAlignmentPanels(av.getSequenceSetId());
1727       for (int panel = 0; aps != null && panel < aps.length; panel++)
1728       {
1729         if (aps[panel] != null && aps[panel].av == av)
1730         {
1731           return aps[panel].alignFrame;
1732         }
1733       }
1734     }
1735     return null;
1736   }
1737
1738   public VamsasApplication getVamsasApplication()
1739   {
1740     return v_client;
1741
1742   }
1743 }