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