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