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