6912e195e045783fa07901bee6fee3b432a184b5
[jalview.git] / src / jalview / gui / Desktop.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
3  * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  * 
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.gui;
19
20 import jalview.bin.Cache;
21 import jalview.io.*;
22 import jalview.ws.params.ParamManager;
23
24 import java.awt.*;
25 import java.awt.datatransfer.*;
26 import java.awt.dnd.*;
27 import java.awt.event.*;
28 import java.beans.PropertyChangeEvent;
29 import java.beans.PropertyChangeListener;
30 import java.io.BufferedInputStream;
31 import java.io.BufferedOutputStream;
32 import java.io.File;
33 import java.io.FileOutputStream;
34 import java.io.InputStream;
35 import java.lang.reflect.Constructor;
36 import java.net.URL;
37 import java.net.URLConnection;
38 import java.nio.channels.ReadableByteChannel;
39 import java.util.*;
40
41 import javax.swing.*;
42 import javax.swing.event.MenuEvent;
43 import javax.swing.event.MenuListener;
44
45 /**
46  * Jalview Desktop
47  * 
48  * 
49  * @author $author$
50  * @version $Revision$
51  */
52 public class Desktop extends jalview.jbgui.GDesktop implements
53         DropTargetListener, ClipboardOwner, IProgressIndicator
54 {
55
56   private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
57
58   /**
59    * @param listener
60    * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
61    */
62   public void addJalviewPropertyChangeListener(
63           PropertyChangeListener listener)
64   {
65     changeSupport.addJalviewPropertyChangeListener(listener);
66   }
67
68   /**
69    * @param propertyName
70    * @param listener
71    * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
72    *      java.beans.PropertyChangeListener)
73    */
74   public void addJalviewPropertyChangeListener(String propertyName,
75           PropertyChangeListener listener)
76   {
77     changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
78   }
79
80   /**
81    * @param propertyName
82    * @param listener
83    * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
84    *      java.beans.PropertyChangeListener)
85    */
86   public void removeJalviewPropertyChangeListener(String propertyName,
87           PropertyChangeListener listener)
88   {
89     changeSupport.removeJalviewPropertyChangeListener(propertyName,
90             listener);
91   }
92
93   /** Singleton Desktop instance */
94   public static Desktop instance;
95
96   public static MyDesktopPane desktop;
97
98   static int openFrameCount = 0;
99
100   static final int xOffset = 30;
101
102   static final int yOffset = 30;
103
104   public static jalview.ws.jws1.Discoverer discoverer;
105
106   public static Object[] jalviewClipboard;
107
108   public static boolean internalCopy = false;
109
110   static int fileLoadingCount = 0;
111
112   class MyDesktopManager implements DesktopManager
113   {
114
115     private DesktopManager delegate;
116
117     public MyDesktopManager(DesktopManager delegate)
118     {
119       this.delegate = delegate;
120     }
121
122     public void activateFrame(JInternalFrame f)
123     {
124       try
125       {
126         delegate.activateFrame(f);
127       } catch (NullPointerException npe)
128       {
129         Point p = getMousePosition();
130         instance.showPasteMenu(p.x, p.y);
131       }
132     }
133
134     public void beginDraggingFrame(JComponent f)
135     {
136       delegate.beginDraggingFrame(f);
137     }
138
139     public void beginResizingFrame(JComponent f, int direction)
140     {
141       delegate.beginResizingFrame(f, direction);
142     }
143
144     public void closeFrame(JInternalFrame f)
145     {
146       delegate.closeFrame(f);
147     }
148
149     public void deactivateFrame(JInternalFrame f)
150     {
151       delegate.deactivateFrame(f);
152     }
153
154     public void deiconifyFrame(JInternalFrame f)
155     {
156       delegate.deiconifyFrame(f);
157     }
158
159     public void dragFrame(JComponent f, int newX, int newY)
160     {
161       delegate.dragFrame(f, newX, newY);
162     }
163
164     public void endDraggingFrame(JComponent f)
165     {
166       delegate.endDraggingFrame(f);
167     }
168
169     public void endResizingFrame(JComponent f)
170     {
171       delegate.endResizingFrame(f);
172     }
173
174     public void iconifyFrame(JInternalFrame f)
175     {
176       delegate.iconifyFrame(f);
177     }
178
179     public void maximizeFrame(JInternalFrame f)
180     {
181       delegate.maximizeFrame(f);
182     }
183
184     public void minimizeFrame(JInternalFrame f)
185     {
186       delegate.minimizeFrame(f);
187     }
188
189     public void openFrame(JInternalFrame f)
190     {
191       delegate.openFrame(f);
192     }
193
194     public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
195             int newHeight)
196     {
197       delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
198     }
199
200     public void setBoundsForFrame(JComponent f, int newX, int newY,
201             int newWidth, int newHeight)
202     {
203       delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
204     }
205
206     // All other methods, simply delegate
207
208   }
209
210   /**
211    * Creates a new Desktop object.
212    */
213   public Desktop()
214   {
215     /**
216      * A note to implementors. It is ESSENTIAL that any activities that might
217      * block are spawned off as threads rather than waited for during this
218      * constructor.
219      */
220     instance = this;
221     doVamsasClientCheck();
222     doGroovyCheck();
223
224     setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
225     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
226     boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
227             false);
228     boolean showjconsole = jalview.bin.Cache.getDefault(
229             "SHOW_JAVA_CONSOLE", false);
230     desktop = new MyDesktopPane(selmemusage);
231     showMemusage.setSelected(selmemusage);
232     desktop.setBackground(Color.white);
233     getContentPane().setLayout(new BorderLayout());
234     getContentPane().add(desktop, BorderLayout.CENTER);
235     desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
236
237     // This line prevents Windows Look&Feel resizing all new windows to maximum
238     // if previous window was maximised
239     desktop.setDesktopManager(new MyDesktopManager(
240             new DefaultDesktopManager()));
241     Rectangle dims = getLastKnownDimensions("");
242     if (dims != null)
243     {
244       setBounds(dims);
245     }
246     else
247     {
248       Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
249       setBounds((int) (screenSize.width - 900) / 2,
250               (int) (screenSize.height - 650) / 2, 900, 650);
251     }
252     jconsole = new Console(this, showjconsole);
253     // add essential build information
254     jconsole.setHeader("Jalview Desktop "
255             + jalview.bin.Cache.getProperty("VERSION") + "\n"
256             + "Build Date: "
257             + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
258             + "Java version: " + System.getProperty("java.version") + "\n"
259             + System.getProperty("os.arch") + " "
260             + System.getProperty("os.name") + " "
261             + System.getProperty("os.version"));
262
263     showConsole(showjconsole);
264
265     this.addWindowListener(new WindowAdapter()
266     {
267       public void windowClosing(WindowEvent evt)
268       {
269         quit();
270       }
271     });
272
273     this.addMouseListener(new MouseAdapter()
274     {
275       public void mousePressed(MouseEvent evt)
276       {
277         if (SwingUtilities.isRightMouseButton(evt))
278         {
279           showPasteMenu(evt.getX(), evt.getY());
280         }
281       }
282     });
283
284     this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
285     // Spawn a thread that shows the splashscreen
286     SwingUtilities.invokeLater(new Runnable()
287     {
288       public void run()
289       {
290         new SplashScreen();
291       }
292     });
293
294     // displayed.
295     // Thread off a new instance of the file chooser - this reduces the time it
296     // takes to open it later on.
297     new Thread(new Runnable()
298     {
299       public void run()
300       {
301         Cache.log.debug("Filechooser init thread started.");
302         JalviewFileChooser chooser = new JalviewFileChooser(
303                 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
304                 jalview.io.AppletFormatAdapter.READABLE_EXTENSIONS,
305                 jalview.io.AppletFormatAdapter.READABLE_FNAMES,
306                 jalview.bin.Cache.getProperty("DEFAULT_FILE_FORMAT"));
307         Cache.log.debug("Filechooser init thread finished.");
308       }
309     }).start();
310     // Add the service change listener
311     changeSupport.addJalviewPropertyChangeListener("services",
312             new PropertyChangeListener()
313             {
314
315               @Override
316               public void propertyChange(PropertyChangeEvent evt)
317               {
318                 Cache.log.debug("Firing service changed event for "
319                         + evt.getNewValue());
320                 JalviewServicesChanged(evt);
321               }
322
323             });
324   }
325
326   /**
327    * recover the last known dimensions for a jalview window
328    * 
329    * @param windowName
330    *          - empty string is desktop, all other windows have unique prefix
331    * @return null or last known dimensions scaled to current geometry (if last
332    *         window geom was known)
333    */
334   Rectangle getLastKnownDimensions(String windowName)
335   {
336     // TODO: lock aspect ratio for scaling desktop Bug #0058199
337     Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
338     String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
339     String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
340     String width = jalview.bin.Cache.getProperty(windowName
341             + "SCREEN_WIDTH");
342     String height = jalview.bin.Cache.getProperty(windowName
343             + "SCREEN_HEIGHT");
344     if ((x != null) && (y != null) && (width != null) && (height != null))
345     {
346       int ix = Integer.parseInt(x), iy = Integer.parseInt(y), iw = Integer
347               .parseInt(width), ih = Integer.parseInt(height);
348       if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
349       {
350         // attempt #1 - try to cope with change in screen geometry - this
351         // version doesn't preserve original jv aspect ratio.
352         // take ratio of current screen size vs original screen size.
353         double sw = ((1f * screenSize.width) / (1f * Integer
354                 .parseInt(jalview.bin.Cache
355                         .getProperty("SCREENGEOMETRY_WIDTH"))));
356         double sh = ((1f * screenSize.height) / (1f * Integer
357                 .parseInt(jalview.bin.Cache
358                         .getProperty("SCREENGEOMETRY_HEIGHT"))));
359         // rescale the bounds depending upon the current screen geometry.
360         ix = (int) (ix * sw);
361         iw = (int) (iw * sw);
362         iy = (int) (iy * sh);
363         ih = (int) (ih * sh);
364         while (ix >= screenSize.width)
365         {
366           jalview.bin.Cache.log
367                   .debug("Window geometry location recall error: shifting horizontal to within screenbounds.");
368           ix -= screenSize.width;
369         }
370         while (iy >= screenSize.height)
371         {
372           jalview.bin.Cache.log
373                   .debug("Window geometry location recall error: shifting vertical to within screenbounds.");
374           iy -= screenSize.height;
375         }
376         jalview.bin.Cache.log.debug("Got last known dimensions for "
377                 + windowName + ": x:" + ix + " y:" + iy + " width:" + iw
378                 + " height:" + ih);
379       }
380       // return dimensions for new instance
381       return new Rectangle(ix, iy, iw, ih);
382     }
383     return null;
384   }
385
386   private void doVamsasClientCheck()
387   {
388     if (jalview.bin.Cache.vamsasJarsPresent())
389     {
390       setupVamsasDisconnectedGui();
391       VamsasMenu.setVisible(true);
392       final Desktop us = this;
393       VamsasMenu.addMenuListener(new MenuListener()
394       {
395         // this listener remembers when the menu was first selected, and
396         // doesn't rebuild the session list until it has been cleared and
397         // reselected again.
398         boolean refresh = true;
399
400         public void menuCanceled(MenuEvent e)
401         {
402           refresh = true;
403         }
404
405         public void menuDeselected(MenuEvent e)
406         {
407           refresh = true;
408         }
409
410         public void menuSelected(MenuEvent e)
411         {
412           if (refresh)
413           {
414             us.buildVamsasStMenu();
415             refresh = false;
416           }
417         }
418       });
419       vamsasStart.setVisible(true);
420     }
421   }
422
423   void showPasteMenu(int x, int y)
424   {
425     JPopupMenu popup = new JPopupMenu();
426     JMenuItem item = new JMenuItem("Paste To New Window");
427     item.addActionListener(new ActionListener()
428     {
429       public void actionPerformed(ActionEvent evt)
430       {
431         paste();
432       }
433     });
434
435     popup.add(item);
436     popup.show(this, x, y);
437   }
438
439   public void paste()
440   {
441     try
442     {
443       Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
444       Transferable contents = c.getContents(this);
445
446       if (contents != null)
447       {
448         String file = (String) contents
449                 .getTransferData(DataFlavor.stringFlavor);
450
451         String format = new IdentifyFile().Identify(file,
452                 FormatAdapter.PASTE);
453
454         new FileLoader().LoadFile(file, FormatAdapter.PASTE, format);
455
456       }
457     } catch (Exception ex)
458     {
459       System.out
460               .println("Unable to paste alignment from system clipboard:\n"
461                       + ex);
462     }
463   }
464
465   /**
466    * Adds and opens the given frame to the desktop
467    * 
468    * @param frame
469    *          DOCUMENT ME!
470    * @param title
471    *          DOCUMENT ME!
472    * @param w
473    *          DOCUMENT ME!
474    * @param h
475    *          DOCUMENT ME!
476    */
477   public static synchronized void addInternalFrame(
478           final JInternalFrame frame, String title, int w, int h)
479   {
480     addInternalFrame(frame, title, w, h, true);
481   }
482
483   /**
484    * DOCUMENT ME!
485    * 
486    * @param frame
487    *          DOCUMENT ME!
488    * @param title
489    *          DOCUMENT ME!
490    * @param w
491    *          DOCUMENT ME!
492    * @param h
493    *          DOCUMENT ME!
494    * @param resizable
495    *          DOCUMENT ME!
496    */
497   public static synchronized void addInternalFrame(
498           final JInternalFrame frame, String title, int w, int h,
499           boolean resizable)
500   {
501
502     // TODO: allow callers to determine X and Y position of frame (eg. via
503     // bounds object).
504     // TODO: consider fixing method to update entries in the window submenu with
505     // the current window title
506
507     frame.setTitle(title);
508     if (frame.getWidth() < 1 || frame.getHeight() < 1)
509     {
510       frame.setSize(w, h);
511     }
512     // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
513     // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
514     // IF JALVIEW IS RUNNING HEADLESS
515     // ///////////////////////////////////////////////
516     if (System.getProperty("java.awt.headless") != null
517             && System.getProperty("java.awt.headless").equals("true"))
518     {
519       return;
520     }
521
522     openFrameCount++;
523
524     frame.setVisible(true);
525     frame.setClosable(true);
526     frame.setResizable(resizable);
527     frame.setMaximizable(resizable);
528     frame.setIconifiable(resizable);
529     frame.setFrameIcon(null);
530
531     if (frame.getX() < 1 && frame.getY() < 1)
532     {
533       frame.setLocation(xOffset * openFrameCount, yOffset
534               * ((openFrameCount - 1) % 10) + yOffset);
535     }
536
537     final JMenuItem menuItem = new JMenuItem(title);
538     frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
539     {
540       public void internalFrameActivated(
541               javax.swing.event.InternalFrameEvent evt)
542       {
543         JInternalFrame itf = desktop.getSelectedFrame();
544         if (itf != null)
545         {
546           itf.requestFocus();
547         }
548
549       }
550
551       public void internalFrameClosed(
552               javax.swing.event.InternalFrameEvent evt)
553       {
554         PaintRefresher.RemoveComponent(frame);
555         openFrameCount--;
556         windowMenu.remove(menuItem);
557         JInternalFrame itf = desktop.getSelectedFrame();
558         if (itf != null)
559         {
560           itf.requestFocus();
561         }
562         System.gc();
563       };
564     });
565
566     menuItem.addActionListener(new ActionListener()
567     {
568       public void actionPerformed(ActionEvent e)
569       {
570         try
571         {
572           frame.setSelected(true);
573           frame.setIcon(false);
574         } catch (java.beans.PropertyVetoException ex)
575         {
576
577         }
578       }
579     });
580
581     windowMenu.add(menuItem);
582
583     desktop.add(frame);
584     frame.toFront();
585     try
586     {
587       frame.setSelected(true);
588       frame.requestFocus();
589     } catch (java.beans.PropertyVetoException ve)
590     {
591     }
592   }
593
594   public void lostOwnership(Clipboard clipboard, Transferable contents)
595   {
596     if (!internalCopy)
597     {
598       Desktop.jalviewClipboard = null;
599     }
600
601     internalCopy = false;
602   }
603
604   public void dragEnter(DropTargetDragEvent evt)
605   {
606   }
607
608   public void dragExit(DropTargetEvent evt)
609   {
610   }
611
612   public void dragOver(DropTargetDragEvent evt)
613   {
614   }
615
616   public void dropActionChanged(DropTargetDragEvent evt)
617   {
618   }
619
620   /**
621    * DOCUMENT ME!
622    * 
623    * @param evt
624    *          DOCUMENT ME!
625    */
626   public void drop(DropTargetDropEvent evt)
627   {
628     Transferable t = evt.getTransferable();
629     java.util.List files = null;
630     java.util.List protocols = null;
631
632     try
633     {
634       DataFlavor uriListFlavor = new DataFlavor(
635               "text/uri-list;class=java.lang.String");
636       if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
637       {
638         // Works on Windows and MacOSX
639         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
640         files = (java.util.List) t
641                 .getTransferData(DataFlavor.javaFileListFlavor);
642       }
643       else if (t.isDataFlavorSupported(uriListFlavor))
644       {
645         // This is used by Unix drag system
646         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
647         String data = (String) t.getTransferData(uriListFlavor);
648         files = new java.util.ArrayList(1);
649         protocols = new java.util.ArrayList(1);
650         for (java.util.StringTokenizer st = new java.util.StringTokenizer(
651                 data, "\r\n"); st.hasMoreTokens();)
652         {
653           String s = st.nextToken();
654           if (s.startsWith("#"))
655           {
656             // the line is a comment (as per the RFC 2483)
657             continue;
658           }
659           java.net.URI uri = new java.net.URI(s);
660           if (uri.getScheme().toLowerCase().startsWith("http"))
661           {
662             protocols.add(FormatAdapter.URL);
663             files.add(uri.toString());
664           }
665           else
666           {
667             // otherwise preserve old behaviour: catch all for file objects
668             java.io.File file = new java.io.File(uri);
669             protocols.add(FormatAdapter.FILE);
670             files.add(file.toString());
671           }
672         }
673       }
674     } catch (Exception e)
675     {
676     }
677
678     if (files != null)
679     {
680       try
681       {
682         for (int i = 0; i < files.size(); i++)
683         {
684           String file = files.get(i).toString();
685           String protocol = (protocols == null) ? FormatAdapter.FILE
686                   : (String) protocols.get(i);
687           String format = null;
688
689           if (file.endsWith(".jar"))
690           {
691             format = "Jalview";
692
693           }
694           else
695           {
696             format = new IdentifyFile().Identify(file, protocol);
697           }
698
699           new FileLoader().LoadFile(file, protocol, format);
700
701         }
702       } catch (Exception ex)
703       {
704       }
705     }
706   }
707
708   /**
709    * DOCUMENT ME!
710    * 
711    * @param e
712    *          DOCUMENT ME!
713    */
714   public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
715   {
716     JalviewFileChooser chooser = new JalviewFileChooser(
717             jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
718             jalview.io.AppletFormatAdapter.READABLE_EXTENSIONS,
719             jalview.io.AppletFormatAdapter.READABLE_FNAMES,
720             jalview.bin.Cache.getProperty("DEFAULT_FILE_FORMAT"));
721
722     chooser.setFileView(new JalviewFileView());
723     chooser.setDialogTitle("Open local file");
724     chooser.setToolTipText("Open");
725
726     int value = chooser.showOpenDialog(this);
727
728     if (value == JalviewFileChooser.APPROVE_OPTION)
729     {
730       String choice = chooser.getSelectedFile().getPath();
731       jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
732               .getSelectedFile().getParent());
733
734       String format = null;
735       if (chooser.getSelectedFormat().equals("Jalview"))
736       {
737         format = "Jalview";
738       }
739       else
740       {
741         format = new IdentifyFile().Identify(choice, FormatAdapter.FILE);
742       }
743
744       if (viewport != null)
745       {
746         new FileLoader().LoadFile(viewport, choice, FormatAdapter.FILE,
747                 format);
748       }
749       else
750       {
751         new FileLoader().LoadFile(choice, FormatAdapter.FILE, format);
752       }
753     }
754   }
755
756   /**
757    * DOCUMENT ME!
758    * 
759    * @param e
760    *          DOCUMENT ME!
761    */
762   public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
763   {
764     // This construct allows us to have a wider textfield
765     // for viewing
766     JLabel label = new JLabel("Enter URL of Input File");
767     final JComboBox history = new JComboBox();
768
769     JPanel panel = new JPanel(new GridLayout(2, 1));
770     panel.add(label);
771     panel.add(history);
772     history.setPreferredSize(new Dimension(400, 20));
773     history.setEditable(true);
774     history.addItem("http://www.");
775
776     String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
777
778     StringTokenizer st;
779
780     if (historyItems != null)
781     {
782       st = new StringTokenizer(historyItems, "\t");
783
784       while (st.hasMoreTokens())
785       {
786         history.addItem(st.nextElement());
787       }
788     }
789
790     int reply = JOptionPane.showInternalConfirmDialog(desktop, panel,
791             "Input Alignment From URL", JOptionPane.OK_CANCEL_OPTION);
792
793     if (reply != JOptionPane.OK_OPTION)
794     {
795       return;
796     }
797
798     String url = history.getSelectedItem().toString();
799
800     if (url.toLowerCase().endsWith(".jar"))
801     {
802       if (viewport != null)
803       {
804         new FileLoader().LoadFile(viewport, url, FormatAdapter.URL,
805                 "Jalview");
806       }
807       else
808       {
809         new FileLoader().LoadFile(url, FormatAdapter.URL, "Jalview");
810       }
811     }
812     else
813     {
814       String format = new IdentifyFile().Identify(url, FormatAdapter.URL);
815
816       if (format.equals("URL NOT FOUND"))
817       {
818         JOptionPane.showInternalMessageDialog(Desktop.desktop,
819                 "Couldn't locate " + url, "URL not found",
820                 JOptionPane.WARNING_MESSAGE);
821
822         return;
823       }
824
825       if (viewport != null)
826       {
827         new FileLoader().LoadFile(viewport, url, FormatAdapter.URL, format);
828       }
829       else
830       {
831         new FileLoader().LoadFile(url, FormatAdapter.URL, format);
832       }
833     }
834   }
835
836   /**
837    * DOCUMENT ME!
838    * 
839    * @param e
840    *          DOCUMENT ME!
841    */
842   public void inputTextboxMenuItem_actionPerformed(AlignViewport viewport)
843   {
844     CutAndPasteTransfer cap = new CutAndPasteTransfer();
845     cap.setForInput(viewport);
846     Desktop.addInternalFrame(cap, "Cut & Paste Alignment File", 600, 500);
847   }
848
849   /*
850    * Exit the program
851    */
852   public void quit()
853   {
854     Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
855     jalview.bin.Cache
856             .setProperty("SCREENGEOMETRY_WIDTH", screen.width + "");
857     jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT", screen.height
858             + "");
859     storeLastKnownDimensions("", new Rectangle(getBounds().x,
860             getBounds().y, getWidth(), getHeight()));
861
862     if (jconsole != null)
863     {
864       storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
865       jconsole.stopConsole();
866     }
867     System.exit(0);
868   }
869
870   private void storeLastKnownDimensions(String string, Rectangle jc)
871   {
872     jalview.bin.Cache.log.debug("Storing last known dimensions for "
873             + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
874             + " height:" + jc.height);
875
876     jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
877     jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
878     jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
879     jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
880   }
881
882   /**
883    * DOCUMENT ME!
884    * 
885    * @param e
886    *          DOCUMENT ME!
887    */
888   public void aboutMenuItem_actionPerformed(ActionEvent e)
889   {
890     StringBuffer message = new StringBuffer("Jalview version "
891             + jalview.bin.Cache.getProperty("VERSION") + "; last updated: "
892             + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
893
894     if (!jalview.bin.Cache.getProperty("LATEST_VERSION").equals(
895             jalview.bin.Cache.getProperty("VERSION")))
896     {
897       message.append("\n\n!! Jalview version "
898               + jalview.bin.Cache.getProperty("LATEST_VERSION")
899               + " is available for download from http://www.jalview.org !!\n");
900
901     }
902     // TODO: update this text for each release or centrally store it for lite
903     // and application
904     message.append("\nAuthors:  Jim Procter, Andrew Waterhouse, Michele Clamp, James Cuff, Steve Searle,\n    David Martin & Geoff Barton."
905             + "\nDevelopment managed by The Barton Group, University of Dundee, Scotland, UK.\n"
906             + "\nFor help, see the FAQ at www.jalview.org and/or join the jalview-discuss@jalview.org mailing list\n"
907             + "\nIf  you use Jalview, please cite:"
908             + "\nWaterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
909             + "\nJalview Version 2 - a multiple sequence alignment editor and analysis workbench"
910             + "\nBioinformatics doi: 10.1093/bioinformatics/btp033");
911     JOptionPane.showInternalMessageDialog(Desktop.desktop,
912
913     message.toString(), "About Jalview", JOptionPane.INFORMATION_MESSAGE);
914   }
915
916   /**
917    * DOCUMENT ME!
918    * 
919    * @param e
920    *          DOCUMENT ME!
921    */
922   public void documentationMenuItem_actionPerformed(ActionEvent e)
923   {
924     try
925     {
926       ClassLoader cl = jalview.gui.Desktop.class.getClassLoader();
927       java.net.URL url = javax.help.HelpSet.findHelpSet(cl, "help/help");
928       javax.help.HelpSet hs = new javax.help.HelpSet(cl, url);
929
930       javax.help.HelpBroker hb = hs.createHelpBroker();
931       hb.setCurrentID("home");
932       hb.setDisplayed(true);
933     } catch (Exception ex)
934     {
935     }
936   }
937
938   public void closeAll_actionPerformed(ActionEvent e)
939   {
940     JInternalFrame[] frames = desktop.getAllFrames();
941     for (int i = 0; i < frames.length; i++)
942     {
943       try
944       {
945         frames[i].setClosed(true);
946       } catch (java.beans.PropertyVetoException ex)
947       {
948       }
949     }
950     System.out.println("ALL CLOSED");
951     if (v_client != null)
952     {
953       // TODO clear binding to vamsas document objects on close_all
954
955     }
956   }
957
958   public void raiseRelated_actionPerformed(ActionEvent e)
959   {
960     reorderAssociatedWindows(false, false);
961   }
962
963   public void minimizeAssociated_actionPerformed(ActionEvent e)
964   {
965     reorderAssociatedWindows(true, false);
966   }
967
968   void closeAssociatedWindows()
969   {
970     reorderAssociatedWindows(false, true);
971   }
972
973   /*
974    * (non-Javadoc)
975    * 
976    * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
977    * ActionEvent)
978    */
979   protected void garbageCollect_actionPerformed(ActionEvent e)
980   {
981     // We simply collect the garbage
982     jalview.bin.Cache.log.debug("Collecting garbage...");
983     System.gc();
984     jalview.bin.Cache.log.debug("Finished garbage collection.");
985   }
986
987   /*
988    * (non-Javadoc)
989    * 
990    * @see
991    * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
992    * )
993    */
994   protected void showMemusage_actionPerformed(ActionEvent e)
995   {
996     desktop.showMemoryUsage(showMemusage.isSelected());
997   }
998
999   /*
1000    * (non-Javadoc)
1001    * 
1002    * @see
1003    * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1004    * )
1005    */
1006   protected void showConsole_actionPerformed(ActionEvent e)
1007   {
1008     showConsole(showConsole.isSelected());
1009   }
1010
1011   Console jconsole = null;
1012
1013   /**
1014    * control whether the java console is visible or not
1015    * 
1016    * @param selected
1017    */
1018   void showConsole(boolean selected)
1019   {
1020     showConsole.setSelected(selected);
1021     // TODO: decide if we should update properties file
1022     Cache.setProperty("SHOW_JAVA_CONSOLE", Boolean.valueOf(selected)
1023             .toString());
1024     jconsole.setVisible(selected);
1025   }
1026
1027   void reorderAssociatedWindows(boolean minimize, boolean close)
1028   {
1029     JInternalFrame[] frames = desktop.getAllFrames();
1030     if (frames == null || frames.length < 1)
1031     {
1032       return;
1033     }
1034
1035     AlignViewport source = null, target = null;
1036     if (frames[0] instanceof AlignFrame)
1037     {
1038       source = ((AlignFrame) frames[0]).getCurrentView();
1039     }
1040     else if (frames[0] instanceof TreePanel)
1041     {
1042       source = ((TreePanel) frames[0]).getViewPort();
1043     }
1044     else if (frames[0] instanceof PCAPanel)
1045     {
1046       source = ((PCAPanel) frames[0]).av;
1047     }
1048     else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1049     {
1050       source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1051     }
1052
1053     if (source != null)
1054     {
1055       for (int i = 0; i < frames.length; i++)
1056       {
1057         target = null;
1058         if (frames[i] == null)
1059         {
1060           continue;
1061         }
1062         if (frames[i] instanceof AlignFrame)
1063         {
1064           target = ((AlignFrame) frames[i]).getCurrentView();
1065         }
1066         else if (frames[i] instanceof TreePanel)
1067         {
1068           target = ((TreePanel) frames[i]).getViewPort();
1069         }
1070         else if (frames[i] instanceof PCAPanel)
1071         {
1072           target = ((PCAPanel) frames[i]).av;
1073         }
1074         else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1075         {
1076           target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1077         }
1078
1079         if (source == target)
1080         {
1081           try
1082           {
1083             if (close)
1084             {
1085               frames[i].setClosed(true);
1086             }
1087             else
1088             {
1089               frames[i].setIcon(minimize);
1090               if (!minimize)
1091               {
1092                 frames[i].toFront();
1093               }
1094             }
1095
1096           } catch (java.beans.PropertyVetoException ex)
1097           {
1098           }
1099         }
1100       }
1101     }
1102   }
1103
1104   /**
1105    * DOCUMENT ME!
1106    * 
1107    * @param e
1108    *          DOCUMENT ME!
1109    */
1110   protected void preferences_actionPerformed(ActionEvent e)
1111   {
1112     new Preferences();
1113   }
1114
1115   /**
1116    * DOCUMENT ME!
1117    * 
1118    * @param e
1119    *          DOCUMENT ME!
1120    */
1121   public void saveState_actionPerformed(ActionEvent e)
1122   {
1123     JalviewFileChooser chooser = new JalviewFileChooser(
1124             jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
1125             { "jar" }, new String[]
1126             { "Jalview Project" }, "Jalview Project");
1127
1128     chooser.setFileView(new JalviewFileView());
1129     chooser.setDialogTitle("Save State");
1130
1131     int value = chooser.showSaveDialog(this);
1132
1133     if (value == JalviewFileChooser.APPROVE_OPTION)
1134     {
1135       java.io.File choice = chooser.getSelectedFile();
1136       setProgressBar("Saving jalview project " + choice.getName(),
1137               choice.hashCode());
1138       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice.getParent());
1139       // TODO catch and handle errors for savestate
1140       try
1141       {
1142         new Jalview2XML().SaveState(choice);
1143       } catch (OutOfMemoryError oom)
1144       {
1145         new OOMWarning(
1146                 "Whilst saving current state to " + choice.getName(), oom);
1147       } catch (Exception ex)
1148       {
1149         Cache.log
1150                 .error("Problems whilst trying to save to "
1151                         + choice.getName(), ex);
1152         JOptionPane.showMessageDialog(this,
1153                 "Error whilst saving current state to " + choice.getName(),
1154                 "Couldn't save project", JOptionPane.WARNING_MESSAGE);
1155       }
1156       setProgressBar(null, choice.hashCode());
1157
1158     }
1159   }
1160
1161   /**
1162    * DOCUMENT ME!
1163    * 
1164    * @param e
1165    *          DOCUMENT ME!
1166    */
1167   public void loadState_actionPerformed(ActionEvent e)
1168   {
1169     JalviewFileChooser chooser = new JalviewFileChooser(
1170             jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
1171             { "jar" }, new String[]
1172             { "Jalview Project" }, "Jalview Project");
1173     chooser.setFileView(new JalviewFileView());
1174     chooser.setDialogTitle("Restore state");
1175
1176     int value = chooser.showOpenDialog(this);
1177
1178     if (value == JalviewFileChooser.APPROVE_OPTION)
1179     {
1180       final String choice = chooser.getSelectedFile().getAbsolutePath();
1181       jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
1182               .getSelectedFile().getParent());
1183       new Thread(new Runnable()
1184       {
1185         public void run()
1186         {
1187           setProgressBar("loading jalview project " + choice,
1188                   choice.hashCode());
1189           try
1190           {
1191             new Jalview2XML().LoadJalviewAlign(choice);
1192           } catch (OutOfMemoryError oom)
1193           {
1194             new OOMWarning("Whilst loading project from " + choice, oom);
1195           } catch (Exception ex)
1196           {
1197             Cache.log.error("Problems whilst loading project from "
1198                     + choice, ex);
1199             JOptionPane.showMessageDialog(Desktop.desktop,
1200                     "Error whilst loading project from " + choice,
1201                     "Couldn't load project", JOptionPane.WARNING_MESSAGE);
1202           }
1203           setProgressBar(null, choice.hashCode());
1204         }
1205       }).start();
1206     }
1207   }
1208
1209   public void inputSequence_actionPerformed(ActionEvent e)
1210   {
1211     new SequenceFetcher(this);
1212   }
1213
1214   JPanel progressPanel;
1215
1216   public void startLoading(final String fileName)
1217   {
1218     if (fileLoadingCount == 0)
1219     {
1220       addProgressPanel("Loading File: " + fileName + "   ");
1221
1222     }
1223     fileLoadingCount++;
1224   }
1225
1226   private JProgressBar addProgressPanel(String string)
1227   {
1228     if (progressPanel == null)
1229     {
1230       progressPanel = new JPanel(new BorderLayout());
1231       totalProgressCount = 0;
1232     }
1233     JProgressBar progressBar = new JProgressBar();
1234     progressBar.setIndeterminate(true);
1235
1236     progressPanel.add(new JLabel(string), BorderLayout.WEST);
1237
1238     progressPanel.add(progressBar, BorderLayout.CENTER);
1239
1240     instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1241     totalProgressCount++;
1242     validate();
1243     return progressBar;
1244   }
1245
1246   int totalProgressCount = 0;
1247
1248   private void removeProgressPanel(JProgressBar progbar)
1249   {
1250     if (progressPanel != null)
1251     {
1252       progressPanel.remove(progbar);
1253       if (--totalProgressCount < 1)
1254       {
1255         this.getContentPane().remove(progressPanel);
1256         progressPanel = null;
1257       }
1258     }
1259     validate();
1260   }
1261
1262   public void stopLoading()
1263   {
1264     fileLoadingCount--;
1265     if (fileLoadingCount < 1)
1266     {
1267       if (progressPanel != null)
1268       {
1269         this.getContentPane().remove(progressPanel);
1270         progressPanel = null;
1271       }
1272       fileLoadingCount = 0;
1273     }
1274     validate();
1275   }
1276
1277   public static int getViewCount(String viewId)
1278   {
1279     AlignViewport[] aps = getViewports(viewId);
1280     return (aps == null) ? 0 : aps.length;
1281   }
1282
1283   /**
1284    * 
1285    * @param viewId
1286    * @return all AlignmentPanels concerning the viewId sequence set
1287    */
1288   public static AlignmentPanel[] getAlignmentPanels(String viewId)
1289   {
1290     int count = 0;
1291     if (Desktop.desktop == null)
1292     {
1293       // no frames created and in headless mode
1294       // TODO: verify that frames are recoverable when in headless mode
1295       return null;
1296     }
1297     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1298     ArrayList aps = new ArrayList();
1299     for (int t = 0; t < frames.length; t++)
1300     {
1301       if (frames[t] instanceof AlignFrame)
1302       {
1303         AlignFrame af = (AlignFrame) frames[t];
1304         for (int a = 0; a < af.alignPanels.size(); a++)
1305         {
1306           if (viewId
1307                   .equals(((AlignmentPanel) af.alignPanels.elementAt(a)).av
1308                           .getSequenceSetId()))
1309           {
1310             aps.add(af.alignPanels.elementAt(a));
1311           }
1312         }
1313       }
1314     }
1315     if (aps.size() == 0)
1316     {
1317       return null;
1318     }
1319     AlignmentPanel[] vap = new AlignmentPanel[aps.size()];
1320     for (int t = 0; t < vap.length; t++)
1321     {
1322       vap[t] = (AlignmentPanel) aps.get(t);
1323     }
1324     return vap;
1325   }
1326
1327   /**
1328    * get all the viewports on an alignment.
1329    * 
1330    * @param sequenceSetId
1331    *          unique alignment id
1332    * @return all viewports on the alignment bound to sequenceSetId
1333    */
1334   public static AlignViewport[] getViewports(String sequenceSetId)
1335   {
1336     Vector viewp = new Vector();
1337     if (desktop != null)
1338     {
1339       javax.swing.JInternalFrame[] frames = instance.getAllFrames();
1340
1341       for (int t = 0; t < frames.length; t++)
1342       {
1343         if (frames[t] instanceof AlignFrame)
1344         {
1345           AlignFrame afr = ((AlignFrame) frames[t]);
1346           if (afr.getViewport().getSequenceSetId().equals(sequenceSetId))
1347           {
1348             if (afr.alignPanels != null)
1349             {
1350               for (int a = 0; a < afr.alignPanels.size(); a++)
1351               {
1352                 if (sequenceSetId.equals(((AlignmentPanel) afr.alignPanels
1353                         .elementAt(a)).av.getSequenceSetId()))
1354                 {
1355                   viewp.addElement(((AlignmentPanel) afr.alignPanels
1356                           .elementAt(a)).av);
1357                 }
1358               }
1359             }
1360             else
1361             {
1362               viewp.addElement(((AlignFrame) frames[t]).getViewport());
1363             }
1364           }
1365         }
1366       }
1367       if (viewp.size() > 0)
1368       {
1369         AlignViewport[] vp = new AlignViewport[viewp.size()];
1370         viewp.copyInto(vp);
1371         return vp;
1372       }
1373     }
1374     return null;
1375   }
1376
1377   public void explodeViews(AlignFrame af)
1378   {
1379     int size = af.alignPanels.size();
1380     if (size < 2)
1381     {
1382       return;
1383     }
1384
1385     for (int i = 0; i < size; i++)
1386     {
1387       AlignmentPanel ap = (AlignmentPanel) af.alignPanels.elementAt(i);
1388       AlignFrame newaf = new AlignFrame(ap);
1389       if (ap.av.explodedPosition != null
1390               && !ap.av.explodedPosition.equals(af.getBounds()))
1391       {
1392         newaf.setBounds(ap.av.explodedPosition);
1393       }
1394
1395       ap.av.gatherViewsHere = false;
1396
1397       addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1398               AlignFrame.DEFAULT_HEIGHT);
1399     }
1400
1401     af.alignPanels.clear();
1402     af.closeMenuItem_actionPerformed(true);
1403
1404   }
1405
1406   public void gatherViews(AlignFrame source)
1407   {
1408     source.viewport.gatherViewsHere = true;
1409     source.viewport.explodedPosition = source.getBounds();
1410     JInternalFrame[] frames = desktop.getAllFrames();
1411     String viewId = source.viewport.sequenceSetID;
1412
1413     for (int t = 0; t < frames.length; t++)
1414     {
1415       if (frames[t] instanceof AlignFrame && frames[t] != source)
1416       {
1417         AlignFrame af = (AlignFrame) frames[t];
1418         boolean gatherThis = false;
1419         for (int a = 0; a < af.alignPanels.size(); a++)
1420         {
1421           AlignmentPanel ap = (AlignmentPanel) af.alignPanels.elementAt(a);
1422           if (viewId.equals(ap.av.getSequenceSetId()))
1423           {
1424             gatherThis = true;
1425             ap.av.gatherViewsHere = false;
1426             ap.av.explodedPosition = af.getBounds();
1427             source.addAlignmentPanel(ap, false);
1428           }
1429         }
1430
1431         if (gatherThis)
1432         {
1433           af.alignPanels.clear();
1434           af.closeMenuItem_actionPerformed(true);
1435         }
1436       }
1437     }
1438
1439   }
1440
1441   jalview.gui.VamsasApplication v_client = null;
1442
1443   public void vamsasImport_actionPerformed(ActionEvent e)
1444   {
1445     if (v_client == null)
1446     {
1447       // Load and try to start a session.
1448       JalviewFileChooser chooser = new JalviewFileChooser(
1449               jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
1450
1451       chooser.setFileView(new JalviewFileView());
1452       chooser.setDialogTitle("Open a saved VAMSAS session");
1453       chooser.setToolTipText("select a vamsas session to be opened as a new vamsas session.");
1454
1455       int value = chooser.showOpenDialog(this);
1456
1457       if (value == JalviewFileChooser.APPROVE_OPTION)
1458       {
1459         String fle = chooser.getSelectedFile().toString();
1460         if (!vamsasImport(chooser.getSelectedFile()))
1461         {
1462           JOptionPane.showInternalMessageDialog(Desktop.desktop,
1463                   "Couldn't import '" + fle + "' as a new vamsas session.",
1464                   "Vamsas Document Import Failed",
1465                   JOptionPane.ERROR_MESSAGE);
1466         }
1467       }
1468     }
1469     else
1470     {
1471       jalview.bin.Cache.log
1472               .error("Implementation error - load session from a running session is not supported.");
1473     }
1474   }
1475
1476   /**
1477    * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
1478    * 
1479    * @param file
1480    * @return true if import was a success and a session was started.
1481    */
1482   public boolean vamsasImport(URL url)
1483   {
1484     // TODO: create progress bar
1485     if (v_client != null)
1486     {
1487
1488       jalview.bin.Cache.log
1489               .error("Implementation error - load session from a running session is not supported.");
1490       return false;
1491     }
1492
1493     try
1494     {
1495       // copy the URL content to a temporary local file
1496       // TODO: be a bit cleverer here with nio (?!)
1497       File file = File.createTempFile("vdocfromurl", ".vdj");
1498       FileOutputStream fos = new FileOutputStream(file);
1499       BufferedInputStream bis = new BufferedInputStream(url.openStream());
1500       byte[] buffer = new byte[2048];
1501       int ln;
1502       while ((ln = bis.read(buffer)) > -1)
1503       {
1504         fos.write(buffer, 0, ln);
1505       }
1506       bis.close();
1507       fos.close();
1508       v_client = new jalview.gui.VamsasApplication(this, file,
1509               url.toExternalForm());
1510     } catch (Exception ex)
1511     {
1512       jalview.bin.Cache.log.error(
1513               "Failed to create new vamsas session from contents of URL "
1514                       + url, ex);
1515       return false;
1516     }
1517     setupVamsasConnectedGui();
1518     v_client.initial_update(); // TODO: thread ?
1519     return v_client.inSession();
1520   }
1521
1522   /**
1523    * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
1524    * 
1525    * @param file
1526    * @return true if import was a success and a session was started.
1527    */
1528   public boolean vamsasImport(File file)
1529   {
1530     if (v_client != null)
1531     {
1532
1533       jalview.bin.Cache.log
1534               .error("Implementation error - load session from a running session is not supported.");
1535       return false;
1536     }
1537
1538     setProgressBar("Importing VAMSAS session from " + file.getName(),
1539             file.hashCode());
1540     try
1541     {
1542       v_client = new jalview.gui.VamsasApplication(this, file, null);
1543     } catch (Exception ex)
1544     {
1545       setProgressBar("Importing VAMSAS session from " + file.getName(),
1546               file.hashCode());
1547       jalview.bin.Cache.log.error(
1548               "New vamsas session from existing session file failed:", ex);
1549       return false;
1550     }
1551     setupVamsasConnectedGui();
1552     v_client.initial_update(); // TODO: thread ?
1553     setProgressBar("Importing VAMSAS session from " + file.getName(),
1554             file.hashCode());
1555     return v_client.inSession();
1556   }
1557
1558   public boolean joinVamsasSession(String mysesid)
1559   {
1560     if (v_client != null)
1561     {
1562       throw new Error(
1563               "Trying to join a vamsas session when another is already connected.");
1564     }
1565     if (mysesid == null)
1566     {
1567       throw new Error("Invalid vamsas session id.");
1568     }
1569     v_client = new VamsasApplication(this, mysesid);
1570     setupVamsasConnectedGui();
1571     v_client.initial_update();
1572     return (v_client.inSession());
1573   }
1574
1575   public void vamsasStart_actionPerformed(ActionEvent e)
1576   {
1577     if (v_client == null)
1578     {
1579       // Start a session.
1580       // we just start a default session for moment.
1581       /*
1582        * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
1583        * getProperty("LAST_DIRECTORY"));
1584        * 
1585        * chooser.setFileView(new JalviewFileView());
1586        * chooser.setDialogTitle("Load Vamsas file");
1587        * chooser.setToolTipText("Import");
1588        * 
1589        * int value = chooser.showOpenDialog(this);
1590        * 
1591        * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
1592        * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
1593        */
1594       v_client = new VamsasApplication(this);
1595       setupVamsasConnectedGui();
1596       v_client.initial_update(); // TODO: thread ?
1597     }
1598     else
1599     {
1600       // store current data in session.
1601       v_client.push_update(); // TODO: thread
1602     }
1603   }
1604
1605   protected void setupVamsasConnectedGui()
1606   {
1607     vamsasStart.setText("Session Update");
1608     vamsasSave.setVisible(true);
1609     vamsasStop.setVisible(true);
1610     vamsasImport.setVisible(false); // Document import to existing session is
1611     // not possible for vamsas-client-1.0.
1612   }
1613
1614   protected void setupVamsasDisconnectedGui()
1615   {
1616     vamsasSave.setVisible(false);
1617     vamsasStop.setVisible(false);
1618     vamsasImport.setVisible(true);
1619     vamsasStart.setText("New Vamsas Session");
1620   }
1621
1622   public void vamsasStop_actionPerformed(ActionEvent e)
1623   {
1624     if (v_client != null)
1625     {
1626       v_client.end_session();
1627       v_client = null;
1628       setupVamsasDisconnectedGui();
1629     }
1630   }
1631
1632   protected void buildVamsasStMenu()
1633   {
1634     if (v_client == null)
1635     {
1636       String[] sess = null;
1637       try
1638       {
1639         sess = VamsasApplication.getSessionList();
1640       } catch (Exception e)
1641       {
1642         jalview.bin.Cache.log.warn(
1643                 "Problem getting current sessions list.", e);
1644         sess = null;
1645       }
1646       if (sess != null)
1647       {
1648         jalview.bin.Cache.log.debug("Got current sessions list: "
1649                 + sess.length + " entries.");
1650         VamsasStMenu.removeAll();
1651         for (int i = 0; i < sess.length; i++)
1652         {
1653           JMenuItem sessit = new JMenuItem();
1654           sessit.setText(sess[i]);
1655           sessit.setToolTipText("Connect to session " + sess[i]);
1656           final Desktop dsktp = this;
1657           final String mysesid = sess[i];
1658           sessit.addActionListener(new ActionListener()
1659           {
1660
1661             public void actionPerformed(ActionEvent e)
1662             {
1663               if (dsktp.v_client == null)
1664               {
1665                 Thread rthr = new Thread(new Runnable()
1666                 {
1667
1668                   public void run()
1669                   {
1670                     dsktp.v_client = new VamsasApplication(dsktp, mysesid);
1671                     dsktp.setupVamsasConnectedGui();
1672                     dsktp.v_client.initial_update();
1673                   }
1674
1675                 });
1676                 rthr.start();
1677               }
1678             };
1679           });
1680           VamsasStMenu.add(sessit);
1681         }
1682         // don't show an empty menu.
1683         VamsasStMenu.setVisible(sess.length > 0);
1684
1685       }
1686       else
1687       {
1688         jalview.bin.Cache.log.debug("No current vamsas sessions.");
1689         VamsasStMenu.removeAll();
1690         VamsasStMenu.setVisible(false);
1691       }
1692     }
1693     else
1694     {
1695       // Not interested in the content. Just hide ourselves.
1696       VamsasStMenu.setVisible(false);
1697     }
1698   }
1699
1700   public void vamsasSave_actionPerformed(ActionEvent e)
1701   {
1702     if (v_client != null)
1703     {
1704       JalviewFileChooser chooser = new JalviewFileChooser(
1705               jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
1706               { "vdj" }, // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
1707               new String[]
1708               { "Vamsas Document" }, "Vamsas Document");
1709
1710       chooser.setFileView(new JalviewFileView());
1711       chooser.setDialogTitle("Save Vamsas Document Archive");
1712
1713       int value = chooser.showSaveDialog(this);
1714
1715       if (value == JalviewFileChooser.APPROVE_OPTION)
1716       {
1717         java.io.File choice = chooser.getSelectedFile();
1718         JProgressBar progpanel = addProgressPanel("Saving VAMSAS Document to "
1719                 + choice.getName());
1720         jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice.getParent());
1721         String warnmsg = null;
1722         String warnttl = null;
1723         try
1724         {
1725           v_client.vclient.storeDocument(choice);
1726         } catch (Error ex)
1727         {
1728           warnttl = "Serious Problem saving Vamsas Document";
1729           warnmsg = ex.toString();
1730           jalview.bin.Cache.log.error("Error Whilst saving document to "
1731                   + choice, ex);
1732
1733         } catch (Exception ex)
1734         {
1735           warnttl = "Problem saving Vamsas Document.";
1736           warnmsg = ex.toString();
1737           jalview.bin.Cache.log.warn("Exception Whilst saving document to "
1738                   + choice, ex);
1739
1740         }
1741         removeProgressPanel(progpanel);
1742         if (warnmsg != null)
1743         {
1744           JOptionPane.showInternalMessageDialog(Desktop.desktop,
1745
1746           warnmsg, warnttl, JOptionPane.ERROR_MESSAGE);
1747         }
1748       }
1749     }
1750   }
1751
1752   JProgressBar vamUpdate = null;
1753
1754   /**
1755    * hide vamsas user gui bits when a vamsas document event is being handled.
1756    * 
1757    * @param b
1758    *          true to hide gui, false to reveal gui
1759    */
1760   public void setVamsasUpdate(boolean b)
1761   {
1762     jalview.bin.Cache.log.debug("Setting gui for Vamsas update "
1763             + (b ? "in progress" : "finished"));
1764
1765     if (vamUpdate != null)
1766     {
1767       this.removeProgressPanel(vamUpdate);
1768     }
1769     if (b)
1770     {
1771       vamUpdate = this.addProgressPanel("Updating vamsas session");
1772     }
1773     vamsasStart.setVisible(!b);
1774     vamsasStop.setVisible(!b);
1775     vamsasSave.setVisible(!b);
1776   }
1777
1778   public JInternalFrame[] getAllFrames()
1779   {
1780     return desktop.getAllFrames();
1781   }
1782
1783   /**
1784    * Checks the given url to see if it gives a response indicating that the user
1785    * should be informed of a new questionnaire.
1786    * 
1787    * @param url
1788    */
1789   public void checkForQuestionnaire(String url)
1790   {
1791     UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
1792     // javax.swing.SwingUtilities.invokeLater(jvq);
1793     new Thread(jvq).start();
1794   }
1795
1796   /**
1797    * Proxy class for JDesktopPane which optionally displays the current memory
1798    * usage and highlights the desktop area with a red bar if free memory runs
1799    * low.
1800    * 
1801    * @author AMW
1802    */
1803   public class MyDesktopPane extends JDesktopPane implements Runnable
1804   {
1805
1806     boolean showMemoryUsage = false;
1807
1808     Runtime runtime;
1809
1810     java.text.NumberFormat df;
1811
1812     float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
1813             percentUsage;
1814
1815     public MyDesktopPane(boolean showMemoryUsage)
1816     {
1817       showMemoryUsage(showMemoryUsage);
1818     }
1819
1820     public void showMemoryUsage(boolean showMemoryUsage)
1821     {
1822       this.showMemoryUsage = showMemoryUsage;
1823       if (showMemoryUsage)
1824       {
1825         Thread worker = new Thread(this);
1826         worker.start();
1827       }
1828     }
1829
1830     public boolean isShowMemoryUsage()
1831     {
1832       return showMemoryUsage;
1833     }
1834
1835     public void run()
1836     {
1837       df = java.text.NumberFormat.getNumberInstance();
1838       df.setMaximumFractionDigits(2);
1839       runtime = Runtime.getRuntime();
1840
1841       while (showMemoryUsage)
1842       {
1843         try
1844         {
1845           maxMemory = runtime.maxMemory() / 1048576f;
1846           allocatedMemory = runtime.totalMemory() / 1048576f;
1847           freeMemory = runtime.freeMemory() / 1048576f;
1848           totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
1849
1850           percentUsage = (totalFreeMemory / maxMemory) * 100;
1851
1852           // if (percentUsage < 20)
1853           {
1854             // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
1855             // Color.red);
1856             // instance.set.setBorder(border1);
1857           }
1858           repaint();
1859           // sleep after showing usage
1860           Thread.sleep(3000);
1861         } catch (Exception ex)
1862         {
1863           ex.printStackTrace();
1864         }
1865       }
1866     }
1867
1868     public void paintComponent(Graphics g)
1869     {
1870       if (showMemoryUsage && g != null && df != null)
1871       {
1872         if (percentUsage < 20)
1873           g.setColor(Color.red);
1874         FontMetrics fm = g.getFontMetrics();
1875         if (fm != null)
1876         {
1877           g.drawString(
1878                   "Total Free Memory: " + df.format(totalFreeMemory)
1879                           + "MB; Max Memory: " + df.format(maxMemory)
1880                           + "MB; " + df.format(percentUsage) + "%", 10,
1881                   getHeight() - fm.getHeight());
1882         }
1883       }
1884     }
1885
1886   }
1887
1888   protected JMenuItem groovyShell;
1889
1890   public void doGroovyCheck()
1891   {
1892     if (jalview.bin.Cache.groovyJarsPresent())
1893     {
1894       groovyShell = new JMenuItem();
1895       groovyShell.setText("Groovy Console...");
1896       groovyShell.addActionListener(new ActionListener()
1897       {
1898         public void actionPerformed(ActionEvent e)
1899         {
1900           groovyShell_actionPerformed(e);
1901         }
1902       });
1903       toolsMenu.add(groovyShell);
1904       groovyShell.setVisible(true);
1905     }
1906   }
1907
1908   /**
1909    * Accessor method to quickly get all the AlignmentFrames loaded.
1910    */
1911   public static AlignFrame[] getAlignframes()
1912   {
1913     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1914
1915     if (frames == null)
1916     {
1917       return null;
1918     }
1919     Vector avp = new Vector();
1920     try
1921     {
1922       // REVERSE ORDER
1923       for (int i = frames.length - 1; i > -1; i--)
1924       {
1925         if (frames[i] instanceof AlignFrame)
1926         {
1927           AlignFrame af = (AlignFrame) frames[i];
1928           avp.addElement(af);
1929         }
1930       }
1931     } catch (Exception ex)
1932     {
1933       ex.printStackTrace();
1934     }
1935     if (avp.size() == 0)
1936     {
1937       return null;
1938     }
1939     AlignFrame afs[] = new AlignFrame[avp.size()];
1940     for (int i = 0, j = avp.size(); i < j; i++)
1941     {
1942       afs[i] = (AlignFrame) avp.elementAt(i);
1943     }
1944     avp.clear();
1945     return afs;
1946   }
1947
1948   /**
1949    * Add Groovy Support to Jalview
1950    */
1951   public void groovyShell_actionPerformed(ActionEvent e)
1952   {
1953     // use reflection to avoid creating compilation dependency.
1954     if (!jalview.bin.Cache.groovyJarsPresent())
1955     {
1956       throw new Error(
1957               "Implementation Error. Cannot create groovyShell without Groovy on the classpath!");
1958     }
1959     try
1960     {
1961       Class gcClass = Desktop.class.getClassLoader().loadClass(
1962               "groovy.ui.Console");
1963       Constructor gccons = gcClass.getConstructor(null);
1964       java.lang.reflect.Method setvar = gcClass.getMethod("setVariable",
1965               new Class[]
1966               { String.class, Object.class });
1967       java.lang.reflect.Method run = gcClass.getMethod("run", null);
1968       Object gc = gccons.newInstance(null);
1969       setvar.invoke(gc, new Object[]
1970       { "Jalview", this });
1971       run.invoke(gc, null);
1972     } catch (Exception ex)
1973     {
1974       jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
1975       JOptionPane
1976               .showInternalMessageDialog(
1977                       Desktop.desktop,
1978
1979                       "Couldn't create the groovy Shell. Check the error log for the details of what went wrong.",
1980                       "Jalview Groovy Support Failed",
1981                       JOptionPane.ERROR_MESSAGE);
1982     }
1983   }
1984
1985   /**
1986    * Progress bars managed by the IProgressIndicator method.
1987    */
1988   private Hashtable progressBars, progressBarHandlers;
1989
1990   /*
1991    * (non-Javadoc)
1992    * 
1993    * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
1994    */
1995   public void setProgressBar(String message, long id)
1996   {
1997     if (progressBars == null)
1998     {
1999       progressBars = new Hashtable();
2000       progressBarHandlers = new Hashtable();
2001     }
2002
2003     if (progressBars.get(new Long(id)) != null)
2004     {
2005       JProgressBar progressPanel = (JProgressBar) progressBars
2006               .remove(new Long(id));
2007       if (progressBarHandlers.contains(new Long(id)))
2008       {
2009         progressBarHandlers.remove(new Long(id));
2010       }
2011       removeProgressPanel(progressPanel);
2012     }
2013     else
2014     {
2015       progressBars.put(new Long(id), addProgressPanel(message));
2016     }
2017   }
2018
2019   /*
2020    * (non-Javadoc)
2021    * 
2022    * @see jalview.gui.IProgressIndicator#registerHandler(long,
2023    * jalview.gui.IProgressIndicatorHandler)
2024    */
2025   public void registerHandler(final long id,
2026           final IProgressIndicatorHandler handler)
2027   {
2028     if (progressBarHandlers == null || !progressBars.contains(new Long(id)))
2029     {
2030       throw new Error(
2031               "call setProgressBar before registering the progress bar's handler.");
2032     }
2033     progressBarHandlers.put(new Long(id), handler);
2034     final JPanel progressPanel = (JPanel) progressBars.get(new Long(id));
2035     if (handler.canCancel())
2036     {
2037       JButton cancel = new JButton("Cancel");
2038       final IProgressIndicator us = this;
2039       cancel.addActionListener(new ActionListener()
2040       {
2041
2042         public void actionPerformed(ActionEvent e)
2043         {
2044           handler.cancelActivity(id);
2045           us.setProgressBar(
2046                   "Cancelled "
2047                           + ((JLabel) progressPanel.getComponent(0))
2048                                   .getText(), id);
2049         }
2050       });
2051       progressPanel.add(cancel, BorderLayout.EAST);
2052     }
2053   }
2054
2055   /**
2056    * This will return the first AlignFrame viewing AlignViewport av. It will
2057    * break if there are more than one AlignFrames viewing a particular av. This
2058    * 
2059    * @param av
2060    * @return alignFrame for av
2061    */
2062   public static AlignFrame getAlignFrameFor(AlignViewport av)
2063   {
2064     if (desktop != null)
2065     {
2066       AlignmentPanel[] aps = getAlignmentPanels(av.getSequenceSetId());
2067       for (int panel = 0; aps != null && panel < aps.length; panel++)
2068       {
2069         if (aps[panel] != null && aps[panel].av == av)
2070         {
2071           return aps[panel].alignFrame;
2072         }
2073       }
2074     }
2075     return null;
2076   }
2077
2078   public VamsasApplication getVamsasApplication()
2079   {
2080     return v_client;
2081
2082   }
2083
2084   /**
2085    * flag set if jalview GUI is being operated programmatically
2086    */
2087   private boolean inBatchMode = false;
2088
2089   /**
2090    * check if jalview GUI is being operated programmatically
2091    * 
2092    * @return inBatchMode
2093    */
2094   public boolean isInBatchMode()
2095   {
2096     return inBatchMode;
2097   }
2098
2099   /**
2100    * set flag if jalview GUI is being operated programmatically
2101    * 
2102    * @param inBatchMode
2103    */
2104   public void setInBatchMode(boolean inBatchMode)
2105   {
2106     this.inBatchMode = inBatchMode;
2107   }
2108
2109   public void startServiceDiscovery()
2110   {
2111     startServiceDiscovery(false);
2112   }
2113
2114   public void startServiceDiscovery(boolean blocking)
2115   {
2116     boolean alive = true;
2117     Thread t0 = null, t1 = null, t2 = null;
2118
2119     // todo: changesupport handlers need to be transferred
2120     if (discoverer == null)
2121     {
2122       discoverer = new jalview.ws.jws1.Discoverer();
2123       // register PCS handler for desktop.
2124       discoverer.addPropertyChangeListener(changeSupport);
2125     }
2126     if (Cache.getDefault("SHOW_JWS1_SERVICES", true))
2127     {
2128       (t0 = new Thread(discoverer)).start();
2129     }
2130
2131     try
2132     {
2133       if (Cache.getDefault("SHOW_ENFIN_SERVICES", true))
2134       {
2135         // EnfinEnvision web service menu entries are rebuild every time the
2136         // menu is shown, so no changeSupport events are needed.
2137         jalview.ws.EnfinEnvision2OneWay.getInstance();
2138         (t1 = new Thread(jalview.ws.EnfinEnvision2OneWay.getInstance()))
2139                 .start();
2140       }
2141     } catch (Exception e)
2142     {
2143       Cache.log
2144               .info("Exception when trying to launch Envision2 workflow discovery.",
2145                       e);
2146       Cache.log.info(e.getStackTrace());
2147     }
2148     if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2149     {
2150       if (jalview.ws.jws2.Jws2Discoverer.getDiscoverer().isRunning())
2151       {
2152         jalview.ws.jws2.Jws2Discoverer.getDiscoverer().setAborted(true);
2153       }
2154       t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer().startDiscoverer(
2155               changeSupport);
2156
2157     }
2158     if (blocking)
2159     {
2160       while (alive)
2161       {
2162         try
2163         {
2164           Thread.sleep(15);
2165         } catch (Exception e)
2166         {
2167         }
2168         alive = (t1 != null && t1.isAlive())
2169                 || (t2 != null && t2.isAlive())
2170                 || (t0 != null && t0.isAlive());
2171       }
2172     }
2173   }
2174
2175   /**
2176    * called to check if the service discovery process completed successfully.
2177    * 
2178    * @param evt
2179    */
2180   protected void JalviewServicesChanged(PropertyChangeEvent evt)
2181   {
2182     if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2183     {
2184       final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2185               .getErrorMessages();
2186       if (ermsg != null)
2187       {
2188         if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
2189         {
2190           if (serviceChangedDialog == null)
2191
2192           {
2193             // only run if we aren't already displaying one of these.
2194             javax.swing.SwingUtilities
2195                     .invokeLater(serviceChangedDialog = new Runnable()
2196                     {
2197                       public void run()
2198                       {
2199
2200                         JOptionPane
2201                                 .showInternalMessageDialog(
2202                                         Desktop.desktop,
2203                                         ermsg
2204                                                 + "It may be that you have invalid JABA URLs\nin your web service preferences.\n\nGo to the Web services tab of the\nTools->Preferences dialog box to change them.\n",
2205                                         "Preferences Problem",
2206                                         JOptionPane.WARNING_MESSAGE);
2207                         serviceChangedDialog = null;
2208
2209                       }
2210                     });
2211           }
2212         }
2213         else
2214         {
2215           Cache.log
2216                   .error("Errors reported by JABA discovery service. Check web services preferences.\n"
2217                           + ermsg);
2218         }
2219       }
2220     }
2221   }
2222
2223   private Runnable serviceChangedDialog = null;
2224
2225   /**
2226    * start a thread to open a URL in the configured browser. Pops up a warning
2227    * dialog to the user if there is an exception when calling out to the browser
2228    * to open the URL.
2229    * 
2230    * @param url
2231    */
2232   public static void showUrl(final String url)
2233   {
2234     new Thread(new Runnable()
2235     {
2236       public void run()
2237       {
2238         try
2239         {
2240           jalview.util.BrowserLauncher.openURL(url);
2241         } catch (Exception ex)
2242         {
2243           JOptionPane
2244                   .showInternalMessageDialog(
2245                           Desktop.desktop,
2246                           "Unixers: Couldn't find default web browser."
2247                                   + "\nAdd the full path to your browser in Preferences.",
2248                           "Web browser not found",
2249                           JOptionPane.WARNING_MESSAGE);
2250
2251           ex.printStackTrace();
2252         }
2253       }
2254     }).start();
2255   }
2256
2257   public static WsParamSetManager wsparamManager = null;
2258
2259   public static ParamManager getUserParameterStore()
2260   {
2261     if (wsparamManager == null)
2262     {
2263       wsparamManager = new WsParamSetManager();
2264     }
2265     return wsparamManager;
2266   }
2267
2268 }