2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.api.AlignViewportI;
24 import jalview.api.AlignmentViewPanel;
25 import jalview.bin.Cache;
26 import jalview.bin.Jalview;
27 import jalview.io.BackupFiles;
28 import jalview.io.DataSourceType;
29 import jalview.io.FileFormat;
30 import jalview.io.FileFormatException;
31 import jalview.io.FileFormatI;
32 import jalview.io.FileFormats;
33 import jalview.io.FileLoader;
34 import jalview.io.FormatAdapter;
35 import jalview.io.IdentifyFile;
36 import jalview.io.JalviewFileChooser;
37 import jalview.io.JalviewFileView;
38 import jalview.jbgui.GSplitFrame;
39 import jalview.jbgui.GStructureViewer;
40 import jalview.project.Jalview2XML;
41 import jalview.structure.StructureSelectionManager;
42 import jalview.urls.IdOrgSettings;
43 import jalview.util.ImageMaker;
44 import jalview.util.MessageManager;
45 import jalview.util.Platform;
46 import jalview.util.UrlConstants;
47 import jalview.viewmodel.AlignmentViewport;
48 import jalview.ws.params.ParamManager;
49 import jalview.ws.utils.UrlDownloadClient;
51 import java.awt.BorderLayout;
52 import java.awt.Color;
53 import java.awt.Dimension;
54 import java.awt.FontMetrics;
55 import java.awt.Graphics;
56 import java.awt.GridLayout;
57 import java.awt.Point;
58 import java.awt.Rectangle;
59 import java.awt.Toolkit;
60 import java.awt.Window;
61 import java.awt.datatransfer.Clipboard;
62 import java.awt.datatransfer.ClipboardOwner;
63 import java.awt.datatransfer.DataFlavor;
64 import java.awt.datatransfer.Transferable;
65 import java.awt.desktop.AboutEvent;
66 import java.awt.desktop.AboutHandler;
67 import java.awt.desktop.PreferencesEvent;
68 import java.awt.desktop.PreferencesHandler;
69 import java.awt.desktop.QuitEvent;
70 import java.awt.desktop.QuitHandler;
71 import java.awt.desktop.QuitResponse;
72 import java.awt.desktop.QuitStrategy;
73 import java.awt.dnd.DnDConstants;
74 import java.awt.dnd.DropTargetDragEvent;
75 import java.awt.dnd.DropTargetDropEvent;
76 import java.awt.dnd.DropTargetEvent;
77 import java.awt.dnd.DropTargetListener;
78 import java.awt.event.ActionEvent;
79 import java.awt.event.ActionListener;
80 import java.awt.event.InputEvent;
81 import java.awt.event.KeyEvent;
82 import java.awt.event.MouseAdapter;
83 import java.awt.event.MouseEvent;
84 import java.awt.event.WindowAdapter;
85 import java.awt.event.WindowEvent;
86 import java.beans.PropertyChangeEvent;
87 import java.beans.PropertyChangeListener;
88 import java.io.BufferedInputStream;
90 import java.io.FileOutputStream;
91 import java.io.FileWriter;
92 import java.io.IOException;
94 import java.util.ArrayList;
95 import java.util.HashMap;
96 import java.util.Hashtable;
97 import java.util.List;
98 import java.util.ListIterator;
99 import java.util.StringTokenizer;
100 import java.util.Vector;
101 import java.util.concurrent.ExecutorService;
102 import java.util.concurrent.Executors;
103 import java.util.concurrent.Semaphore;
105 import javax.swing.AbstractAction;
106 import javax.swing.Action;
107 import javax.swing.ActionMap;
108 import javax.swing.Box;
109 import javax.swing.BoxLayout;
110 import javax.swing.DefaultDesktopManager;
111 import javax.swing.DesktopManager;
112 import javax.swing.InputMap;
113 import javax.swing.JButton;
114 import javax.swing.JCheckBox;
115 import javax.swing.JComboBox;
116 import javax.swing.JComponent;
117 import javax.swing.JDesktopPane;
118 import javax.swing.JInternalFrame;
119 import javax.swing.JLabel;
120 import javax.swing.JMenuItem;
121 import javax.swing.JOptionPane;
122 import javax.swing.JPanel;
123 import javax.swing.JPopupMenu;
124 import javax.swing.JProgressBar;
125 import javax.swing.KeyStroke;
126 import javax.swing.SwingUtilities;
127 import javax.swing.event.HyperlinkEvent;
128 import javax.swing.event.HyperlinkEvent.EventType;
129 import javax.swing.event.InternalFrameAdapter;
130 import javax.swing.event.InternalFrameEvent;
131 import javax.swing.event.MenuEvent;
132 import javax.swing.event.MenuListener;
134 import org.stackoverflowusers.file.WindowsShortcut;
141 * @version $Revision: 1.155 $
143 public class Desktop extends jalview.jbgui.GDesktop
144 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
145 jalview.api.StructureSelectionManagerProvider
147 private static int DEFAULT_MIN_WIDTH = 300;
149 private static int DEFAULT_MIN_HEIGHT = 250;
151 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
153 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
155 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
157 private static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
159 public static HashMap<String, FileWriter> savingFiles = new HashMap<>();
161 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
164 * news reader - null if it was never started.
166 private BlogReader jvnews = null;
168 private File projectFile;
170 private static boolean setAPQHandlers = false;
174 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
176 public void addJalviewPropertyChangeListener(
177 PropertyChangeListener listener)
179 changeSupport.addJalviewPropertyChangeListener(listener);
183 * @param propertyName
185 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
186 * java.beans.PropertyChangeListener)
188 public void addJalviewPropertyChangeListener(String propertyName,
189 PropertyChangeListener listener)
191 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
195 * @param propertyName
197 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
198 * java.beans.PropertyChangeListener)
200 public void removeJalviewPropertyChangeListener(String propertyName,
201 PropertyChangeListener listener)
203 changeSupport.removeJalviewPropertyChangeListener(propertyName,
207 /** Singleton Desktop instance */
208 public static Desktop instance;
210 public static MyDesktopPane desktop;
212 static int openFrameCount = 0;
214 static final int xOffset = 30;
216 static final int yOffset = 30;
218 public static jalview.ws.jws1.Discoverer discoverer;
220 public static Object[] jalviewClipboard;
222 public static boolean internalCopy = false;
224 static int fileLoadingCount = 0;
226 class MyDesktopManager implements DesktopManager
229 private DesktopManager delegate;
231 public MyDesktopManager(DesktopManager delegate)
233 this.delegate = delegate;
237 public void activateFrame(JInternalFrame f)
241 delegate.activateFrame(f);
242 } catch (NullPointerException npe)
244 Point p = getMousePosition();
245 instance.showPasteMenu(p.x, p.y);
250 public void beginDraggingFrame(JComponent f)
252 delegate.beginDraggingFrame(f);
256 public void beginResizingFrame(JComponent f, int direction)
258 delegate.beginResizingFrame(f, direction);
262 public void closeFrame(JInternalFrame f)
264 delegate.closeFrame(f);
268 public void deactivateFrame(JInternalFrame f)
270 delegate.deactivateFrame(f);
274 public void deiconifyFrame(JInternalFrame f)
276 delegate.deiconifyFrame(f);
280 public void dragFrame(JComponent f, int newX, int newY)
286 delegate.dragFrame(f, newX, newY);
290 public void endDraggingFrame(JComponent f)
292 delegate.endDraggingFrame(f);
297 public void endResizingFrame(JComponent f)
299 delegate.endResizingFrame(f);
304 public void iconifyFrame(JInternalFrame f)
306 delegate.iconifyFrame(f);
310 public void maximizeFrame(JInternalFrame f)
312 delegate.maximizeFrame(f);
316 public void minimizeFrame(JInternalFrame f)
318 delegate.minimizeFrame(f);
322 public void openFrame(JInternalFrame f)
324 delegate.openFrame(f);
328 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
335 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
339 public void setBoundsForFrame(JComponent f, int newX, int newY,
340 int newWidth, int newHeight)
342 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
345 // All other methods, simply delegate
350 * Creates a new Desktop object.
355 * A note to implementors. It is ESSENTIAL that any activities that might
356 * block are spawned off as threads rather than waited for during this
360 doVamsasClientCheck();
362 doConfigureStructurePrefs();
363 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
365 if (!Platform.isAMac())
367 // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
371 this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
375 // flagging this test to avoid unnecessary reflection
378 // see if the Quit, About and Preferences handlers are available
379 Class desktopClass = java.awt.Desktop.class;
380 java.awt.Desktop hdesktop = java.awt.Desktop.getDesktop();
385 if (Platform.isAMac())
387 if (desktopClass.getDeclaredMethod("setAboutHandler",
389 { AboutHandler.class }) != null)
392 hdesktop.setAboutHandler(new AboutHandler()
395 public void handleAbout(AboutEvent e)
397 aboutMenuItem_actionPerformed(null);
403 if (desktopClass.getDeclaredMethod("setPreferencesHandler",
405 { PreferencesHandler.class }) != null)
408 hdesktop.setPreferencesHandler(new PreferencesHandler()
411 public void handlePreferences(PreferencesEvent e)
413 preferences_actionPerformed(null);
419 if (desktopClass.getDeclaredMethod("setQuitHandler",
421 { QuitHandler.class }) != null)
424 hdesktop.setQuitHandler(new QuitHandler()
427 public void handleQuitRequestWith(QuitEvent e, QuitResponse r)
429 boolean confirmQuit = jalview.bin.Cache
430 .getDefault(CONFIRM_KEYBOARD_QUIT, true);
434 n = JOptionPane.showConfirmDialog(null,
435 MessageManager.getString("label.quit_jalview"),
436 MessageManager.getString("action.quit"),
437 JOptionPane.OK_CANCEL_OPTION,
438 JOptionPane.PLAIN_MESSAGE, null);
442 n = JOptionPane.OK_OPTION;
444 if (n == JOptionPane.OK_OPTION)
446 System.out.println("Shortcut Quit confirmed by user");
448 r.performQuit(); // probably won't reach this line, but just
455 System.out.println("Shortcut Quit cancelled by user");
459 hdesktop.setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
464 } catch (NoSuchMethodException e)
467 "NoSuchMethodException when looking for About, Preferences, Quit Handlers");
471 setAPQHandlers = true;
474 addWindowListener(new WindowAdapter()
478 public void windowClosing(WindowEvent ev)
484 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
487 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
489 desktop = new MyDesktopPane(selmemusage);
490 showMemusage.setSelected(selmemusage);
491 desktop.setBackground(Color.white);
493 getContentPane().setLayout(new BorderLayout());
494 // alternate config - have scrollbars - see notes in JAL-153
495 // JScrollPane sp = new JScrollPane();
496 // sp.getViewport().setView(desktop);
497 // getContentPane().add(sp, BorderLayout.CENTER);
498 getContentPane().add(desktop, BorderLayout.CENTER);
499 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
501 // This line prevents Windows Look&Feel resizing all new windows to maximum
502 // if previous window was maximised
503 desktop.setDesktopManager(new MyDesktopManager(
504 (Platform.isWindows() ? new DefaultDesktopManager()
506 ? new AquaInternalFrameManager(
507 desktop.getDesktopManager())
508 : desktop.getDesktopManager())));
510 Rectangle dims = getLastKnownDimensions("");
517 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
518 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
521 jconsole = new Console(this, showjconsole);
522 // add essential build information
524 "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
525 + "\n" + "Jalview Installation: "
526 + jalview.bin.Cache.getDefault("INSTALLATION",
528 + "\n" + "Build Date: "
529 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
530 + "\n" + "Java version: "
531 + System.getProperty("java.version") + "\n"
532 + System.getProperty("os.arch") + " "
533 + System.getProperty("os.name") + " "
534 + System.getProperty("os.version"));
536 showConsole(showjconsole);
538 showNews.setVisible(false);
540 experimentalFeatures.setSelected(showExperimental());
542 getIdentifiersOrgData();
546 this.addWindowListener(new WindowAdapter()
549 public void windowClosing(WindowEvent evt)
556 this.addMouseListener(ma = new MouseAdapter()
559 public void mousePressed(MouseEvent evt)
561 if (evt.isPopupTrigger()) // Mac
563 showPasteMenu(evt.getX(), evt.getY());
568 public void mouseReleased(MouseEvent evt)
570 if (evt.isPopupTrigger()) // Windows
572 showPasteMenu(evt.getX(), evt.getY());
576 desktop.addMouseListener(ma);
578 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
579 // Spawn a thread that shows the splashscreen
580 SwingUtilities.invokeLater(new Runnable()
589 // Thread off a new instance of the file chooser - this reduces the time it
590 // takes to open it later on.
591 new Thread(new Runnable()
596 Cache.log.debug("Filechooser init thread started.");
597 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
598 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
600 Cache.log.debug("Filechooser init thread finished.");
603 // Add the service change listener
604 changeSupport.addJalviewPropertyChangeListener("services",
605 new PropertyChangeListener()
609 public void propertyChange(PropertyChangeEvent evt)
611 Cache.log.debug("Firing service changed event for "
612 + evt.getNewValue());
613 JalviewServicesChanged(evt);
620 * Answers true if user preferences to enable experimental features is True
625 public boolean showExperimental()
627 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
628 Boolean.FALSE.toString());
629 return Boolean.valueOf(experimental).booleanValue();
632 public void doConfigureStructurePrefs()
634 // configure services
635 StructureSelectionManager ssm = StructureSelectionManager
636 .getStructureSelectionManager(this);
637 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
639 ssm.setAddTempFacAnnot(jalview.bin.Cache
640 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
641 ssm.setProcessSecondaryStructure(jalview.bin.Cache
642 .getDefault(Preferences.STRUCT_FROM_PDB, true));
643 ssm.setSecStructServices(
644 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
648 ssm.setAddTempFacAnnot(false);
649 ssm.setProcessSecondaryStructure(false);
650 ssm.setSecStructServices(false);
654 public void checkForNews()
656 final Desktop me = this;
657 // Thread off the news reader, in case there are connection problems.
658 new Thread(new Runnable()
663 Cache.log.debug("Starting news thread.");
665 jvnews = new BlogReader(me);
666 showNews.setVisible(true);
667 Cache.log.debug("Completed news thread.");
672 public void getIdentifiersOrgData()
674 // Thread off the identifiers fetcher
675 new Thread(new Runnable()
680 Cache.log.debug("Downloading data from identifiers.org");
681 UrlDownloadClient client = new UrlDownloadClient();
684 client.download(IdOrgSettings.getUrl(),
685 IdOrgSettings.getDownloadLocation());
686 } catch (IOException e)
688 Cache.log.debug("Exception downloading identifiers.org data"
697 protected void showNews_actionPerformed(ActionEvent e)
699 showNews(showNews.isSelected());
702 void showNews(boolean visible)
705 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
706 showNews.setSelected(visible);
707 if (visible && !jvnews.isVisible())
709 new Thread(new Runnable()
714 long now = System.currentTimeMillis();
715 Desktop.instance.setProgressBar(
716 MessageManager.getString("status.refreshing_news"),
718 jvnews.refreshNews();
719 Desktop.instance.setProgressBar(null, now);
728 * recover the last known dimensions for a jalview window
731 * - empty string is desktop, all other windows have unique prefix
732 * @return null or last known dimensions scaled to current geometry (if last
733 * window geom was known)
735 Rectangle getLastKnownDimensions(String windowName)
737 // TODO: lock aspect ratio for scaling desktop Bug #0058199
738 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
739 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
740 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
741 String width = jalview.bin.Cache
742 .getProperty(windowName + "SCREEN_WIDTH");
743 String height = jalview.bin.Cache
744 .getProperty(windowName + "SCREEN_HEIGHT");
745 if ((x != null) && (y != null) && (width != null) && (height != null))
747 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
748 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
749 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
751 // attempt #1 - try to cope with change in screen geometry - this
752 // version doesn't preserve original jv aspect ratio.
753 // take ratio of current screen size vs original screen size.
754 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
755 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
756 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
757 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
758 // rescale the bounds depending upon the current screen geometry.
759 ix = (int) (ix * sw);
760 iw = (int) (iw * sw);
761 iy = (int) (iy * sh);
762 ih = (int) (ih * sh);
763 while (ix >= screenSize.width)
765 jalview.bin.Cache.log.debug(
766 "Window geometry location recall error: shifting horizontal to within screenbounds.");
767 ix -= screenSize.width;
769 while (iy >= screenSize.height)
771 jalview.bin.Cache.log.debug(
772 "Window geometry location recall error: shifting vertical to within screenbounds.");
773 iy -= screenSize.height;
775 jalview.bin.Cache.log.debug(
776 "Got last known dimensions for " + windowName + ": x:" + ix
777 + " y:" + iy + " width:" + iw + " height:" + ih);
779 // return dimensions for new instance
780 return new Rectangle(ix, iy, iw, ih);
785 private void doVamsasClientCheck()
787 if (jalview.bin.Cache.vamsasJarsPresent())
789 setupVamsasDisconnectedGui();
790 VamsasMenu.setVisible(true);
791 final Desktop us = this;
792 VamsasMenu.addMenuListener(new MenuListener()
794 // this listener remembers when the menu was first selected, and
795 // doesn't rebuild the session list until it has been cleared and
797 boolean refresh = true;
800 public void menuCanceled(MenuEvent e)
806 public void menuDeselected(MenuEvent e)
812 public void menuSelected(MenuEvent e)
816 us.buildVamsasStMenu();
821 vamsasStart.setVisible(true);
825 void showPasteMenu(int x, int y)
827 JPopupMenu popup = new JPopupMenu();
828 JMenuItem item = new JMenuItem(
829 MessageManager.getString("label.paste_new_window"));
830 item.addActionListener(new ActionListener()
833 public void actionPerformed(ActionEvent evt)
840 popup.show(this, x, y);
847 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
848 Transferable contents = c.getContents(this);
850 if (contents != null)
852 String file = (String) contents
853 .getTransferData(DataFlavor.stringFlavor);
855 FileFormatI format = new IdentifyFile().identify(file,
856 DataSourceType.PASTE);
858 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
861 } catch (Exception ex)
864 "Unable to paste alignment from system clipboard:\n" + ex);
869 * Adds and opens the given frame to the desktop
880 public static synchronized void addInternalFrame(
881 final JInternalFrame frame, String title, int w, int h)
883 addInternalFrame(frame, title, true, w, h, true, false);
887 * Add an internal frame to the Jalview desktop
894 * When true, display frame immediately, otherwise, caller must call
895 * setVisible themselves.
901 public static synchronized void addInternalFrame(
902 final JInternalFrame frame, String title, boolean makeVisible,
905 addInternalFrame(frame, title, makeVisible, w, h, true, false);
909 * Add an internal frame to the Jalview desktop and make it visible
922 public static synchronized void addInternalFrame(
923 final JInternalFrame frame, String title, int w, int h,
926 addInternalFrame(frame, title, true, w, h, resizable, false);
930 * Add an internal frame to the Jalview desktop
937 * When true, display frame immediately, otherwise, caller must call
938 * setVisible themselves.
945 * @param ignoreMinSize
946 * Do not set the default minimum size for frame
948 public static synchronized void addInternalFrame(
949 final JInternalFrame frame, String title, boolean makeVisible,
950 int w, int h, boolean resizable, boolean ignoreMinSize)
953 // TODO: allow callers to determine X and Y position of frame (eg. via
955 // TODO: consider fixing method to update entries in the window submenu with
956 // the current window title
958 frame.setTitle(title);
959 if (frame.getWidth() < 1 || frame.getHeight() < 1)
963 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
964 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
965 // IF JALVIEW IS RUNNING HEADLESS
966 // ///////////////////////////////////////////////
967 if (instance == null || (System.getProperty("java.awt.headless") != null
968 && System.getProperty("java.awt.headless").equals("true")))
977 frame.setMinimumSize(
978 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
980 // Set default dimension for Alignment Frame window.
981 // The Alignment Frame window could be added from a number of places,
983 // I did this here in order not to miss out on any Alignment frame.
984 if (frame instanceof AlignFrame)
986 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
987 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
991 frame.setVisible(makeVisible);
992 frame.setClosable(true);
993 frame.setResizable(resizable);
994 frame.setMaximizable(resizable);
995 frame.setIconifiable(resizable);
996 frame.setOpaque(false);
998 if (frame.getX() < 1 && frame.getY() < 1)
1000 frame.setLocation(xOffset * openFrameCount,
1001 yOffset * ((openFrameCount - 1) % 10) + yOffset);
1005 * add an entry for the new frame in the Window menu
1006 * (and remove it when the frame is closed)
1008 final JMenuItem menuItem = new JMenuItem(title);
1009 frame.addInternalFrameListener(new InternalFrameAdapter()
1012 public void internalFrameActivated(InternalFrameEvent evt)
1014 JInternalFrame itf = desktop.getSelectedFrame();
1017 if (itf instanceof AlignFrame)
1019 Jalview.setCurrentAlignFrame((AlignFrame) itf);
1026 public void internalFrameClosed(InternalFrameEvent evt)
1028 PaintRefresher.RemoveComponent(frame);
1031 * defensive check to prevent frames being
1032 * added half off the window
1034 if (openFrameCount > 0)
1040 * ensure no reference to alignFrame retained by menu item listener
1042 if (menuItem.getActionListeners().length > 0)
1044 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
1046 windowMenu.remove(menuItem);
1050 menuItem.addActionListener(new ActionListener()
1053 public void actionPerformed(ActionEvent e)
1057 frame.setSelected(true);
1058 frame.setIcon(false);
1059 } catch (java.beans.PropertyVetoException ex)
1066 setKeyBindings(frame);
1070 windowMenu.add(menuItem);
1075 frame.setSelected(true);
1076 frame.requestFocus();
1077 } catch (java.beans.PropertyVetoException ve)
1079 } catch (java.lang.ClassCastException cex)
1082 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
1088 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
1093 private static void setKeyBindings(JInternalFrame frame)
1095 @SuppressWarnings("serial")
1096 final Action closeAction = new AbstractAction()
1099 public void actionPerformed(ActionEvent e)
1106 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1108 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1109 InputEvent.CTRL_DOWN_MASK);
1110 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1111 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1113 InputMap inputMap = frame
1114 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1115 String ctrlW = ctrlWKey.toString();
1116 inputMap.put(ctrlWKey, ctrlW);
1117 inputMap.put(cmdWKey, ctrlW);
1119 ActionMap actionMap = frame.getActionMap();
1120 actionMap.put(ctrlW, closeAction);
1124 public void lostOwnership(Clipboard clipboard, Transferable contents)
1128 Desktop.jalviewClipboard = null;
1131 internalCopy = false;
1135 public void dragEnter(DropTargetDragEvent evt)
1140 public void dragExit(DropTargetEvent evt)
1145 public void dragOver(DropTargetDragEvent evt)
1150 public void dropActionChanged(DropTargetDragEvent evt)
1161 public void drop(DropTargetDropEvent evt)
1163 boolean success = true;
1164 // JAL-1552 - acceptDrop required before getTransferable call for
1165 // Java's Transferable for native dnd
1166 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1167 Transferable t = evt.getTransferable();
1168 List<String> files = new ArrayList<>();
1169 List<DataSourceType> protocols = new ArrayList<>();
1173 Desktop.transferFromDropTarget(files, protocols, evt, t);
1174 } catch (Exception e)
1176 e.printStackTrace();
1184 for (int i = 0; i < files.size(); i++)
1186 String file = files.get(i).toString();
1187 DataSourceType protocol = (protocols == null)
1188 ? DataSourceType.FILE
1190 FileFormatI format = null;
1192 if (file.endsWith(".jar"))
1194 format = FileFormat.Jalview;
1199 format = new IdentifyFile().identify(file, protocol);
1202 new FileLoader().LoadFile(file, protocol, format);
1205 } catch (Exception ex)
1210 evt.dropComplete(success); // need this to ensure input focus is properly
1211 // transfered to any new windows created
1221 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1223 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1224 JalviewFileChooser chooser = JalviewFileChooser
1225 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, true);
1227 chooser.setFileView(new JalviewFileView());
1228 chooser.setDialogTitle(
1229 MessageManager.getString("label.open_local_file"));
1230 chooser.setToolTipText(MessageManager.getString("action.open"));
1232 int value = chooser.showOpenDialog(this);
1234 if (value == JalviewFileChooser.APPROVE_OPTION)
1236 String choice = chooser.getSelectedFile().getPath();
1237 Cache.setProperty("LAST_DIRECTORY",
1238 chooser.getSelectedFile().getParent());
1240 FileFormatI format = chooser.getSelectedFormat();
1243 * Call IdentifyFile to verify the file contains what its extension implies.
1244 * Skip this step for dynamically added file formats, because
1245 * IdentifyFile does not know how to recognise them.
1247 if (FileFormats.getInstance().isIdentifiable(format))
1251 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1252 } catch (FileFormatException e)
1254 // format = null; //??
1258 if (viewport != null)
1260 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1265 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1277 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1279 // This construct allows us to have a wider textfield
1281 JLabel label = new JLabel(
1282 MessageManager.getString("label.input_file_url"));
1283 final JComboBox history = new JComboBox();
1285 JPanel panel = new JPanel(new GridLayout(2, 1));
1288 history.setPreferredSize(new Dimension(400, 20));
1289 history.setEditable(true);
1290 history.addItem("http://www.");
1292 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1296 if (historyItems != null)
1298 st = new StringTokenizer(historyItems, "\t");
1300 while (st.hasMoreTokens())
1302 history.addItem(st.nextElement());
1306 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1307 MessageManager.getString("label.input_alignment_from_url"),
1308 JvOptionPane.OK_CANCEL_OPTION);
1310 if (reply != JvOptionPane.OK_OPTION)
1315 String url = history.getSelectedItem().toString();
1317 if (url.toLowerCase().endsWith(".jar"))
1319 if (viewport != null)
1321 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1322 FileFormat.Jalview);
1326 new FileLoader().LoadFile(url, DataSourceType.URL,
1327 FileFormat.Jalview);
1332 FileFormatI format = null;
1335 format = new IdentifyFile().identify(url, DataSourceType.URL);
1336 } catch (FileFormatException e)
1338 // TODO revise error handling, distinguish between
1339 // URL not found and response not valid
1344 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1345 MessageManager.formatMessage("label.couldnt_locate",
1348 MessageManager.getString("label.url_not_found"),
1349 JvOptionPane.WARNING_MESSAGE);
1354 if (viewport != null)
1356 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1361 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1367 * Opens the CutAndPaste window for the user to paste an alignment in to
1370 * - if not null, the pasted alignment is added to the current
1371 * alignment; if null, to a new alignment window
1374 public void inputTextboxMenuItem_actionPerformed(
1375 AlignmentViewPanel viewPanel)
1377 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1378 cap.setForInput(viewPanel);
1379 Desktop.addInternalFrame(cap,
1380 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1390 System.out.println("********** Desktop.quit()");
1391 System.out.println(savingFiles.toString());
1392 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1393 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1395 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1396 screen.height + "");
1397 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1398 getWidth(), getHeight()));
1400 if (jconsole != null)
1402 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1403 jconsole.stopConsole();
1407 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1410 if (dialogExecutor != null)
1412 dialogExecutor.shutdownNow();
1414 closeAll_actionPerformed(null);
1416 if (groovyConsole != null)
1418 // suppress a possible repeat prompt to save script
1419 groovyConsole.setDirty(false);
1420 groovyConsole.exit();
1425 private void storeLastKnownDimensions(String string, Rectangle jc)
1427 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1428 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1429 + " height:" + jc.height);
1431 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1432 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1433 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1434 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1444 public void aboutMenuItem_actionPerformed(ActionEvent e)
1446 // StringBuffer message = getAboutMessage(false);
1447 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1449 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1450 new Thread(new Runnable()
1455 new SplashScreen(true);
1460 public StringBuffer getAboutMessage(boolean shortv)
1462 StringBuffer message = new StringBuffer();
1463 message.append("<html>");
1466 message.append("<h1><strong>Version: "
1467 + jalview.bin.Cache.getProperty("VERSION")
1468 + "</strong></h1>");
1469 message.append("<strong>Last Updated: <em>"
1470 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1471 + "</em></strong>");
1477 message.append("<strong>Version "
1478 + jalview.bin.Cache.getProperty("VERSION")
1479 + "; last updated: "
1480 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1483 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1484 .equals("Checking"))
1486 message.append("<br>...Checking latest version...</br>");
1488 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1489 .equals(jalview.bin.Cache.getProperty("VERSION")))
1491 boolean red = false;
1492 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1493 .indexOf("automated build") == -1)
1496 // Displayed when code version and jnlp version do not match and code
1497 // version is not a development build
1498 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1501 message.append("<br>!! Version "
1502 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1504 + " is available for download from "
1505 + jalview.bin.Cache.getDefault("www.jalview.org",
1506 "http://www.jalview.org")
1510 message.append("</div>");
1513 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1515 "The Jalview Authors (See AUTHORS file for current list)")
1516 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1517 + "<br><br>For help, see the FAQ at <a href=\"http://www.jalview.org/faq\">www.jalview.org/faq</a> and/or join the jalview-discuss@jalview.org mailing list"
1518 + "<br><br>If you use Jalview, please cite:"
1519 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1520 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1521 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1533 public void documentationMenuItem_actionPerformed(ActionEvent e)
1537 Help.showHelpWindow();
1538 } catch (Exception ex)
1544 public void closeAll_actionPerformed(ActionEvent e)
1546 // TODO show a progress bar while closing?
1547 JInternalFrame[] frames = desktop.getAllFrames();
1548 for (int i = 0; i < frames.length; i++)
1552 frames[i].setClosed(true);
1553 } catch (java.beans.PropertyVetoException ex)
1557 Jalview.setCurrentAlignFrame(null);
1558 System.out.println("ALL CLOSED");
1559 if (v_client != null)
1561 // TODO clear binding to vamsas document objects on close_all
1565 * reset state of singleton objects as appropriate (clear down session state
1566 * when all windows are closed)
1568 StructureSelectionManager ssm = StructureSelectionManager
1569 .getStructureSelectionManager(this);
1577 public void raiseRelated_actionPerformed(ActionEvent e)
1579 reorderAssociatedWindows(false, false);
1583 public void minimizeAssociated_actionPerformed(ActionEvent e)
1585 reorderAssociatedWindows(true, false);
1588 void closeAssociatedWindows()
1590 reorderAssociatedWindows(false, true);
1596 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1600 protected void garbageCollect_actionPerformed(ActionEvent e)
1602 // We simply collect the garbage
1603 jalview.bin.Cache.log.debug("Collecting garbage...");
1605 jalview.bin.Cache.log.debug("Finished garbage collection.");
1612 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1616 protected void showMemusage_actionPerformed(ActionEvent e)
1618 desktop.showMemoryUsage(showMemusage.isSelected());
1625 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1629 protected void showConsole_actionPerformed(ActionEvent e)
1631 showConsole(showConsole.isSelected());
1634 Console jconsole = null;
1637 * control whether the java console is visible or not
1641 void showConsole(boolean selected)
1643 showConsole.setSelected(selected);
1644 // TODO: decide if we should update properties file
1645 Cache.setProperty("SHOW_JAVA_CONSOLE",
1646 Boolean.valueOf(selected).toString());
1647 jconsole.setVisible(selected);
1650 void reorderAssociatedWindows(boolean minimize, boolean close)
1652 JInternalFrame[] frames = desktop.getAllFrames();
1653 if (frames == null || frames.length < 1)
1658 AlignmentViewport source = null, target = null;
1659 if (frames[0] instanceof AlignFrame)
1661 source = ((AlignFrame) frames[0]).getCurrentView();
1663 else if (frames[0] instanceof TreePanel)
1665 source = ((TreePanel) frames[0]).getViewPort();
1667 else if (frames[0] instanceof PCAPanel)
1669 source = ((PCAPanel) frames[0]).av;
1671 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1673 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1678 for (int i = 0; i < frames.length; i++)
1681 if (frames[i] == null)
1685 if (frames[i] instanceof AlignFrame)
1687 target = ((AlignFrame) frames[i]).getCurrentView();
1689 else if (frames[i] instanceof TreePanel)
1691 target = ((TreePanel) frames[i]).getViewPort();
1693 else if (frames[i] instanceof PCAPanel)
1695 target = ((PCAPanel) frames[i]).av;
1697 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1699 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1702 if (source == target)
1708 frames[i].setClosed(true);
1712 frames[i].setIcon(minimize);
1715 frames[i].toFront();
1719 } catch (java.beans.PropertyVetoException ex)
1734 protected void preferences_actionPerformed(ActionEvent e)
1740 * Shows a file chooser dialog and writes out the current session as a Jalview
1744 public void saveState_actionPerformed()
1746 saveState_actionPerformed(false);
1749 public void saveState_actionPerformed(boolean saveAs)
1751 java.io.File projectFile = getProjectFile();
1752 // autoSave indicates we already have a file and don't need to ask
1753 boolean autoSave = projectFile != null && !saveAs
1754 && BackupFiles.getEnabled();
1756 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1757 // saveAs="+saveAs+", Backups
1758 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1760 boolean approveSave = false;
1763 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1766 chooser.setFileView(new JalviewFileView());
1767 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1769 int value = chooser.showSaveDialog(this);
1771 if (value == JalviewFileChooser.APPROVE_OPTION)
1773 projectFile = chooser.getSelectedFile();
1774 setProjectFile(projectFile);
1779 if (approveSave || autoSave)
1781 final Desktop me = this;
1782 final java.io.File chosenFile = projectFile;
1783 new Thread(new Runnable()
1788 // TODO: refactor to Jalview desktop session controller action.
1789 setProgressBar(MessageManager.formatMessage(
1790 "label.saving_jalview_project", new Object[]
1791 { chosenFile.getName() }), chosenFile.hashCode());
1792 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1793 chosenFile.getParent());
1794 // TODO catch and handle errors for savestate
1795 // TODO prevent user from messing with the Desktop whilst we're saving
1798 BackupFiles backupfiles = new BackupFiles(chosenFile);
1800 new Jalview2XML().saveState(backupfiles.getTempFile());
1802 backupfiles.setWriteSuccess(true);
1803 backupfiles.rollBackupsAndRenameTempFile();
1804 } catch (OutOfMemoryError oom)
1806 new OOMWarning("Whilst saving current state to "
1807 + chosenFile.getName(), oom);
1808 } catch (Exception ex)
1810 Cache.log.error("Problems whilst trying to save to "
1811 + chosenFile.getName(), ex);
1812 JvOptionPane.showMessageDialog(me,
1813 MessageManager.formatMessage(
1814 "label.error_whilst_saving_current_state_to",
1816 { chosenFile.getName() }),
1817 MessageManager.getString("label.couldnt_save_project"),
1818 JvOptionPane.WARNING_MESSAGE);
1820 setProgressBar(null, chosenFile.hashCode());
1827 public void saveAsState_actionPerformed(ActionEvent e)
1829 saveState_actionPerformed(true);
1832 private void setProjectFile(File choice)
1834 this.projectFile = choice;
1837 public File getProjectFile()
1839 return this.projectFile;
1843 * Shows a file chooser dialog and tries to read in the selected file as a
1847 public void loadState_actionPerformed()
1849 final String[] suffix = new String[] { "jvp", "jar" };
1850 final String[] desc = new String[] { "Jalview Project",
1851 "Jalview Project (old)" };
1852 JalviewFileChooser chooser = new JalviewFileChooser(
1853 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1854 "Jalview Project", true, true); // last two booleans: allFiles,
1856 chooser.setFileView(new JalviewFileView());
1857 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1859 int value = chooser.showOpenDialog(this);
1861 if (value == JalviewFileChooser.APPROVE_OPTION)
1863 final File selectedFile = chooser.getSelectedFile();
1864 setProjectFile(selectedFile);
1865 final String choice = selectedFile.getAbsolutePath();
1866 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1867 new Thread(new Runnable()
1872 setProgressBar(MessageManager.formatMessage(
1873 "label.loading_jalview_project", new Object[]
1874 { choice }), choice.hashCode());
1877 new Jalview2XML().loadJalviewAlign(choice);
1878 } catch (OutOfMemoryError oom)
1880 new OOMWarning("Whilst loading project from " + choice, oom);
1881 } catch (Exception ex)
1884 "Problems whilst loading project from " + choice, ex);
1885 JvOptionPane.showMessageDialog(Desktop.desktop,
1886 MessageManager.formatMessage(
1887 "label.error_whilst_loading_project_from",
1890 MessageManager.getString("label.couldnt_load_project"),
1891 JvOptionPane.WARNING_MESSAGE);
1893 setProgressBar(null, choice.hashCode());
1900 public void inputSequence_actionPerformed(ActionEvent e)
1902 new SequenceFetcher(this);
1905 JPanel progressPanel;
1907 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1909 public void startLoading(final String fileName)
1911 if (fileLoadingCount == 0)
1913 fileLoadingPanels.add(addProgressPanel(MessageManager
1914 .formatMessage("label.loading_file", new Object[]
1920 private JPanel addProgressPanel(String string)
1922 if (progressPanel == null)
1924 progressPanel = new JPanel(new GridLayout(1, 1));
1925 totalProgressCount = 0;
1926 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1928 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1929 JProgressBar progressBar = new JProgressBar();
1930 progressBar.setIndeterminate(true);
1932 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1934 thisprogress.add(progressBar, BorderLayout.CENTER);
1935 progressPanel.add(thisprogress);
1936 ((GridLayout) progressPanel.getLayout()).setRows(
1937 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1938 ++totalProgressCount;
1939 instance.validate();
1940 return thisprogress;
1943 int totalProgressCount = 0;
1945 private void removeProgressPanel(JPanel progbar)
1947 if (progressPanel != null)
1949 synchronized (progressPanel)
1951 progressPanel.remove(progbar);
1952 GridLayout gl = (GridLayout) progressPanel.getLayout();
1953 gl.setRows(gl.getRows() - 1);
1954 if (--totalProgressCount < 1)
1956 this.getContentPane().remove(progressPanel);
1957 progressPanel = null;
1964 public void stopLoading()
1967 if (fileLoadingCount < 1)
1969 while (fileLoadingPanels.size() > 0)
1971 removeProgressPanel(fileLoadingPanels.remove(0));
1973 fileLoadingPanels.clear();
1974 fileLoadingCount = 0;
1979 public static int getViewCount(String alignmentId)
1981 AlignmentViewport[] aps = getViewports(alignmentId);
1982 return (aps == null) ? 0 : aps.length;
1987 * @param alignmentId
1988 * - if null, all sets are returned
1989 * @return all AlignmentPanels concerning the alignmentId sequence set
1991 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1993 if (Desktop.desktop == null)
1995 // no frames created and in headless mode
1996 // TODO: verify that frames are recoverable when in headless mode
1999 List<AlignmentPanel> aps = new ArrayList<>();
2000 AlignFrame[] frames = getAlignFrames();
2005 for (AlignFrame af : frames)
2007 for (AlignmentPanel ap : af.alignPanels)
2009 if (alignmentId == null
2010 || alignmentId.equals(ap.av.getSequenceSetId()))
2016 if (aps.size() == 0)
2020 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
2025 * get all the viewports on an alignment.
2027 * @param sequenceSetId
2028 * unique alignment id (may be null - all viewports returned in that
2030 * @return all viewports on the alignment bound to sequenceSetId
2032 public static AlignmentViewport[] getViewports(String sequenceSetId)
2034 List<AlignmentViewport> viewp = new ArrayList<>();
2035 if (desktop != null)
2037 AlignFrame[] frames = Desktop.getAlignFrames();
2039 for (AlignFrame afr : frames)
2041 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
2042 .equals(sequenceSetId))
2044 if (afr.alignPanels != null)
2046 for (AlignmentPanel ap : afr.alignPanels)
2048 if (sequenceSetId == null
2049 || sequenceSetId.equals(ap.av.getSequenceSetId()))
2057 viewp.add(afr.getViewport());
2061 if (viewp.size() > 0)
2063 return viewp.toArray(new AlignmentViewport[viewp.size()]);
2070 * Explode the views in the given frame into separate AlignFrame
2074 public static void explodeViews(AlignFrame af)
2076 int size = af.alignPanels.size();
2082 for (int i = 0; i < size; i++)
2084 AlignmentPanel ap = af.alignPanels.get(i);
2085 AlignFrame newaf = new AlignFrame(ap);
2088 * Restore the view's last exploded frame geometry if known. Multiple
2089 * views from one exploded frame share and restore the same (frame)
2090 * position and size.
2092 Rectangle geometry = ap.av.getExplodedGeometry();
2093 if (geometry != null)
2095 newaf.setBounds(geometry);
2098 ap.av.setGatherViewsHere(false);
2100 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2101 AlignFrame.DEFAULT_HEIGHT);
2104 af.alignPanels.clear();
2105 af.closeMenuItem_actionPerformed(true);
2110 * Gather expanded views (separate AlignFrame's) with the same sequence set
2111 * identifier back in to this frame as additional views, and close the
2112 * expanded views. Note the expanded frames may themselves have multiple
2113 * views. We take the lot.
2117 public void gatherViews(AlignFrame source)
2119 source.viewport.setGatherViewsHere(true);
2120 source.viewport.setExplodedGeometry(source.getBounds());
2121 JInternalFrame[] frames = desktop.getAllFrames();
2122 String viewId = source.viewport.getSequenceSetId();
2124 for (int t = 0; t < frames.length; t++)
2126 if (frames[t] instanceof AlignFrame && frames[t] != source)
2128 AlignFrame af = (AlignFrame) frames[t];
2129 boolean gatherThis = false;
2130 for (int a = 0; a < af.alignPanels.size(); a++)
2132 AlignmentPanel ap = af.alignPanels.get(a);
2133 if (viewId.equals(ap.av.getSequenceSetId()))
2136 ap.av.setGatherViewsHere(false);
2137 ap.av.setExplodedGeometry(af.getBounds());
2138 source.addAlignmentPanel(ap, false);
2144 af.alignPanels.clear();
2145 af.closeMenuItem_actionPerformed(true);
2152 jalview.gui.VamsasApplication v_client = null;
2155 public void vamsasImport_actionPerformed(ActionEvent e)
2157 if (v_client == null)
2159 // Load and try to start a session.
2160 JalviewFileChooser chooser = new JalviewFileChooser(
2161 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2163 chooser.setFileView(new JalviewFileView());
2164 chooser.setDialogTitle(
2165 MessageManager.getString("label.open_saved_vamsas_session"));
2166 chooser.setToolTipText(MessageManager.getString(
2167 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2169 int value = chooser.showOpenDialog(this);
2171 if (value == JalviewFileChooser.APPROVE_OPTION)
2173 String fle = chooser.getSelectedFile().toString();
2174 if (!vamsasImport(chooser.getSelectedFile()))
2176 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2177 MessageManager.formatMessage(
2178 "label.couldnt_import_as_vamsas_session",
2182 .getString("label.vamsas_document_import_failed"),
2183 JvOptionPane.ERROR_MESSAGE);
2189 jalview.bin.Cache.log.error(
2190 "Implementation error - load session from a running session is not supported.");
2195 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2198 * @return true if import was a success and a session was started.
2200 public boolean vamsasImport(URL url)
2202 // TODO: create progress bar
2203 if (v_client != null)
2206 jalview.bin.Cache.log.error(
2207 "Implementation error - load session from a running session is not supported.");
2213 // copy the URL content to a temporary local file
2214 // TODO: be a bit cleverer here with nio (?!)
2215 File file = File.createTempFile("vdocfromurl", ".vdj");
2216 FileOutputStream fos = new FileOutputStream(file);
2217 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2218 byte[] buffer = new byte[2048];
2220 while ((ln = bis.read(buffer)) > -1)
2222 fos.write(buffer, 0, ln);
2226 v_client = new jalview.gui.VamsasApplication(this, file,
2227 url.toExternalForm());
2228 } catch (Exception ex)
2230 jalview.bin.Cache.log.error(
2231 "Failed to create new vamsas session from contents of URL "
2236 setupVamsasConnectedGui();
2237 v_client.initial_update(); // TODO: thread ?
2238 return v_client.inSession();
2242 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2245 * @return true if import was a success and a session was started.
2247 public boolean vamsasImport(File file)
2249 if (v_client != null)
2252 jalview.bin.Cache.log.error(
2253 "Implementation error - load session from a running session is not supported.");
2257 setProgressBar(MessageManager.formatMessage(
2258 "status.importing_vamsas_session_from", new Object[]
2259 { file.getName() }), file.hashCode());
2262 v_client = new jalview.gui.VamsasApplication(this, file, null);
2263 } catch (Exception ex)
2265 setProgressBar(MessageManager.formatMessage(
2266 "status.importing_vamsas_session_from", new Object[]
2267 { file.getName() }), file.hashCode());
2268 jalview.bin.Cache.log.error(
2269 "New vamsas session from existing session file failed:", ex);
2272 setupVamsasConnectedGui();
2273 v_client.initial_update(); // TODO: thread ?
2274 setProgressBar(MessageManager.formatMessage(
2275 "status.importing_vamsas_session_from", new Object[]
2276 { file.getName() }), file.hashCode());
2277 return v_client.inSession();
2280 public boolean joinVamsasSession(String mysesid)
2282 if (v_client != null)
2284 throw new Error(MessageManager
2285 .getString("error.try_join_vamsas_session_another"));
2287 if (mysesid == null)
2290 MessageManager.getString("error.invalid_vamsas_session_id"));
2292 v_client = new VamsasApplication(this, mysesid);
2293 setupVamsasConnectedGui();
2294 v_client.initial_update();
2295 return (v_client.inSession());
2299 public void vamsasStart_actionPerformed(ActionEvent e)
2301 if (v_client == null)
2304 // we just start a default session for moment.
2306 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2307 * getProperty("LAST_DIRECTORY"));
2309 * chooser.setFileView(new JalviewFileView());
2310 * chooser.setDialogTitle("Load Vamsas file");
2311 * chooser.setToolTipText("Import");
2313 * int value = chooser.showOpenDialog(this);
2315 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2316 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2318 v_client = new VamsasApplication(this);
2319 setupVamsasConnectedGui();
2320 v_client.initial_update(); // TODO: thread ?
2324 // store current data in session.
2325 v_client.push_update(); // TODO: thread
2329 protected void setupVamsasConnectedGui()
2331 vamsasStart.setText(MessageManager.getString("label.session_update"));
2332 vamsasSave.setVisible(true);
2333 vamsasStop.setVisible(true);
2334 vamsasImport.setVisible(false); // Document import to existing session is
2335 // not possible for vamsas-client-1.0.
2338 protected void setupVamsasDisconnectedGui()
2340 vamsasSave.setVisible(false);
2341 vamsasStop.setVisible(false);
2342 vamsasImport.setVisible(true);
2344 .setText(MessageManager.getString("label.new_vamsas_session"));
2348 public void vamsasStop_actionPerformed(ActionEvent e)
2350 if (v_client != null)
2352 v_client.end_session();
2354 setupVamsasDisconnectedGui();
2358 protected void buildVamsasStMenu()
2360 if (v_client == null)
2362 String[] sess = null;
2365 sess = VamsasApplication.getSessionList();
2366 } catch (Exception e)
2368 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2374 jalview.bin.Cache.log.debug(
2375 "Got current sessions list: " + sess.length + " entries.");
2376 VamsasStMenu.removeAll();
2377 for (int i = 0; i < sess.length; i++)
2379 JMenuItem sessit = new JMenuItem();
2380 sessit.setText(sess[i]);
2381 sessit.setToolTipText(MessageManager
2382 .formatMessage("label.connect_to_session", new Object[]
2384 final Desktop dsktp = this;
2385 final String mysesid = sess[i];
2386 sessit.addActionListener(new ActionListener()
2390 public void actionPerformed(ActionEvent e)
2392 if (dsktp.v_client == null)
2394 Thread rthr = new Thread(new Runnable()
2400 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2401 dsktp.setupVamsasConnectedGui();
2402 dsktp.v_client.initial_update();
2410 VamsasStMenu.add(sessit);
2412 // don't show an empty menu.
2413 VamsasStMenu.setVisible(sess.length > 0);
2418 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2419 VamsasStMenu.removeAll();
2420 VamsasStMenu.setVisible(false);
2425 // Not interested in the content. Just hide ourselves.
2426 VamsasStMenu.setVisible(false);
2431 public void vamsasSave_actionPerformed(ActionEvent e)
2433 if (v_client != null)
2435 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2436 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2439 chooser.setFileView(new JalviewFileView());
2440 chooser.setDialogTitle(MessageManager
2441 .getString("label.save_vamsas_document_archive"));
2443 int value = chooser.showSaveDialog(this);
2445 if (value == JalviewFileChooser.APPROVE_OPTION)
2447 java.io.File choice = chooser.getSelectedFile();
2448 JPanel progpanel = addProgressPanel(MessageManager
2449 .formatMessage("label.saving_vamsas_doc", new Object[]
2450 { choice.getName() }));
2451 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2452 String warnmsg = null;
2453 String warnttl = null;
2456 v_client.vclient.storeDocument(choice);
2459 warnttl = "Serious Problem saving Vamsas Document";
2460 warnmsg = ex.toString();
2461 jalview.bin.Cache.log
2462 .error("Error Whilst saving document to " + choice, ex);
2464 } catch (Exception ex)
2466 warnttl = "Problem saving Vamsas Document.";
2467 warnmsg = ex.toString();
2468 jalview.bin.Cache.log.warn(
2469 "Exception Whilst saving document to " + choice, ex);
2472 removeProgressPanel(progpanel);
2473 if (warnmsg != null)
2475 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2477 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2483 JPanel vamUpdate = null;
2486 * hide vamsas user gui bits when a vamsas document event is being handled.
2489 * true to hide gui, false to reveal gui
2491 public void setVamsasUpdate(boolean b)
2493 Cache.log.debug("Setting gui for Vamsas update "
2494 + (b ? "in progress" : "finished"));
2496 if (vamUpdate != null)
2498 this.removeProgressPanel(vamUpdate);
2502 vamUpdate = this.addProgressPanel(
2503 MessageManager.getString("label.updating_vamsas_session"));
2505 vamsasStart.setVisible(!b);
2506 vamsasStop.setVisible(!b);
2507 vamsasSave.setVisible(!b);
2510 public JInternalFrame[] getAllFrames()
2512 return desktop.getAllFrames();
2516 * Checks the given url to see if it gives a response indicating that the user
2517 * should be informed of a new questionnaire.
2521 public void checkForQuestionnaire(String url)
2523 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2524 // javax.swing.SwingUtilities.invokeLater(jvq);
2525 new Thread(jvq).start();
2528 public void checkURLLinks()
2530 // Thread off the URL link checker
2531 addDialogThread(new Runnable()
2536 if (Cache.getDefault("CHECKURLLINKS", true))
2538 // check what the actual links are - if it's just the default don't
2539 // bother with the warning
2540 List<String> links = Preferences.sequenceUrlLinks
2543 // only need to check links if there is one with a
2544 // SEQUENCE_ID which is not the default EMBL_EBI link
2545 ListIterator<String> li = links.listIterator();
2546 boolean check = false;
2547 List<JLabel> urls = new ArrayList<>();
2548 while (li.hasNext())
2550 String link = li.next();
2551 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2552 && !UrlConstants.isDefaultString(link))
2555 int barPos = link.indexOf("|");
2556 String urlMsg = barPos == -1 ? link
2557 : link.substring(0, barPos) + ": "
2558 + link.substring(barPos + 1);
2559 urls.add(new JLabel(urlMsg));
2567 // ask user to check in case URL links use old style tokens
2568 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2569 JPanel msgPanel = new JPanel();
2570 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2571 msgPanel.add(Box.createVerticalGlue());
2572 JLabel msg = new JLabel(MessageManager
2573 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2574 JLabel msg2 = new JLabel(MessageManager
2575 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2577 for (JLabel url : urls)
2583 final JCheckBox jcb = new JCheckBox(
2584 MessageManager.getString("label.do_not_display_again"));
2585 jcb.addActionListener(new ActionListener()
2588 public void actionPerformed(ActionEvent e)
2590 // update Cache settings for "don't show this again"
2591 boolean showWarningAgain = !jcb.isSelected();
2592 Cache.setProperty("CHECKURLLINKS",
2593 Boolean.valueOf(showWarningAgain).toString());
2598 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2600 .getString("label.SEQUENCE_ID_no_longer_used"),
2601 JvOptionPane.WARNING_MESSAGE);
2608 * Proxy class for JDesktopPane which optionally displays the current memory
2609 * usage and highlights the desktop area with a red bar if free memory runs
2614 public class MyDesktopPane extends JDesktopPane implements Runnable
2617 private static final float ONE_MB = 1048576f;
2619 boolean showMemoryUsage = false;
2623 java.text.NumberFormat df;
2625 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2628 public MyDesktopPane(boolean showMemoryUsage)
2630 showMemoryUsage(showMemoryUsage);
2633 public void showMemoryUsage(boolean showMemory)
2635 this.showMemoryUsage = showMemory;
2638 Thread worker = new Thread(this);
2644 public boolean isShowMemoryUsage()
2646 return showMemoryUsage;
2652 df = java.text.NumberFormat.getNumberInstance();
2653 df.setMaximumFractionDigits(2);
2654 runtime = Runtime.getRuntime();
2656 while (showMemoryUsage)
2660 maxMemory = runtime.maxMemory() / ONE_MB;
2661 allocatedMemory = runtime.totalMemory() / ONE_MB;
2662 freeMemory = runtime.freeMemory() / ONE_MB;
2663 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2665 percentUsage = (totalFreeMemory / maxMemory) * 100;
2667 // if (percentUsage < 20)
2669 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2671 // instance.set.setBorder(border1);
2674 // sleep after showing usage
2676 } catch (Exception ex)
2678 ex.printStackTrace();
2684 public void paintComponent(Graphics g)
2686 if (showMemoryUsage && g != null && df != null)
2688 if (percentUsage < 20)
2690 g.setColor(Color.red);
2692 FontMetrics fm = g.getFontMetrics();
2695 g.drawString(MessageManager.formatMessage("label.memory_stats",
2697 { df.format(totalFreeMemory), df.format(maxMemory),
2698 df.format(percentUsage) }),
2699 10, getHeight() - fm.getHeight());
2706 * Accessor method to quickly get all the AlignmentFrames loaded.
2708 * @return an array of AlignFrame, or null if none found
2710 public static AlignFrame[] getAlignFrames()
2712 if (Jalview.isHeadlessMode())
2714 // Desktop.desktop is null in headless mode
2715 return new AlignFrame[] { Jalview.currentAlignFrame };
2718 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2724 List<AlignFrame> avp = new ArrayList<>();
2726 for (int i = frames.length - 1; i > -1; i--)
2728 if (frames[i] instanceof AlignFrame)
2730 avp.add((AlignFrame) frames[i]);
2732 else if (frames[i] instanceof SplitFrame)
2735 * Also check for a split frame containing an AlignFrame
2737 GSplitFrame sf = (GSplitFrame) frames[i];
2738 if (sf.getTopFrame() instanceof AlignFrame)
2740 avp.add((AlignFrame) sf.getTopFrame());
2742 if (sf.getBottomFrame() instanceof AlignFrame)
2744 avp.add((AlignFrame) sf.getBottomFrame());
2748 if (avp.size() == 0)
2752 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2757 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2761 public GStructureViewer[] getJmols()
2763 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2769 List<GStructureViewer> avp = new ArrayList<>();
2771 for (int i = frames.length - 1; i > -1; i--)
2773 if (frames[i] instanceof AppJmol)
2775 GStructureViewer af = (GStructureViewer) frames[i];
2779 if (avp.size() == 0)
2783 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2788 * Add Groovy Support to Jalview
2791 public void groovyShell_actionPerformed()
2795 openGroovyConsole();
2796 } catch (Exception ex)
2798 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2799 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2801 MessageManager.getString("label.couldnt_create_groovy_shell"),
2802 MessageManager.getString("label.groovy_support_failed"),
2803 JvOptionPane.ERROR_MESSAGE);
2808 * Open the Groovy console
2810 void openGroovyConsole()
2812 if (groovyConsole == null)
2814 groovyConsole = new groovy.ui.Console();
2815 groovyConsole.setVariable("Jalview", this);
2816 groovyConsole.run();
2819 * We allow only one console at a time, so that AlignFrame menu option
2820 * 'Calculate | Run Groovy script' is unambiguous.
2821 * Disable 'Groovy Console', and enable 'Run script', when the console is
2822 * opened, and the reverse when it is closed
2824 Window window = (Window) groovyConsole.getFrame();
2825 window.addWindowListener(new WindowAdapter()
2828 public void windowClosed(WindowEvent e)
2831 * rebind CMD-Q from Groovy Console to Jalview Quit
2834 enableExecuteGroovy(false);
2840 * show Groovy console window (after close and reopen)
2842 ((Window) groovyConsole.getFrame()).setVisible(true);
2845 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2846 * and disable opening a second console
2848 enableExecuteGroovy(true);
2852 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2853 * binding when opened
2855 protected void addQuitHandler()
2857 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2858 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2859 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2861 getRootPane().getActionMap().put("Quit", new AbstractAction()
2864 public void actionPerformed(ActionEvent e)
2872 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2875 * true if Groovy console is open
2877 public void enableExecuteGroovy(boolean enabled)
2880 * disable opening a second Groovy console
2881 * (or re-enable when the console is closed)
2883 groovyShell.setEnabled(!enabled);
2885 AlignFrame[] alignFrames = getAlignFrames();
2886 if (alignFrames != null)
2888 for (AlignFrame af : alignFrames)
2890 af.setGroovyEnabled(enabled);
2896 * Progress bars managed by the IProgressIndicator method.
2898 private Hashtable<Long, JPanel> progressBars;
2900 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2905 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2908 public void setProgressBar(String message, long id)
2910 if (progressBars == null)
2912 progressBars = new Hashtable<>();
2913 progressBarHandlers = new Hashtable<>();
2916 if (progressBars.get(new Long(id)) != null)
2918 JPanel panel = progressBars.remove(new Long(id));
2919 if (progressBarHandlers.contains(new Long(id)))
2921 progressBarHandlers.remove(new Long(id));
2923 removeProgressPanel(panel);
2927 progressBars.put(new Long(id), addProgressPanel(message));
2934 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2935 * jalview.gui.IProgressIndicatorHandler)
2938 public void registerHandler(final long id,
2939 final IProgressIndicatorHandler handler)
2941 if (progressBarHandlers == null
2942 || !progressBars.containsKey(new Long(id)))
2944 throw new Error(MessageManager.getString(
2945 "error.call_setprogressbar_before_registering_handler"));
2947 progressBarHandlers.put(new Long(id), handler);
2948 final JPanel progressPanel = progressBars.get(new Long(id));
2949 if (handler.canCancel())
2951 JButton cancel = new JButton(
2952 MessageManager.getString("action.cancel"));
2953 final IProgressIndicator us = this;
2954 cancel.addActionListener(new ActionListener()
2958 public void actionPerformed(ActionEvent e)
2960 handler.cancelActivity(id);
2961 us.setProgressBar(MessageManager
2962 .formatMessage("label.cancelled_params", new Object[]
2963 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2967 progressPanel.add(cancel, BorderLayout.EAST);
2973 * @return true if any progress bars are still active
2976 public boolean operationInProgress()
2978 if (progressBars != null && progressBars.size() > 0)
2986 * This will return the first AlignFrame holding the given viewport instance.
2987 * It will break if there are more than one AlignFrames viewing a particular
2991 * @return alignFrame for viewport
2993 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2995 if (desktop != null)
2997 AlignmentPanel[] aps = getAlignmentPanels(
2998 viewport.getSequenceSetId());
2999 for (int panel = 0; aps != null && panel < aps.length; panel++)
3001 if (aps[panel] != null && aps[panel].av == viewport)
3003 return aps[panel].alignFrame;
3010 public VamsasApplication getVamsasApplication()
3017 * flag set if jalview GUI is being operated programmatically
3019 private boolean inBatchMode = false;
3022 * check if jalview GUI is being operated programmatically
3024 * @return inBatchMode
3026 public boolean isInBatchMode()
3032 * set flag if jalview GUI is being operated programmatically
3034 * @param inBatchMode
3036 public void setInBatchMode(boolean inBatchMode)
3038 this.inBatchMode = inBatchMode;
3041 public void startServiceDiscovery()
3043 startServiceDiscovery(false);
3046 public void startServiceDiscovery(boolean blocking)
3048 boolean alive = true;
3049 Thread t0 = null, t1 = null, t2 = null;
3050 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3053 // todo: changesupport handlers need to be transferred
3054 if (discoverer == null)
3056 discoverer = new jalview.ws.jws1.Discoverer();
3057 // register PCS handler for desktop.
3058 discoverer.addPropertyChangeListener(changeSupport);
3060 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3061 // until we phase out completely
3062 (t0 = new Thread(discoverer)).start();
3065 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3067 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3068 .startDiscoverer(changeSupport);
3072 // TODO: do rest service discovery
3081 } catch (Exception e)
3084 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3085 || (t3 != null && t3.isAlive())
3086 || (t0 != null && t0.isAlive());
3092 * called to check if the service discovery process completed successfully.
3096 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3098 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3100 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3101 .getErrorMessages();
3104 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3106 if (serviceChangedDialog == null)
3108 // only run if we aren't already displaying one of these.
3109 addDialogThread(serviceChangedDialog = new Runnable()
3116 * JalviewDialog jd =new JalviewDialog() {
3118 * @Override protected void cancelPressed() { // TODO
3119 * Auto-generated method stub
3121 * }@Override protected void okPressed() { // TODO
3122 * Auto-generated method stub
3124 * }@Override protected void raiseClosed() { // TODO
3125 * Auto-generated method stub
3127 * } }; jd.initDialogFrame(new
3128 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3129 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3130 * + " or mis-configured HTTP proxy settings.<br/>" +
3131 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3133 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3134 * ), true, true, "Web Service Configuration Problem", 450,
3137 * jd.waitForInput();
3139 JvOptionPane.showConfirmDialog(Desktop.desktop,
3140 new JLabel("<html><table width=\"450\"><tr><td>"
3141 + ermsg + "</td></tr></table>"
3142 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3143 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3144 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3145 + " Tools->Preferences dialog box to change them.</p></html>"),
3146 "Web Service Configuration Problem",
3147 JvOptionPane.DEFAULT_OPTION,
3148 JvOptionPane.ERROR_MESSAGE);
3149 serviceChangedDialog = null;
3158 "Errors reported by JABA discovery service. Check web services preferences.\n"
3165 private Runnable serviceChangedDialog = null;
3168 * start a thread to open a URL in the configured browser. Pops up a warning
3169 * dialog to the user if there is an exception when calling out to the browser
3174 public static void showUrl(final String url)
3176 showUrl(url, Desktop.instance);
3180 * Like showUrl but allows progress handler to be specified
3184 * (null) or object implementing IProgressIndicator
3186 public static void showUrl(final String url,
3187 final IProgressIndicator progress)
3189 new Thread(new Runnable()
3196 if (progress != null)
3198 progress.setProgressBar(MessageManager
3199 .formatMessage("status.opening_params", new Object[]
3200 { url }), this.hashCode());
3202 jalview.util.BrowserLauncher.openURL(url);
3203 } catch (Exception ex)
3205 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3207 .getString("label.web_browser_not_found_unix"),
3208 MessageManager.getString("label.web_browser_not_found"),
3209 JvOptionPane.WARNING_MESSAGE);
3211 ex.printStackTrace();
3213 if (progress != null)
3215 progress.setProgressBar(null, this.hashCode());
3221 public static WsParamSetManager wsparamManager = null;
3223 public static ParamManager getUserParameterStore()
3225 if (wsparamManager == null)
3227 wsparamManager = new WsParamSetManager();
3229 return wsparamManager;
3233 * static hyperlink handler proxy method for use by Jalview's internal windows
3237 public static void hyperlinkUpdate(HyperlinkEvent e)
3239 if (e.getEventType() == EventType.ACTIVATED)
3244 url = e.getURL().toString();
3245 Desktop.showUrl(url);
3246 } catch (Exception x)
3250 if (Cache.log != null)
3252 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3257 "Couldn't handle string " + url + " as a URL.");
3260 // ignore any exceptions due to dud links.
3267 * single thread that handles display of dialogs to user.
3269 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3272 * flag indicating if dialogExecutor should try to acquire a permit
3274 private volatile boolean dialogPause = true;
3279 private java.util.concurrent.Semaphore block = new Semaphore(0);
3281 private static groovy.ui.Console groovyConsole;
3284 * add another dialog thread to the queue
3288 public void addDialogThread(final Runnable prompter)
3290 dialogExecutor.submit(new Runnable()
3300 } catch (InterruptedException x)
3305 if (instance == null)
3311 SwingUtilities.invokeAndWait(prompter);
3312 } catch (Exception q)
3314 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3320 public void startDialogQueue()
3322 // set the flag so we don't pause waiting for another permit and semaphore
3323 // the current task to begin
3324 dialogPause = false;
3329 protected void snapShotWindow_actionPerformed(ActionEvent e)
3333 ImageMaker im = new jalview.util.ImageMaker(
3334 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3335 getHeight(), of = new File("Jalview_snapshot"
3336 + System.currentTimeMillis() + ".eps"),
3337 "View of desktop", null, 0, false);
3340 paintAll(im.getGraphics());
3342 } catch (Exception q)
3344 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3348 Cache.log.info("Successfully written snapshot to file "
3349 + of.getAbsolutePath());
3353 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3354 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3355 * and location last time the view was expanded (if any). However it does not
3356 * remember the split pane divider location - this is set to match the
3357 * 'exploding' frame.
3361 public void explodeViews(SplitFrame sf)
3363 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3364 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3365 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3367 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3369 int viewCount = topPanels.size();
3376 * Processing in reverse order works, forwards order leaves the first panels
3377 * not visible. I don't know why!
3379 for (int i = viewCount - 1; i >= 0; i--)
3382 * Make new top and bottom frames. These take over the respective
3383 * AlignmentPanel objects, including their AlignmentViewports, so the
3384 * cdna/protein relationships between the viewports is carried over to the
3387 * explodedGeometry holds the (x, y) position of the previously exploded
3388 * SplitFrame, and the (width, height) of the AlignFrame component
3390 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3391 AlignFrame newTopFrame = new AlignFrame(topPanel);
3392 newTopFrame.setSize(oldTopFrame.getSize());
3393 newTopFrame.setVisible(true);
3394 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3395 .getExplodedGeometry();
3396 if (geometry != null)
3398 newTopFrame.setSize(geometry.getSize());
3401 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3402 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3403 newBottomFrame.setSize(oldBottomFrame.getSize());
3404 newBottomFrame.setVisible(true);
3405 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3406 .getExplodedGeometry();
3407 if (geometry != null)
3409 newBottomFrame.setSize(geometry.getSize());
3412 topPanel.av.setGatherViewsHere(false);
3413 bottomPanel.av.setGatherViewsHere(false);
3414 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3416 if (geometry != null)
3418 splitFrame.setLocation(geometry.getLocation());
3420 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3424 * Clear references to the panels (now relocated in the new SplitFrames)
3425 * before closing the old SplitFrame.
3428 bottomPanels.clear();
3433 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3434 * back into the given SplitFrame as additional views. Note that the gathered
3435 * frames may themselves have multiple views.
3439 public void gatherViews(GSplitFrame source)
3442 * special handling of explodedGeometry for a view within a SplitFrame: - it
3443 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3444 * height) of the AlignFrame component
3446 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3447 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3448 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3449 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3450 myBottomFrame.viewport
3451 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3452 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3453 myTopFrame.viewport.setGatherViewsHere(true);
3454 myBottomFrame.viewport.setGatherViewsHere(true);
3455 String topViewId = myTopFrame.viewport.getSequenceSetId();
3456 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3458 JInternalFrame[] frames = desktop.getAllFrames();
3459 for (JInternalFrame frame : frames)
3461 if (frame instanceof SplitFrame && frame != source)
3463 SplitFrame sf = (SplitFrame) frame;
3464 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3465 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3466 boolean gatherThis = false;
3467 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3469 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3470 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3471 if (topViewId.equals(topPanel.av.getSequenceSetId())
3472 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3475 topPanel.av.setGatherViewsHere(false);
3476 bottomPanel.av.setGatherViewsHere(false);
3477 topPanel.av.setExplodedGeometry(
3478 new Rectangle(sf.getLocation(), topFrame.getSize()));
3479 bottomPanel.av.setExplodedGeometry(
3480 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3481 myTopFrame.addAlignmentPanel(topPanel, false);
3482 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3488 topFrame.getAlignPanels().clear();
3489 bottomFrame.getAlignPanels().clear();
3496 * The dust settles...give focus to the tab we did this from.
3498 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3501 public static groovy.ui.Console getGroovyConsole()
3503 return groovyConsole;
3507 * handles the payload of a drag and drop event.
3509 * TODO refactor to desktop utilities class
3512 * - Data source strings extracted from the drop event
3514 * - protocol for each data source extracted from the drop event
3518 * - the payload from the drop event
3521 public static void transferFromDropTarget(List<String> files,
3522 List<DataSourceType> protocols, DropTargetDropEvent evt,
3523 Transferable t) throws Exception
3526 DataFlavor uriListFlavor = new DataFlavor(
3527 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3530 urlFlavour = new DataFlavor(
3531 "application/x-java-url; class=java.net.URL");
3532 } catch (ClassNotFoundException cfe)
3534 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3537 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3542 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3543 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3544 // means url may be null.
3547 protocols.add(DataSourceType.URL);
3548 files.add(url.toString());
3549 Cache.log.debug("Drop handled as URL dataflavor "
3550 + files.get(files.size() - 1));
3555 if (Platform.isAMac())
3558 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3562 } catch (Throwable ex)
3564 Cache.log.debug("URL drop handler failed.", ex);
3567 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3569 // Works on Windows and MacOSX
3570 Cache.log.debug("Drop handled as javaFileListFlavor");
3571 for (Object file : (List) t
3572 .getTransferData(DataFlavor.javaFileListFlavor))
3574 files.add(((File) file).toString());
3575 protocols.add(DataSourceType.FILE);
3580 // Unix like behaviour
3581 boolean added = false;
3583 if (t.isDataFlavorSupported(uriListFlavor))
3585 Cache.log.debug("Drop handled as uriListFlavor");
3586 // This is used by Unix drag system
3587 data = (String) t.getTransferData(uriListFlavor);
3591 // fallback to text: workaround - on OSX where there's a JVM bug
3592 Cache.log.debug("standard URIListFlavor failed. Trying text");
3593 // try text fallback
3594 DataFlavor textDf = new DataFlavor(
3595 "text/plain;class=java.lang.String");
3596 if (t.isDataFlavorSupported(textDf))
3598 data = (String) t.getTransferData(textDf);
3601 Cache.log.debug("Plain text drop content returned "
3602 + (data == null ? "Null - failed" : data));
3607 while (protocols.size() < files.size())
3609 Cache.log.debug("Adding missing FILE protocol for "
3610 + files.get(protocols.size()));
3611 protocols.add(DataSourceType.FILE);
3613 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3614 data, "\r\n"); st.hasMoreTokens();)
3617 String s = st.nextToken();
3618 if (s.startsWith("#"))
3620 // the line is a comment (as per the RFC 2483)
3623 java.net.URI uri = new java.net.URI(s);
3624 if (uri.getScheme().toLowerCase().startsWith("http"))
3626 protocols.add(DataSourceType.URL);
3627 files.add(uri.toString());
3631 // otherwise preserve old behaviour: catch all for file objects
3632 java.io.File file = new java.io.File(uri);
3633 protocols.add(DataSourceType.FILE);
3634 files.add(file.toString());
3639 if (Cache.log.isDebugEnabled())
3641 if (data == null || !added)
3644 if (t.getTransferDataFlavors() != null
3645 && t.getTransferDataFlavors().length > 0)
3648 "Couldn't resolve drop data. Here are the supported flavors:");
3649 for (DataFlavor fl : t.getTransferDataFlavors())
3652 "Supported transfer dataflavor: " + fl.toString());
3653 Object df = t.getTransferData(fl);
3656 Cache.log.debug("Retrieves: " + df);
3660 Cache.log.debug("Retrieved nothing");
3666 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3672 if (Platform.isWindows())
3675 Cache.log.debug("Scanning dropped content for Windows Link Files");
3677 // resolve any .lnk files in the file drop
3678 for (int f = 0; f < files.size(); f++)
3680 String source = files.get(f).toLowerCase();
3681 if (protocols.get(f).equals(DataSourceType.FILE)
3682 && (source.endsWith(".lnk") || source.endsWith(".url")
3683 || source.endsWith(".site")))
3687 File lf = new File(files.get(f));
3688 // process link file to get a URL
3689 Cache.log.debug("Found potential link file: " + lf);
3690 WindowsShortcut wscfile = new WindowsShortcut(lf);
3691 String fullname = wscfile.getRealFilename();
3692 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3693 files.set(f, fullname);
3694 Cache.log.debug("Parsed real filename " + fullname
3695 + " to extract protocol: " + protocols.get(f));
3696 } catch (Exception ex)
3699 "Couldn't parse " + files.get(f) + " as a link file.",
3708 * Sets the Preferences property for experimental features to True or False
3709 * depending on the state of the controlling menu item
3712 protected void showExperimental_actionPerformed(boolean selected)
3714 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3718 * Answers a (possibly empty) list of any structure viewer frames (currently
3719 * for either Jmol or Chimera) which are currently open. This may optionally
3720 * be restricted to viewers of a specified class, or viewers linked to a
3721 * specified alignment panel.
3724 * if not null, only return viewers linked to this panel
3725 * @param structureViewerClass
3726 * if not null, only return viewers of this class
3729 public List<StructureViewerBase> getStructureViewers(
3730 AlignmentPanel apanel,
3731 Class<? extends StructureViewerBase> structureViewerClass)
3733 List<StructureViewerBase> result = new ArrayList<>();
3734 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3736 for (JInternalFrame frame : frames)
3738 if (frame instanceof StructureViewerBase)
3740 if (structureViewerClass == null
3741 || structureViewerClass.isInstance(frame))
3744 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3746 result.add((StructureViewerBase) frame);