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