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.QuitStrategy;
66 /* not importing directly. Calling classes with full name in try block to allow Java 1.8 runtime
67 import java.awt.desktop.AboutHandler;
68 import java.awt.desktop.PreferencesEvent;
69 import java.awt.desktop.PreferencesHandler;
70 import java.awt.desktop.QuitEvent;
71 import java.awt.desktop.QuitHandler;
72 import java.awt.desktop.QuitResponse;
73 import java.awt.desktop.QuitStrategy;
75 import java.awt.dnd.DnDConstants;
76 import java.awt.dnd.DropTargetDragEvent;
77 import java.awt.dnd.DropTargetDropEvent;
78 import java.awt.dnd.DropTargetEvent;
79 import java.awt.dnd.DropTargetListener;
80 import java.awt.event.ActionEvent;
81 import java.awt.event.ActionListener;
82 import java.awt.event.InputEvent;
83 import java.awt.event.KeyEvent;
84 import java.awt.event.MouseAdapter;
85 import java.awt.event.MouseEvent;
86 import java.awt.event.WindowAdapter;
87 import java.awt.event.WindowEvent;
88 import java.beans.PropertyChangeEvent;
89 import java.beans.PropertyChangeListener;
90 import java.io.BufferedInputStream;
92 import java.io.FileOutputStream;
93 import java.io.FileWriter;
94 import java.io.IOException;
96 import java.util.ArrayList;
97 import java.util.HashMap;
98 import java.util.Hashtable;
99 import java.util.List;
100 import java.util.ListIterator;
101 import java.util.StringTokenizer;
102 import java.util.Vector;
103 import java.util.concurrent.ExecutorService;
104 import java.util.concurrent.Executors;
105 import java.util.concurrent.Semaphore;
107 import javax.swing.AbstractAction;
108 import javax.swing.Action;
109 import javax.swing.ActionMap;
110 import javax.swing.Box;
111 import javax.swing.BoxLayout;
112 import javax.swing.DefaultDesktopManager;
113 import javax.swing.DesktopManager;
114 import javax.swing.InputMap;
115 import javax.swing.JButton;
116 import javax.swing.JCheckBox;
117 import javax.swing.JComboBox;
118 import javax.swing.JComponent;
119 import javax.swing.JDesktopPane;
120 import javax.swing.JInternalFrame;
121 import javax.swing.JLabel;
122 import javax.swing.JMenuItem;
123 import javax.swing.JOptionPane;
124 import javax.swing.JPanel;
125 import javax.swing.JPopupMenu;
126 import javax.swing.JProgressBar;
127 import javax.swing.KeyStroke;
128 import javax.swing.SwingUtilities;
129 import javax.swing.event.HyperlinkEvent;
130 import javax.swing.event.HyperlinkEvent.EventType;
131 import javax.swing.event.InternalFrameAdapter;
132 import javax.swing.event.InternalFrameEvent;
133 import javax.swing.event.MenuEvent;
134 import javax.swing.event.MenuListener;
136 import org.stackoverflowusers.file.WindowsShortcut;
143 * @version $Revision: 1.155 $
145 public class Desktop extends jalview.jbgui.GDesktop
146 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
147 jalview.api.StructureSelectionManagerProvider
149 private static int DEFAULT_MIN_WIDTH = 300;
151 private static int DEFAULT_MIN_HEIGHT = 250;
153 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
155 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
157 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
159 private static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
161 public static HashMap<String, FileWriter> savingFiles = new HashMap<>();
163 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
166 * news reader - null if it was never started.
168 private BlogReader jvnews = null;
170 private File projectFile;
172 private static boolean setAPQHandlers = false;
176 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
178 public void addJalviewPropertyChangeListener(
179 PropertyChangeListener listener)
181 changeSupport.addJalviewPropertyChangeListener(listener);
185 * @param propertyName
187 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
188 * java.beans.PropertyChangeListener)
190 public void addJalviewPropertyChangeListener(String propertyName,
191 PropertyChangeListener listener)
193 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
197 * @param propertyName
199 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
200 * java.beans.PropertyChangeListener)
202 public void removeJalviewPropertyChangeListener(String propertyName,
203 PropertyChangeListener listener)
205 changeSupport.removeJalviewPropertyChangeListener(propertyName,
209 /** Singleton Desktop instance */
210 public static Desktop instance;
212 public static MyDesktopPane desktop;
214 static int openFrameCount = 0;
216 static final int xOffset = 30;
218 static final int yOffset = 30;
220 public static jalview.ws.jws1.Discoverer discoverer;
222 public static Object[] jalviewClipboard;
224 public static boolean internalCopy = false;
226 static int fileLoadingCount = 0;
228 class MyDesktopManager implements DesktopManager
231 private DesktopManager delegate;
233 public MyDesktopManager(DesktopManager delegate)
235 this.delegate = delegate;
239 public void activateFrame(JInternalFrame f)
243 delegate.activateFrame(f);
244 } catch (NullPointerException npe)
246 Point p = getMousePosition();
247 instance.showPasteMenu(p.x, p.y);
252 public void beginDraggingFrame(JComponent f)
254 delegate.beginDraggingFrame(f);
258 public void beginResizingFrame(JComponent f, int direction)
260 delegate.beginResizingFrame(f, direction);
264 public void closeFrame(JInternalFrame f)
266 delegate.closeFrame(f);
270 public void deactivateFrame(JInternalFrame f)
272 delegate.deactivateFrame(f);
276 public void deiconifyFrame(JInternalFrame f)
278 delegate.deiconifyFrame(f);
282 public void dragFrame(JComponent f, int newX, int newY)
288 delegate.dragFrame(f, newX, newY);
292 public void endDraggingFrame(JComponent f)
294 delegate.endDraggingFrame(f);
299 public void endResizingFrame(JComponent f)
301 delegate.endResizingFrame(f);
306 public void iconifyFrame(JInternalFrame f)
308 delegate.iconifyFrame(f);
312 public void maximizeFrame(JInternalFrame f)
314 delegate.maximizeFrame(f);
318 public void minimizeFrame(JInternalFrame f)
320 delegate.minimizeFrame(f);
324 public void openFrame(JInternalFrame f)
326 delegate.openFrame(f);
330 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
337 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
341 public void setBoundsForFrame(JComponent f, int newX, int newY,
342 int newWidth, int newHeight)
344 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
347 // All other methods, simply delegate
352 * Creates a new Desktop object.
357 * A note to implementors. It is ESSENTIAL that any activities that might
358 * block are spawned off as threads rather than waited for during this
362 doVamsasClientCheck();
364 doConfigureStructurePrefs();
365 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
367 if (!Platform.isAMac())
369 // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
373 this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
377 // flagging this test to avoid unnecessary reflection
380 // see if the Quit, About and Preferences handlers are available
381 Class desktopClass = java.awt.Desktop.class;
382 java.awt.Desktop hdesktop = java.awt.Desktop.getDesktop();
386 Float specversion = Float.parseFloat(
387 System.getProperty("java.specification.version"));
389 if (specversion >= 9)
391 if (Platform.isAMac())
393 if (desktopClass.getDeclaredMethod("setAboutHandler",
395 { java.awt.desktop.AboutHandler.class }) != null)
398 hdesktop.setAboutHandler(new java.awt.desktop.AboutHandler()
401 public void handleAbout(java.awt.desktop.AboutEvent e)
403 aboutMenuItem_actionPerformed(null);
409 if (desktopClass.getDeclaredMethod("setPreferencesHandler",
411 { java.awt.desktop.PreferencesHandler.class }) != null)
414 hdesktop.setPreferencesHandler(
415 new java.awt.desktop.PreferencesHandler()
418 public void handlePreferences(
419 java.awt.desktop.PreferencesEvent e)
421 preferences_actionPerformed(null);
427 if (desktopClass.getDeclaredMethod("setQuitHandler",
429 { java.awt.desktop.QuitHandler.class }) != null)
432 hdesktop.setQuitHandler(new java.awt.desktop.QuitHandler()
435 public void handleQuitRequestWith(
436 java.awt.desktop.QuitEvent e,
437 java.awt.desktop.QuitResponse r)
439 boolean confirmQuit = jalview.bin.Cache
440 .getDefault(CONFIRM_KEYBOARD_QUIT, true);
444 n = JOptionPane.showConfirmDialog(null,
445 MessageManager.getString("label.quit_jalview"),
446 MessageManager.getString("action.quit"),
447 JOptionPane.OK_CANCEL_OPTION,
448 JOptionPane.PLAIN_MESSAGE, null);
452 n = JOptionPane.OK_OPTION;
454 if (n == JOptionPane.OK_OPTION)
456 System.out.println("Shortcut Quit confirmed by user");
458 r.performQuit(); // probably won't reach this line, but just
465 System.out.println("Shortcut Quit cancelled by user");
469 hdesktop.setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
477 "Not going to try setting APQ Handlers as java.spec.version is "
481 } catch (Exception e)
484 "Exception when looking for About, Preferences, Quit Handlers");
486 } catch (Throwable t)
489 "Throwable when looking for About, Preferences, Quit Handlers");
493 setAPQHandlers = true;
496 addWindowListener(new WindowAdapter()
500 public void windowClosing(WindowEvent ev)
506 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
509 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
511 desktop = new MyDesktopPane(selmemusage);
512 showMemusage.setSelected(selmemusage);
513 desktop.setBackground(Color.white);
515 getContentPane().setLayout(new BorderLayout());
516 // alternate config - have scrollbars - see notes in JAL-153
517 // JScrollPane sp = new JScrollPane();
518 // sp.getViewport().setView(desktop);
519 // getContentPane().add(sp, BorderLayout.CENTER);
520 getContentPane().add(desktop, BorderLayout.CENTER);
521 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
523 // This line prevents Windows Look&Feel resizing all new windows to maximum
524 // if previous window was maximised
525 desktop.setDesktopManager(new MyDesktopManager(
526 (Platform.isWindows() ? new DefaultDesktopManager()
528 ? new AquaInternalFrameManager(
529 desktop.getDesktopManager())
530 : desktop.getDesktopManager())));
532 Rectangle dims = getLastKnownDimensions("");
539 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
540 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
543 jconsole = new Console(this, showjconsole);
544 // add essential build information
546 "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
547 + "\n" + "Jalview Installation: "
548 + jalview.bin.Cache.getDefault("INSTALLATION",
550 + "\n" + "Build Date: "
551 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
552 + "\n" + "Java version: "
553 + System.getProperty("java.version") + "\n"
554 + System.getProperty("os.arch") + " "
555 + System.getProperty("os.name") + " "
556 + System.getProperty("os.version"));
558 showConsole(showjconsole);
560 showNews.setVisible(false);
562 experimentalFeatures.setSelected(showExperimental());
564 getIdentifiersOrgData();
568 this.addWindowListener(new WindowAdapter()
571 public void windowClosing(WindowEvent evt)
578 this.addMouseListener(ma = new MouseAdapter()
581 public void mousePressed(MouseEvent evt)
583 if (evt.isPopupTrigger()) // Mac
585 showPasteMenu(evt.getX(), evt.getY());
590 public void mouseReleased(MouseEvent evt)
592 if (evt.isPopupTrigger()) // Windows
594 showPasteMenu(evt.getX(), evt.getY());
598 desktop.addMouseListener(ma);
600 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
601 // Spawn a thread that shows the splashscreen
602 SwingUtilities.invokeLater(new Runnable()
611 // Thread off a new instance of the file chooser - this reduces the time it
612 // takes to open it later on.
613 new Thread(new Runnable()
618 Cache.log.debug("Filechooser init thread started.");
619 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
620 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
622 Cache.log.debug("Filechooser init thread finished.");
625 // Add the service change listener
626 changeSupport.addJalviewPropertyChangeListener("services",
627 new PropertyChangeListener()
631 public void propertyChange(PropertyChangeEvent evt)
633 Cache.log.debug("Firing service changed event for "
634 + evt.getNewValue());
635 JalviewServicesChanged(evt);
642 * Answers true if user preferences to enable experimental features is True
647 public boolean showExperimental()
649 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
650 Boolean.FALSE.toString());
651 return Boolean.valueOf(experimental).booleanValue();
654 public void doConfigureStructurePrefs()
656 // configure services
657 StructureSelectionManager ssm = StructureSelectionManager
658 .getStructureSelectionManager(this);
659 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
661 ssm.setAddTempFacAnnot(jalview.bin.Cache
662 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
663 ssm.setProcessSecondaryStructure(jalview.bin.Cache
664 .getDefault(Preferences.STRUCT_FROM_PDB, true));
665 ssm.setSecStructServices(
666 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
670 ssm.setAddTempFacAnnot(false);
671 ssm.setProcessSecondaryStructure(false);
672 ssm.setSecStructServices(false);
676 public void checkForNews()
678 final Desktop me = this;
679 // Thread off the news reader, in case there are connection problems.
680 new Thread(new Runnable()
685 Cache.log.debug("Starting news thread.");
687 jvnews = new BlogReader(me);
688 showNews.setVisible(true);
689 Cache.log.debug("Completed news thread.");
694 public void getIdentifiersOrgData()
696 // Thread off the identifiers fetcher
697 new Thread(new Runnable()
702 Cache.log.debug("Downloading data from identifiers.org");
703 UrlDownloadClient client = new UrlDownloadClient();
706 client.download(IdOrgSettings.getUrl(),
707 IdOrgSettings.getDownloadLocation());
708 } catch (IOException e)
710 Cache.log.debug("Exception downloading identifiers.org data"
719 protected void showNews_actionPerformed(ActionEvent e)
721 showNews(showNews.isSelected());
724 void showNews(boolean visible)
727 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
728 showNews.setSelected(visible);
729 if (visible && !jvnews.isVisible())
731 new Thread(new Runnable()
736 long now = System.currentTimeMillis();
737 Desktop.instance.setProgressBar(
738 MessageManager.getString("status.refreshing_news"),
740 jvnews.refreshNews();
741 Desktop.instance.setProgressBar(null, now);
750 * recover the last known dimensions for a jalview window
753 * - empty string is desktop, all other windows have unique prefix
754 * @return null or last known dimensions scaled to current geometry (if last
755 * window geom was known)
757 Rectangle getLastKnownDimensions(String windowName)
759 // TODO: lock aspect ratio for scaling desktop Bug #0058199
760 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
761 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
762 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
763 String width = jalview.bin.Cache
764 .getProperty(windowName + "SCREEN_WIDTH");
765 String height = jalview.bin.Cache
766 .getProperty(windowName + "SCREEN_HEIGHT");
767 if ((x != null) && (y != null) && (width != null) && (height != null))
769 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
770 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
771 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
773 // attempt #1 - try to cope with change in screen geometry - this
774 // version doesn't preserve original jv aspect ratio.
775 // take ratio of current screen size vs original screen size.
776 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
777 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
778 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
779 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
780 // rescale the bounds depending upon the current screen geometry.
781 ix = (int) (ix * sw);
782 iw = (int) (iw * sw);
783 iy = (int) (iy * sh);
784 ih = (int) (ih * sh);
785 while (ix >= screenSize.width)
787 jalview.bin.Cache.log.debug(
788 "Window geometry location recall error: shifting horizontal to within screenbounds.");
789 ix -= screenSize.width;
791 while (iy >= screenSize.height)
793 jalview.bin.Cache.log.debug(
794 "Window geometry location recall error: shifting vertical to within screenbounds.");
795 iy -= screenSize.height;
797 jalview.bin.Cache.log.debug(
798 "Got last known dimensions for " + windowName + ": x:" + ix
799 + " y:" + iy + " width:" + iw + " height:" + ih);
801 // return dimensions for new instance
802 return new Rectangle(ix, iy, iw, ih);
807 private void doVamsasClientCheck()
809 if (jalview.bin.Cache.vamsasJarsPresent())
811 setupVamsasDisconnectedGui();
812 VamsasMenu.setVisible(true);
813 final Desktop us = this;
814 VamsasMenu.addMenuListener(new MenuListener()
816 // this listener remembers when the menu was first selected, and
817 // doesn't rebuild the session list until it has been cleared and
819 boolean refresh = true;
822 public void menuCanceled(MenuEvent e)
828 public void menuDeselected(MenuEvent e)
834 public void menuSelected(MenuEvent e)
838 us.buildVamsasStMenu();
843 vamsasStart.setVisible(true);
847 void showPasteMenu(int x, int y)
849 JPopupMenu popup = new JPopupMenu();
850 JMenuItem item = new JMenuItem(
851 MessageManager.getString("label.paste_new_window"));
852 item.addActionListener(new ActionListener()
855 public void actionPerformed(ActionEvent evt)
862 popup.show(this, x, y);
869 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
870 Transferable contents = c.getContents(this);
872 if (contents != null)
874 String file = (String) contents
875 .getTransferData(DataFlavor.stringFlavor);
877 FileFormatI format = new IdentifyFile().identify(file,
878 DataSourceType.PASTE);
880 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
883 } catch (Exception ex)
886 "Unable to paste alignment from system clipboard:\n" + ex);
891 * Adds and opens the given frame to the desktop
902 public static synchronized void addInternalFrame(
903 final JInternalFrame frame, String title, int w, int h)
905 addInternalFrame(frame, title, true, w, h, true, false);
909 * Add an internal frame to the Jalview desktop
916 * When true, display frame immediately, otherwise, caller must call
917 * setVisible themselves.
923 public static synchronized void addInternalFrame(
924 final JInternalFrame frame, String title, boolean makeVisible,
927 addInternalFrame(frame, title, makeVisible, w, h, true, false);
931 * Add an internal frame to the Jalview desktop and make it visible
944 public static synchronized void addInternalFrame(
945 final JInternalFrame frame, String title, int w, int h,
948 addInternalFrame(frame, title, true, w, h, resizable, false);
952 * Add an internal frame to the Jalview desktop
959 * When true, display frame immediately, otherwise, caller must call
960 * setVisible themselves.
967 * @param ignoreMinSize
968 * Do not set the default minimum size for frame
970 public static synchronized void addInternalFrame(
971 final JInternalFrame frame, String title, boolean makeVisible,
972 int w, int h, boolean resizable, boolean ignoreMinSize)
975 // TODO: allow callers to determine X and Y position of frame (eg. via
977 // TODO: consider fixing method to update entries in the window submenu with
978 // the current window title
980 frame.setTitle(title);
981 if (frame.getWidth() < 1 || frame.getHeight() < 1)
985 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
986 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
987 // IF JALVIEW IS RUNNING HEADLESS
988 // ///////////////////////////////////////////////
989 if (instance == null || (System.getProperty("java.awt.headless") != null
990 && System.getProperty("java.awt.headless").equals("true")))
999 frame.setMinimumSize(
1000 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
1002 // Set default dimension for Alignment Frame window.
1003 // The Alignment Frame window could be added from a number of places,
1005 // I did this here in order not to miss out on any Alignment frame.
1006 if (frame instanceof AlignFrame)
1008 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
1009 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
1013 frame.setVisible(makeVisible);
1014 frame.setClosable(true);
1015 frame.setResizable(resizable);
1016 frame.setMaximizable(resizable);
1017 frame.setIconifiable(resizable);
1018 frame.setOpaque(false);
1020 if (frame.getX() < 1 && frame.getY() < 1)
1022 frame.setLocation(xOffset * openFrameCount,
1023 yOffset * ((openFrameCount - 1) % 10) + yOffset);
1027 * add an entry for the new frame in the Window menu
1028 * (and remove it when the frame is closed)
1030 final JMenuItem menuItem = new JMenuItem(title);
1031 frame.addInternalFrameListener(new InternalFrameAdapter()
1034 public void internalFrameActivated(InternalFrameEvent evt)
1036 JInternalFrame itf = desktop.getSelectedFrame();
1039 if (itf instanceof AlignFrame)
1041 Jalview.setCurrentAlignFrame((AlignFrame) itf);
1048 public void internalFrameClosed(InternalFrameEvent evt)
1050 PaintRefresher.RemoveComponent(frame);
1053 * defensive check to prevent frames being
1054 * added half off the window
1056 if (openFrameCount > 0)
1062 * ensure no reference to alignFrame retained by menu item listener
1064 if (menuItem.getActionListeners().length > 0)
1066 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
1068 windowMenu.remove(menuItem);
1072 menuItem.addActionListener(new ActionListener()
1075 public void actionPerformed(ActionEvent e)
1079 frame.setSelected(true);
1080 frame.setIcon(false);
1081 } catch (java.beans.PropertyVetoException ex)
1088 setKeyBindings(frame);
1092 windowMenu.add(menuItem);
1097 frame.setSelected(true);
1098 frame.requestFocus();
1099 } catch (java.beans.PropertyVetoException ve)
1101 } catch (java.lang.ClassCastException cex)
1104 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
1110 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
1115 private static void setKeyBindings(JInternalFrame frame)
1117 @SuppressWarnings("serial")
1118 final Action closeAction = new AbstractAction()
1121 public void actionPerformed(ActionEvent e)
1128 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1130 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1131 InputEvent.CTRL_DOWN_MASK);
1132 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1133 Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx());
1135 InputMap inputMap = frame
1136 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1137 String ctrlW = ctrlWKey.toString();
1138 inputMap.put(ctrlWKey, ctrlW);
1139 inputMap.put(cmdWKey, ctrlW);
1141 ActionMap actionMap = frame.getActionMap();
1142 actionMap.put(ctrlW, closeAction);
1146 public void lostOwnership(Clipboard clipboard, Transferable contents)
1150 Desktop.jalviewClipboard = null;
1153 internalCopy = false;
1157 public void dragEnter(DropTargetDragEvent evt)
1162 public void dragExit(DropTargetEvent evt)
1167 public void dragOver(DropTargetDragEvent evt)
1172 public void dropActionChanged(DropTargetDragEvent evt)
1183 public void drop(DropTargetDropEvent evt)
1185 boolean success = true;
1186 // JAL-1552 - acceptDrop required before getTransferable call for
1187 // Java's Transferable for native dnd
1188 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1189 Transferable t = evt.getTransferable();
1190 List<String> files = new ArrayList<>();
1191 List<DataSourceType> protocols = new ArrayList<>();
1195 Desktop.transferFromDropTarget(files, protocols, evt, t);
1196 } catch (Exception e)
1198 e.printStackTrace();
1206 for (int i = 0; i < files.size(); i++)
1208 String file = files.get(i).toString();
1209 DataSourceType protocol = (protocols == null)
1210 ? DataSourceType.FILE
1212 FileFormatI format = null;
1214 if (file.endsWith(".jar"))
1216 format = FileFormat.Jalview;
1221 format = new IdentifyFile().identify(file, protocol);
1224 new FileLoader().LoadFile(file, protocol, format);
1227 } catch (Exception ex)
1232 evt.dropComplete(success); // need this to ensure input focus is properly
1233 // transfered to any new windows created
1243 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1245 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1246 JalviewFileChooser chooser = JalviewFileChooser
1247 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, true);
1249 chooser.setFileView(new JalviewFileView());
1250 chooser.setDialogTitle(
1251 MessageManager.getString("label.open_local_file"));
1252 chooser.setToolTipText(MessageManager.getString("action.open"));
1254 int value = chooser.showOpenDialog(this);
1256 if (value == JalviewFileChooser.APPROVE_OPTION)
1258 String choice = chooser.getSelectedFile().getPath();
1259 Cache.setProperty("LAST_DIRECTORY",
1260 chooser.getSelectedFile().getParent());
1262 FileFormatI format = chooser.getSelectedFormat();
1265 * Call IdentifyFile to verify the file contains what its extension implies.
1266 * Skip this step for dynamically added file formats, because
1267 * IdentifyFile does not know how to recognise them.
1269 if (FileFormats.getInstance().isIdentifiable(format))
1273 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1274 } catch (FileFormatException e)
1276 // format = null; //??
1280 if (viewport != null)
1282 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1287 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1299 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1301 // This construct allows us to have a wider textfield
1303 JLabel label = new JLabel(
1304 MessageManager.getString("label.input_file_url"));
1305 final JComboBox history = new JComboBox();
1307 JPanel panel = new JPanel(new GridLayout(2, 1));
1310 history.setPreferredSize(new Dimension(400, 20));
1311 history.setEditable(true);
1312 history.addItem("http://www.");
1314 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1318 if (historyItems != null)
1320 st = new StringTokenizer(historyItems, "\t");
1322 while (st.hasMoreTokens())
1324 history.addItem(st.nextElement());
1328 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1329 MessageManager.getString("label.input_alignment_from_url"),
1330 JvOptionPane.OK_CANCEL_OPTION);
1332 if (reply != JvOptionPane.OK_OPTION)
1337 String url = history.getSelectedItem().toString();
1339 if (url.toLowerCase().endsWith(".jar"))
1341 if (viewport != null)
1343 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1344 FileFormat.Jalview);
1348 new FileLoader().LoadFile(url, DataSourceType.URL,
1349 FileFormat.Jalview);
1354 FileFormatI format = null;
1357 format = new IdentifyFile().identify(url, DataSourceType.URL);
1358 } catch (FileFormatException e)
1360 // TODO revise error handling, distinguish between
1361 // URL not found and response not valid
1366 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1367 MessageManager.formatMessage("label.couldnt_locate",
1370 MessageManager.getString("label.url_not_found"),
1371 JvOptionPane.WARNING_MESSAGE);
1376 if (viewport != null)
1378 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1383 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1389 * Opens the CutAndPaste window for the user to paste an alignment in to
1392 * - if not null, the pasted alignment is added to the current
1393 * alignment; if null, to a new alignment window
1396 public void inputTextboxMenuItem_actionPerformed(
1397 AlignmentViewPanel viewPanel)
1399 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1400 cap.setForInput(viewPanel);
1401 Desktop.addInternalFrame(cap,
1402 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1412 //System.out.println("********** Desktop.quit()");
1413 //System.out.println(savingFiles.toString());
1414 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1415 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1417 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1418 screen.height + "");
1419 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1420 getWidth(), getHeight()));
1422 if (jconsole != null)
1424 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1425 jconsole.stopConsole();
1429 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1432 if (dialogExecutor != null)
1434 dialogExecutor.shutdownNow();
1436 closeAll_actionPerformed(null);
1438 if (groovyConsole != null)
1440 // suppress a possible repeat prompt to save script
1441 groovyConsole.setDirty(false);
1442 groovyConsole.exit();
1447 private void storeLastKnownDimensions(String string, Rectangle jc)
1449 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1450 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1451 + " height:" + jc.height);
1453 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1454 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1455 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1456 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1466 public void aboutMenuItem_actionPerformed(ActionEvent e)
1468 // StringBuffer message = getAboutMessage(false);
1469 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1471 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1472 new Thread(new Runnable()
1477 new SplashScreen(true);
1482 public StringBuffer getAboutMessage(boolean shortv)
1484 StringBuffer message = new StringBuffer();
1485 message.append("<html>");
1488 message.append("<h1><strong>Version: "
1489 + jalview.bin.Cache.getProperty("VERSION")
1490 + "</strong></h1>");
1491 message.append("<strong>Last Updated: <em>"
1492 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1493 + "</em></strong>");
1499 message.append("<strong>Version "
1500 + jalview.bin.Cache.getProperty("VERSION")
1501 + "; last updated: "
1502 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1505 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1506 .equals("Checking"))
1508 message.append("<br>...Checking latest version...</br>");
1510 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1511 .equals(jalview.bin.Cache.getProperty("VERSION")))
1513 boolean red = false;
1514 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1515 .indexOf("automated build") == -1)
1518 // Displayed when code version and jnlp version do not match and code
1519 // version is not a development build
1520 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1523 message.append("<br>!! Version "
1524 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1526 + " is available for download from "
1527 + jalview.bin.Cache.getDefault("www.jalview.org",
1528 "http://www.jalview.org")
1532 message.append("</div>");
1535 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1537 "The Jalview Authors (See AUTHORS file for current list)")
1538 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1539 + "<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"
1540 + "<br><br>If you use Jalview, please cite:"
1541 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1542 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1543 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1555 public void documentationMenuItem_actionPerformed(ActionEvent e)
1559 Help.showHelpWindow();
1560 } catch (Exception ex)
1566 public void closeAll_actionPerformed(ActionEvent e)
1568 // TODO show a progress bar while closing?
1569 JInternalFrame[] frames = desktop.getAllFrames();
1570 for (int i = 0; i < frames.length; i++)
1574 frames[i].setClosed(true);
1575 } catch (java.beans.PropertyVetoException ex)
1579 Jalview.setCurrentAlignFrame(null);
1580 System.out.println("ALL CLOSED");
1581 if (v_client != null)
1583 // TODO clear binding to vamsas document objects on close_all
1587 * reset state of singleton objects as appropriate (clear down session state
1588 * when all windows are closed)
1590 StructureSelectionManager ssm = StructureSelectionManager
1591 .getStructureSelectionManager(this);
1599 public void raiseRelated_actionPerformed(ActionEvent e)
1601 reorderAssociatedWindows(false, false);
1605 public void minimizeAssociated_actionPerformed(ActionEvent e)
1607 reorderAssociatedWindows(true, false);
1610 void closeAssociatedWindows()
1612 reorderAssociatedWindows(false, true);
1618 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1622 protected void garbageCollect_actionPerformed(ActionEvent e)
1624 // We simply collect the garbage
1625 jalview.bin.Cache.log.debug("Collecting garbage...");
1627 jalview.bin.Cache.log.debug("Finished garbage collection.");
1634 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1638 protected void showMemusage_actionPerformed(ActionEvent e)
1640 desktop.showMemoryUsage(showMemusage.isSelected());
1647 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1651 protected void showConsole_actionPerformed(ActionEvent e)
1653 showConsole(showConsole.isSelected());
1656 Console jconsole = null;
1659 * control whether the java console is visible or not
1663 void showConsole(boolean selected)
1665 showConsole.setSelected(selected);
1666 // TODO: decide if we should update properties file
1667 Cache.setProperty("SHOW_JAVA_CONSOLE",
1668 Boolean.valueOf(selected).toString());
1669 jconsole.setVisible(selected);
1672 void reorderAssociatedWindows(boolean minimize, boolean close)
1674 JInternalFrame[] frames = desktop.getAllFrames();
1675 if (frames == null || frames.length < 1)
1680 AlignmentViewport source = null, target = null;
1681 if (frames[0] instanceof AlignFrame)
1683 source = ((AlignFrame) frames[0]).getCurrentView();
1685 else if (frames[0] instanceof TreePanel)
1687 source = ((TreePanel) frames[0]).getViewPort();
1689 else if (frames[0] instanceof PCAPanel)
1691 source = ((PCAPanel) frames[0]).av;
1693 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1695 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1700 for (int i = 0; i < frames.length; i++)
1703 if (frames[i] == null)
1707 if (frames[i] instanceof AlignFrame)
1709 target = ((AlignFrame) frames[i]).getCurrentView();
1711 else if (frames[i] instanceof TreePanel)
1713 target = ((TreePanel) frames[i]).getViewPort();
1715 else if (frames[i] instanceof PCAPanel)
1717 target = ((PCAPanel) frames[i]).av;
1719 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1721 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1724 if (source == target)
1730 frames[i].setClosed(true);
1734 frames[i].setIcon(minimize);
1737 frames[i].toFront();
1741 } catch (java.beans.PropertyVetoException ex)
1756 protected void preferences_actionPerformed(ActionEvent e)
1762 * Shows a file chooser dialog and writes out the current session as a Jalview
1766 public void saveState_actionPerformed()
1768 saveState_actionPerformed(false);
1771 public void saveState_actionPerformed(boolean saveAs)
1773 java.io.File projectFile = getProjectFile();
1774 // autoSave indicates we already have a file and don't need to ask
1775 boolean autoSave = projectFile != null && !saveAs
1776 && BackupFiles.getEnabled();
1778 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1779 // saveAs="+saveAs+", Backups
1780 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1782 boolean approveSave = false;
1785 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1788 chooser.setFileView(new JalviewFileView());
1789 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1791 int value = chooser.showSaveDialog(this);
1793 if (value == JalviewFileChooser.APPROVE_OPTION)
1795 projectFile = chooser.getSelectedFile();
1796 setProjectFile(projectFile);
1801 if (approveSave || autoSave)
1803 final Desktop me = this;
1804 final java.io.File chosenFile = projectFile;
1805 new Thread(new Runnable()
1810 // TODO: refactor to Jalview desktop session controller action.
1811 setProgressBar(MessageManager.formatMessage(
1812 "label.saving_jalview_project", new Object[]
1813 { chosenFile.getName() }), chosenFile.hashCode());
1814 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1815 chosenFile.getParent());
1816 // TODO catch and handle errors for savestate
1817 // TODO prevent user from messing with the Desktop whilst we're saving
1820 BackupFiles backupfiles = new BackupFiles(chosenFile);
1822 new Jalview2XML().saveState(backupfiles.getTempFile());
1824 backupfiles.setWriteSuccess(true);
1825 backupfiles.rollBackupsAndRenameTempFile();
1826 } catch (OutOfMemoryError oom)
1828 new OOMWarning("Whilst saving current state to "
1829 + chosenFile.getName(), oom);
1830 } catch (Exception ex)
1832 Cache.log.error("Problems whilst trying to save to "
1833 + chosenFile.getName(), ex);
1834 JvOptionPane.showMessageDialog(me,
1835 MessageManager.formatMessage(
1836 "label.error_whilst_saving_current_state_to",
1838 { chosenFile.getName() }),
1839 MessageManager.getString("label.couldnt_save_project"),
1840 JvOptionPane.WARNING_MESSAGE);
1842 setProgressBar(null, chosenFile.hashCode());
1849 public void saveAsState_actionPerformed(ActionEvent e)
1851 saveState_actionPerformed(true);
1854 private void setProjectFile(File choice)
1856 this.projectFile = choice;
1859 public File getProjectFile()
1861 return this.projectFile;
1865 * Shows a file chooser dialog and tries to read in the selected file as a
1869 public void loadState_actionPerformed()
1871 final String[] suffix = new String[] { "jvp", "jar" };
1872 final String[] desc = new String[] { "Jalview Project",
1873 "Jalview Project (old)" };
1874 JalviewFileChooser chooser = new JalviewFileChooser(
1875 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1876 "Jalview Project", true, true); // last two booleans: allFiles,
1878 chooser.setFileView(new JalviewFileView());
1879 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1881 int value = chooser.showOpenDialog(this);
1883 if (value == JalviewFileChooser.APPROVE_OPTION)
1885 final File selectedFile = chooser.getSelectedFile();
1886 setProjectFile(selectedFile);
1887 final String choice = selectedFile.getAbsolutePath();
1888 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1889 new Thread(new Runnable()
1894 setProgressBar(MessageManager.formatMessage(
1895 "label.loading_jalview_project", new Object[]
1896 { choice }), choice.hashCode());
1899 new Jalview2XML().loadJalviewAlign(choice);
1900 } catch (OutOfMemoryError oom)
1902 new OOMWarning("Whilst loading project from " + choice, oom);
1903 } catch (Exception ex)
1906 "Problems whilst loading project from " + choice, ex);
1907 JvOptionPane.showMessageDialog(Desktop.desktop,
1908 MessageManager.formatMessage(
1909 "label.error_whilst_loading_project_from",
1912 MessageManager.getString("label.couldnt_load_project"),
1913 JvOptionPane.WARNING_MESSAGE);
1915 setProgressBar(null, choice.hashCode());
1922 public void inputSequence_actionPerformed(ActionEvent e)
1924 new SequenceFetcher(this);
1927 JPanel progressPanel;
1929 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1931 public void startLoading(final String fileName)
1933 if (fileLoadingCount == 0)
1935 fileLoadingPanels.add(addProgressPanel(MessageManager
1936 .formatMessage("label.loading_file", new Object[]
1942 private JPanel addProgressPanel(String string)
1944 if (progressPanel == null)
1946 progressPanel = new JPanel(new GridLayout(1, 1));
1947 totalProgressCount = 0;
1948 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1950 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1951 JProgressBar progressBar = new JProgressBar();
1952 progressBar.setIndeterminate(true);
1954 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1956 thisprogress.add(progressBar, BorderLayout.CENTER);
1957 progressPanel.add(thisprogress);
1958 ((GridLayout) progressPanel.getLayout()).setRows(
1959 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1960 ++totalProgressCount;
1961 instance.validate();
1962 return thisprogress;
1965 int totalProgressCount = 0;
1967 private void removeProgressPanel(JPanel progbar)
1969 if (progressPanel != null)
1971 synchronized (progressPanel)
1973 progressPanel.remove(progbar);
1974 GridLayout gl = (GridLayout) progressPanel.getLayout();
1975 gl.setRows(gl.getRows() - 1);
1976 if (--totalProgressCount < 1)
1978 this.getContentPane().remove(progressPanel);
1979 progressPanel = null;
1986 public void stopLoading()
1989 if (fileLoadingCount < 1)
1991 while (fileLoadingPanels.size() > 0)
1993 removeProgressPanel(fileLoadingPanels.remove(0));
1995 fileLoadingPanels.clear();
1996 fileLoadingCount = 0;
2001 public static int getViewCount(String alignmentId)
2003 AlignmentViewport[] aps = getViewports(alignmentId);
2004 return (aps == null) ? 0 : aps.length;
2009 * @param alignmentId
2010 * - if null, all sets are returned
2011 * @return all AlignmentPanels concerning the alignmentId sequence set
2013 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
2015 if (Desktop.desktop == null)
2017 // no frames created and in headless mode
2018 // TODO: verify that frames are recoverable when in headless mode
2021 List<AlignmentPanel> aps = new ArrayList<>();
2022 AlignFrame[] frames = getAlignFrames();
2027 for (AlignFrame af : frames)
2029 for (AlignmentPanel ap : af.alignPanels)
2031 if (alignmentId == null
2032 || alignmentId.equals(ap.av.getSequenceSetId()))
2038 if (aps.size() == 0)
2042 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
2047 * get all the viewports on an alignment.
2049 * @param sequenceSetId
2050 * unique alignment id (may be null - all viewports returned in that
2052 * @return all viewports on the alignment bound to sequenceSetId
2054 public static AlignmentViewport[] getViewports(String sequenceSetId)
2056 List<AlignmentViewport> viewp = new ArrayList<>();
2057 if (desktop != null)
2059 AlignFrame[] frames = Desktop.getAlignFrames();
2061 for (AlignFrame afr : frames)
2063 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
2064 .equals(sequenceSetId))
2066 if (afr.alignPanels != null)
2068 for (AlignmentPanel ap : afr.alignPanels)
2070 if (sequenceSetId == null
2071 || sequenceSetId.equals(ap.av.getSequenceSetId()))
2079 viewp.add(afr.getViewport());
2083 if (viewp.size() > 0)
2085 return viewp.toArray(new AlignmentViewport[viewp.size()]);
2092 * Explode the views in the given frame into separate AlignFrame
2096 public static void explodeViews(AlignFrame af)
2098 int size = af.alignPanels.size();
2104 for (int i = 0; i < size; i++)
2106 AlignmentPanel ap = af.alignPanels.get(i);
2107 AlignFrame newaf = new AlignFrame(ap);
2110 * Restore the view's last exploded frame geometry if known. Multiple
2111 * views from one exploded frame share and restore the same (frame)
2112 * position and size.
2114 Rectangle geometry = ap.av.getExplodedGeometry();
2115 if (geometry != null)
2117 newaf.setBounds(geometry);
2120 ap.av.setGatherViewsHere(false);
2122 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2123 AlignFrame.DEFAULT_HEIGHT);
2126 af.alignPanels.clear();
2127 af.closeMenuItem_actionPerformed(true);
2132 * Gather expanded views (separate AlignFrame's) with the same sequence set
2133 * identifier back in to this frame as additional views, and close the
2134 * expanded views. Note the expanded frames may themselves have multiple
2135 * views. We take the lot.
2139 public void gatherViews(AlignFrame source)
2141 source.viewport.setGatherViewsHere(true);
2142 source.viewport.setExplodedGeometry(source.getBounds());
2143 JInternalFrame[] frames = desktop.getAllFrames();
2144 String viewId = source.viewport.getSequenceSetId();
2146 for (int t = 0; t < frames.length; t++)
2148 if (frames[t] instanceof AlignFrame && frames[t] != source)
2150 AlignFrame af = (AlignFrame) frames[t];
2151 boolean gatherThis = false;
2152 for (int a = 0; a < af.alignPanels.size(); a++)
2154 AlignmentPanel ap = af.alignPanels.get(a);
2155 if (viewId.equals(ap.av.getSequenceSetId()))
2158 ap.av.setGatherViewsHere(false);
2159 ap.av.setExplodedGeometry(af.getBounds());
2160 source.addAlignmentPanel(ap, false);
2166 af.alignPanels.clear();
2167 af.closeMenuItem_actionPerformed(true);
2174 jalview.gui.VamsasApplication v_client = null;
2177 public void vamsasImport_actionPerformed(ActionEvent e)
2179 if (v_client == null)
2181 // Load and try to start a session.
2182 JalviewFileChooser chooser = new JalviewFileChooser(
2183 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2185 chooser.setFileView(new JalviewFileView());
2186 chooser.setDialogTitle(
2187 MessageManager.getString("label.open_saved_vamsas_session"));
2188 chooser.setToolTipText(MessageManager.getString(
2189 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2191 int value = chooser.showOpenDialog(this);
2193 if (value == JalviewFileChooser.APPROVE_OPTION)
2195 String fle = chooser.getSelectedFile().toString();
2196 if (!vamsasImport(chooser.getSelectedFile()))
2198 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2199 MessageManager.formatMessage(
2200 "label.couldnt_import_as_vamsas_session",
2204 .getString("label.vamsas_document_import_failed"),
2205 JvOptionPane.ERROR_MESSAGE);
2211 jalview.bin.Cache.log.error(
2212 "Implementation error - load session from a running session is not supported.");
2217 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2220 * @return true if import was a success and a session was started.
2222 public boolean vamsasImport(URL url)
2224 // TODO: create progress bar
2225 if (v_client != null)
2228 jalview.bin.Cache.log.error(
2229 "Implementation error - load session from a running session is not supported.");
2235 // copy the URL content to a temporary local file
2236 // TODO: be a bit cleverer here with nio (?!)
2237 File file = File.createTempFile("vdocfromurl", ".vdj");
2238 FileOutputStream fos = new FileOutputStream(file);
2239 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2240 byte[] buffer = new byte[2048];
2242 while ((ln = bis.read(buffer)) > -1)
2244 fos.write(buffer, 0, ln);
2248 v_client = new jalview.gui.VamsasApplication(this, file,
2249 url.toExternalForm());
2250 } catch (Exception ex)
2252 jalview.bin.Cache.log.error(
2253 "Failed to create new vamsas session from contents of URL "
2258 setupVamsasConnectedGui();
2259 v_client.initial_update(); // TODO: thread ?
2260 return v_client.inSession();
2264 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2267 * @return true if import was a success and a session was started.
2269 public boolean vamsasImport(File file)
2271 if (v_client != null)
2274 jalview.bin.Cache.log.error(
2275 "Implementation error - load session from a running session is not supported.");
2279 setProgressBar(MessageManager.formatMessage(
2280 "status.importing_vamsas_session_from", new Object[]
2281 { file.getName() }), file.hashCode());
2284 v_client = new jalview.gui.VamsasApplication(this, file, null);
2285 } catch (Exception ex)
2287 setProgressBar(MessageManager.formatMessage(
2288 "status.importing_vamsas_session_from", new Object[]
2289 { file.getName() }), file.hashCode());
2290 jalview.bin.Cache.log.error(
2291 "New vamsas session from existing session file failed:", ex);
2294 setupVamsasConnectedGui();
2295 v_client.initial_update(); // TODO: thread ?
2296 setProgressBar(MessageManager.formatMessage(
2297 "status.importing_vamsas_session_from", new Object[]
2298 { file.getName() }), file.hashCode());
2299 return v_client.inSession();
2302 public boolean joinVamsasSession(String mysesid)
2304 if (v_client != null)
2306 throw new Error(MessageManager
2307 .getString("error.try_join_vamsas_session_another"));
2309 if (mysesid == null)
2312 MessageManager.getString("error.invalid_vamsas_session_id"));
2314 v_client = new VamsasApplication(this, mysesid);
2315 setupVamsasConnectedGui();
2316 v_client.initial_update();
2317 return (v_client.inSession());
2321 public void vamsasStart_actionPerformed(ActionEvent e)
2323 if (v_client == null)
2326 // we just start a default session for moment.
2328 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2329 * getProperty("LAST_DIRECTORY"));
2331 * chooser.setFileView(new JalviewFileView());
2332 * chooser.setDialogTitle("Load Vamsas file");
2333 * chooser.setToolTipText("Import");
2335 * int value = chooser.showOpenDialog(this);
2337 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2338 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2340 v_client = new VamsasApplication(this);
2341 setupVamsasConnectedGui();
2342 v_client.initial_update(); // TODO: thread ?
2346 // store current data in session.
2347 v_client.push_update(); // TODO: thread
2351 protected void setupVamsasConnectedGui()
2353 vamsasStart.setText(MessageManager.getString("label.session_update"));
2354 vamsasSave.setVisible(true);
2355 vamsasStop.setVisible(true);
2356 vamsasImport.setVisible(false); // Document import to existing session is
2357 // not possible for vamsas-client-1.0.
2360 protected void setupVamsasDisconnectedGui()
2362 vamsasSave.setVisible(false);
2363 vamsasStop.setVisible(false);
2364 vamsasImport.setVisible(true);
2366 .setText(MessageManager.getString("label.new_vamsas_session"));
2370 public void vamsasStop_actionPerformed(ActionEvent e)
2372 if (v_client != null)
2374 v_client.end_session();
2376 setupVamsasDisconnectedGui();
2380 protected void buildVamsasStMenu()
2382 if (v_client == null)
2384 String[] sess = null;
2387 sess = VamsasApplication.getSessionList();
2388 } catch (Exception e)
2390 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2396 jalview.bin.Cache.log.debug(
2397 "Got current sessions list: " + sess.length + " entries.");
2398 VamsasStMenu.removeAll();
2399 for (int i = 0; i < sess.length; i++)
2401 JMenuItem sessit = new JMenuItem();
2402 sessit.setText(sess[i]);
2403 sessit.setToolTipText(MessageManager
2404 .formatMessage("label.connect_to_session", new Object[]
2406 final Desktop dsktp = this;
2407 final String mysesid = sess[i];
2408 sessit.addActionListener(new ActionListener()
2412 public void actionPerformed(ActionEvent e)
2414 if (dsktp.v_client == null)
2416 Thread rthr = new Thread(new Runnable()
2422 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2423 dsktp.setupVamsasConnectedGui();
2424 dsktp.v_client.initial_update();
2432 VamsasStMenu.add(sessit);
2434 // don't show an empty menu.
2435 VamsasStMenu.setVisible(sess.length > 0);
2440 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2441 VamsasStMenu.removeAll();
2442 VamsasStMenu.setVisible(false);
2447 // Not interested in the content. Just hide ourselves.
2448 VamsasStMenu.setVisible(false);
2453 public void vamsasSave_actionPerformed(ActionEvent e)
2455 if (v_client != null)
2457 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2458 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2461 chooser.setFileView(new JalviewFileView());
2462 chooser.setDialogTitle(MessageManager
2463 .getString("label.save_vamsas_document_archive"));
2465 int value = chooser.showSaveDialog(this);
2467 if (value == JalviewFileChooser.APPROVE_OPTION)
2469 java.io.File choice = chooser.getSelectedFile();
2470 JPanel progpanel = addProgressPanel(MessageManager
2471 .formatMessage("label.saving_vamsas_doc", new Object[]
2472 { choice.getName() }));
2473 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2474 String warnmsg = null;
2475 String warnttl = null;
2478 v_client.vclient.storeDocument(choice);
2481 warnttl = "Serious Problem saving Vamsas Document";
2482 warnmsg = ex.toString();
2483 jalview.bin.Cache.log
2484 .error("Error Whilst saving document to " + choice, ex);
2486 } catch (Exception ex)
2488 warnttl = "Problem saving Vamsas Document.";
2489 warnmsg = ex.toString();
2490 jalview.bin.Cache.log.warn(
2491 "Exception Whilst saving document to " + choice, ex);
2494 removeProgressPanel(progpanel);
2495 if (warnmsg != null)
2497 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2499 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2505 JPanel vamUpdate = null;
2508 * hide vamsas user gui bits when a vamsas document event is being handled.
2511 * true to hide gui, false to reveal gui
2513 public void setVamsasUpdate(boolean b)
2515 Cache.log.debug("Setting gui for Vamsas update "
2516 + (b ? "in progress" : "finished"));
2518 if (vamUpdate != null)
2520 this.removeProgressPanel(vamUpdate);
2524 vamUpdate = this.addProgressPanel(
2525 MessageManager.getString("label.updating_vamsas_session"));
2527 vamsasStart.setVisible(!b);
2528 vamsasStop.setVisible(!b);
2529 vamsasSave.setVisible(!b);
2532 public JInternalFrame[] getAllFrames()
2534 return desktop.getAllFrames();
2538 * Checks the given url to see if it gives a response indicating that the user
2539 * should be informed of a new questionnaire.
2543 public void checkForQuestionnaire(String url)
2545 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2546 // javax.swing.SwingUtilities.invokeLater(jvq);
2547 new Thread(jvq).start();
2550 public void checkURLLinks()
2552 // Thread off the URL link checker
2553 addDialogThread(new Runnable()
2558 if (Cache.getDefault("CHECKURLLINKS", true))
2560 // check what the actual links are - if it's just the default don't
2561 // bother with the warning
2562 List<String> links = Preferences.sequenceUrlLinks
2565 // only need to check links if there is one with a
2566 // SEQUENCE_ID which is not the default EMBL_EBI link
2567 ListIterator<String> li = links.listIterator();
2568 boolean check = false;
2569 List<JLabel> urls = new ArrayList<>();
2570 while (li.hasNext())
2572 String link = li.next();
2573 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2574 && !UrlConstants.isDefaultString(link))
2577 int barPos = link.indexOf("|");
2578 String urlMsg = barPos == -1 ? link
2579 : link.substring(0, barPos) + ": "
2580 + link.substring(barPos + 1);
2581 urls.add(new JLabel(urlMsg));
2589 // ask user to check in case URL links use old style tokens
2590 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2591 JPanel msgPanel = new JPanel();
2592 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2593 msgPanel.add(Box.createVerticalGlue());
2594 JLabel msg = new JLabel(MessageManager
2595 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2596 JLabel msg2 = new JLabel(MessageManager
2597 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2599 for (JLabel url : urls)
2605 final JCheckBox jcb = new JCheckBox(
2606 MessageManager.getString("label.do_not_display_again"));
2607 jcb.addActionListener(new ActionListener()
2610 public void actionPerformed(ActionEvent e)
2612 // update Cache settings for "don't show this again"
2613 boolean showWarningAgain = !jcb.isSelected();
2614 Cache.setProperty("CHECKURLLINKS",
2615 Boolean.valueOf(showWarningAgain).toString());
2620 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2622 .getString("label.SEQUENCE_ID_no_longer_used"),
2623 JvOptionPane.WARNING_MESSAGE);
2630 * Proxy class for JDesktopPane which optionally displays the current memory
2631 * usage and highlights the desktop area with a red bar if free memory runs
2636 public class MyDesktopPane extends JDesktopPane implements Runnable
2639 private static final float ONE_MB = 1048576f;
2641 boolean showMemoryUsage = false;
2645 java.text.NumberFormat df;
2647 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2650 public MyDesktopPane(boolean showMemoryUsage)
2652 showMemoryUsage(showMemoryUsage);
2655 public void showMemoryUsage(boolean showMemory)
2657 this.showMemoryUsage = showMemory;
2660 Thread worker = new Thread(this);
2666 public boolean isShowMemoryUsage()
2668 return showMemoryUsage;
2674 df = java.text.NumberFormat.getNumberInstance();
2675 df.setMaximumFractionDigits(2);
2676 runtime = Runtime.getRuntime();
2678 while (showMemoryUsage)
2682 maxMemory = runtime.maxMemory() / ONE_MB;
2683 allocatedMemory = runtime.totalMemory() / ONE_MB;
2684 freeMemory = runtime.freeMemory() / ONE_MB;
2685 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2687 percentUsage = (totalFreeMemory / maxMemory) * 100;
2689 // if (percentUsage < 20)
2691 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2693 // instance.set.setBorder(border1);
2696 // sleep after showing usage
2698 } catch (Exception ex)
2700 ex.printStackTrace();
2706 public void paintComponent(Graphics g)
2708 if (showMemoryUsage && g != null && df != null)
2710 if (percentUsage < 20)
2712 g.setColor(Color.red);
2714 FontMetrics fm = g.getFontMetrics();
2717 g.drawString(MessageManager.formatMessage("label.memory_stats",
2719 { df.format(totalFreeMemory), df.format(maxMemory),
2720 df.format(percentUsage) }),
2721 10, getHeight() - fm.getHeight());
2728 * Accessor method to quickly get all the AlignmentFrames loaded.
2730 * @return an array of AlignFrame, or null if none found
2732 public static AlignFrame[] getAlignFrames()
2734 if (Jalview.isHeadlessMode())
2736 // Desktop.desktop is null in headless mode
2737 return new AlignFrame[] { Jalview.currentAlignFrame };
2740 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2746 List<AlignFrame> avp = new ArrayList<>();
2748 for (int i = frames.length - 1; i > -1; i--)
2750 if (frames[i] instanceof AlignFrame)
2752 avp.add((AlignFrame) frames[i]);
2754 else if (frames[i] instanceof SplitFrame)
2757 * Also check for a split frame containing an AlignFrame
2759 GSplitFrame sf = (GSplitFrame) frames[i];
2760 if (sf.getTopFrame() instanceof AlignFrame)
2762 avp.add((AlignFrame) sf.getTopFrame());
2764 if (sf.getBottomFrame() instanceof AlignFrame)
2766 avp.add((AlignFrame) sf.getBottomFrame());
2770 if (avp.size() == 0)
2774 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2779 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2783 public GStructureViewer[] getJmols()
2785 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2791 List<GStructureViewer> avp = new ArrayList<>();
2793 for (int i = frames.length - 1; i > -1; i--)
2795 if (frames[i] instanceof AppJmol)
2797 GStructureViewer af = (GStructureViewer) frames[i];
2801 if (avp.size() == 0)
2805 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2810 * Add Groovy Support to Jalview
2813 public void groovyShell_actionPerformed()
2817 openGroovyConsole();
2818 } catch (Exception ex)
2820 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2821 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2823 MessageManager.getString("label.couldnt_create_groovy_shell"),
2824 MessageManager.getString("label.groovy_support_failed"),
2825 JvOptionPane.ERROR_MESSAGE);
2830 * Open the Groovy console
2832 void openGroovyConsole()
2834 if (groovyConsole == null)
2836 groovyConsole = new groovy.ui.Console();
2837 groovyConsole.setVariable("Jalview", this);
2838 groovyConsole.run();
2841 * We allow only one console at a time, so that AlignFrame menu option
2842 * 'Calculate | Run Groovy script' is unambiguous.
2843 * Disable 'Groovy Console', and enable 'Run script', when the console is
2844 * opened, and the reverse when it is closed
2846 Window window = (Window) groovyConsole.getFrame();
2847 window.addWindowListener(new WindowAdapter()
2850 public void windowClosed(WindowEvent e)
2853 * rebind CMD-Q from Groovy Console to Jalview Quit
2856 enableExecuteGroovy(false);
2862 * show Groovy console window (after close and reopen)
2864 ((Window) groovyConsole.getFrame()).setVisible(true);
2867 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2868 * and disable opening a second console
2870 enableExecuteGroovy(true);
2874 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2875 * binding when opened
2877 protected void addQuitHandler()
2879 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2880 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2881 Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()),
2883 getRootPane().getActionMap().put("Quit", new AbstractAction()
2886 public void actionPerformed(ActionEvent e)
2894 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2897 * true if Groovy console is open
2899 public void enableExecuteGroovy(boolean enabled)
2902 * disable opening a second Groovy console
2903 * (or re-enable when the console is closed)
2905 groovyShell.setEnabled(!enabled);
2907 AlignFrame[] alignFrames = getAlignFrames();
2908 if (alignFrames != null)
2910 for (AlignFrame af : alignFrames)
2912 af.setGroovyEnabled(enabled);
2918 * Progress bars managed by the IProgressIndicator method.
2920 private Hashtable<Long, JPanel> progressBars;
2922 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2927 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2930 public void setProgressBar(String message, long id)
2932 if (progressBars == null)
2934 progressBars = new Hashtable<>();
2935 progressBarHandlers = new Hashtable<>();
2938 if (progressBars.get(Long.valueOf(id)) != null)
2940 JPanel panel = progressBars.remove(Long.valueOf(id));
2941 if (progressBarHandlers.contains(Long.valueOf(id)))
2943 progressBarHandlers.remove(Long.valueOf(id));
2945 removeProgressPanel(panel);
2949 progressBars.put(Long.valueOf(id), addProgressPanel(message));
2956 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2957 * jalview.gui.IProgressIndicatorHandler)
2960 public void registerHandler(final long id,
2961 final IProgressIndicatorHandler handler)
2963 if (progressBarHandlers == null
2964 || !progressBars.containsKey(Long.valueOf(id)))
2966 throw new Error(MessageManager.getString(
2967 "error.call_setprogressbar_before_registering_handler"));
2969 progressBarHandlers.put(Long.valueOf(id), handler);
2970 final JPanel progressPanel = progressBars.get(Long.valueOf(id));
2971 if (handler.canCancel())
2973 JButton cancel = new JButton(
2974 MessageManager.getString("action.cancel"));
2975 final IProgressIndicator us = this;
2976 cancel.addActionListener(new ActionListener()
2980 public void actionPerformed(ActionEvent e)
2982 handler.cancelActivity(id);
2983 us.setProgressBar(MessageManager
2984 .formatMessage("label.cancelled_params", new Object[]
2985 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2989 progressPanel.add(cancel, BorderLayout.EAST);
2995 * @return true if any progress bars are still active
2998 public boolean operationInProgress()
3000 if (progressBars != null && progressBars.size() > 0)
3008 * This will return the first AlignFrame holding the given viewport instance.
3009 * It will break if there are more than one AlignFrames viewing a particular
3013 * @return alignFrame for viewport
3015 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
3017 if (desktop != null)
3019 AlignmentPanel[] aps = getAlignmentPanels(
3020 viewport.getSequenceSetId());
3021 for (int panel = 0; aps != null && panel < aps.length; panel++)
3023 if (aps[panel] != null && aps[panel].av == viewport)
3025 return aps[panel].alignFrame;
3032 public VamsasApplication getVamsasApplication()
3039 * flag set if jalview GUI is being operated programmatically
3041 private boolean inBatchMode = false;
3044 * check if jalview GUI is being operated programmatically
3046 * @return inBatchMode
3048 public boolean isInBatchMode()
3054 * set flag if jalview GUI is being operated programmatically
3056 * @param inBatchMode
3058 public void setInBatchMode(boolean inBatchMode)
3060 this.inBatchMode = inBatchMode;
3063 public void startServiceDiscovery()
3065 startServiceDiscovery(false);
3068 public void startServiceDiscovery(boolean blocking)
3070 boolean alive = true;
3071 Thread t0 = null, t1 = null, t2 = null;
3072 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3075 // todo: changesupport handlers need to be transferred
3076 if (discoverer == null)
3078 discoverer = new jalview.ws.jws1.Discoverer();
3079 // register PCS handler for desktop.
3080 discoverer.addPropertyChangeListener(changeSupport);
3082 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3083 // until we phase out completely
3084 (t0 = new Thread(discoverer)).start();
3087 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3089 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3090 .startDiscoverer(changeSupport);
3094 // TODO: do rest service discovery
3103 } catch (Exception e)
3106 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3107 || (t3 != null && t3.isAlive())
3108 || (t0 != null && t0.isAlive());
3114 * called to check if the service discovery process completed successfully.
3118 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3120 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3122 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3123 .getErrorMessages();
3126 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3128 if (serviceChangedDialog == null)
3130 // only run if we aren't already displaying one of these.
3131 addDialogThread(serviceChangedDialog = new Runnable()
3138 * JalviewDialog jd =new JalviewDialog() {
3140 * @Override protected void cancelPressed() { // TODO
3141 * Auto-generated method stub
3143 * }@Override protected void okPressed() { // TODO
3144 * Auto-generated method stub
3146 * }@Override protected void raiseClosed() { // TODO
3147 * Auto-generated method stub
3149 * } }; jd.initDialogFrame(new
3150 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3151 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3152 * + " or mis-configured HTTP proxy settings.<br/>" +
3153 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3155 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3156 * ), true, true, "Web Service Configuration Problem", 450,
3159 * jd.waitForInput();
3161 JvOptionPane.showConfirmDialog(Desktop.desktop,
3162 new JLabel("<html><table width=\"450\"><tr><td>"
3163 + ermsg + "</td></tr></table>"
3164 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3165 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3166 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3167 + " Tools->Preferences dialog box to change them.</p></html>"),
3168 "Web Service Configuration Problem",
3169 JvOptionPane.DEFAULT_OPTION,
3170 JvOptionPane.ERROR_MESSAGE);
3171 serviceChangedDialog = null;
3180 "Errors reported by JABA discovery service. Check web services preferences.\n"
3187 private Runnable serviceChangedDialog = null;
3190 * start a thread to open a URL in the configured browser. Pops up a warning
3191 * dialog to the user if there is an exception when calling out to the browser
3196 public static void showUrl(final String url)
3198 showUrl(url, Desktop.instance);
3202 * Like showUrl but allows progress handler to be specified
3206 * (null) or object implementing IProgressIndicator
3208 public static void showUrl(final String url,
3209 final IProgressIndicator progress)
3211 new Thread(new Runnable()
3218 if (progress != null)
3220 progress.setProgressBar(MessageManager
3221 .formatMessage("status.opening_params", new Object[]
3222 { url }), this.hashCode());
3224 jalview.util.BrowserLauncher.openURL(url);
3225 } catch (Exception ex)
3227 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3229 .getString("label.web_browser_not_found_unix"),
3230 MessageManager.getString("label.web_browser_not_found"),
3231 JvOptionPane.WARNING_MESSAGE);
3233 ex.printStackTrace();
3235 if (progress != null)
3237 progress.setProgressBar(null, this.hashCode());
3243 public static WsParamSetManager wsparamManager = null;
3245 public static ParamManager getUserParameterStore()
3247 if (wsparamManager == null)
3249 wsparamManager = new WsParamSetManager();
3251 return wsparamManager;
3255 * static hyperlink handler proxy method for use by Jalview's internal windows
3259 public static void hyperlinkUpdate(HyperlinkEvent e)
3261 if (e.getEventType() == EventType.ACTIVATED)
3266 url = e.getURL().toString();
3267 Desktop.showUrl(url);
3268 } catch (Exception x)
3272 if (Cache.log != null)
3274 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3279 "Couldn't handle string " + url + " as a URL.");
3282 // ignore any exceptions due to dud links.
3289 * single thread that handles display of dialogs to user.
3291 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3294 * flag indicating if dialogExecutor should try to acquire a permit
3296 private volatile boolean dialogPause = true;
3301 private java.util.concurrent.Semaphore block = new Semaphore(0);
3303 private static groovy.ui.Console groovyConsole;
3306 * add another dialog thread to the queue
3310 public void addDialogThread(final Runnable prompter)
3312 dialogExecutor.submit(new Runnable()
3322 } catch (InterruptedException x)
3327 if (instance == null)
3333 SwingUtilities.invokeAndWait(prompter);
3334 } catch (Exception q)
3336 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3342 public void startDialogQueue()
3344 // set the flag so we don't pause waiting for another permit and semaphore
3345 // the current task to begin
3346 dialogPause = false;
3351 protected void snapShotWindow_actionPerformed(ActionEvent e)
3355 ImageMaker im = new jalview.util.ImageMaker(
3356 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3357 getHeight(), of = new File("Jalview_snapshot"
3358 + System.currentTimeMillis() + ".eps"),
3359 "View of desktop", null, 0, false);
3362 paintAll(im.getGraphics());
3364 } catch (Exception q)
3366 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3370 Cache.log.info("Successfully written snapshot to file "
3371 + of.getAbsolutePath());
3375 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3376 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3377 * and location last time the view was expanded (if any). However it does not
3378 * remember the split pane divider location - this is set to match the
3379 * 'exploding' frame.
3383 public void explodeViews(SplitFrame sf)
3385 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3386 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3387 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3389 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3391 int viewCount = topPanels.size();
3398 * Processing in reverse order works, forwards order leaves the first panels
3399 * not visible. I don't know why!
3401 for (int i = viewCount - 1; i >= 0; i--)
3404 * Make new top and bottom frames. These take over the respective
3405 * AlignmentPanel objects, including their AlignmentViewports, so the
3406 * cdna/protein relationships between the viewports is carried over to the
3409 * explodedGeometry holds the (x, y) position of the previously exploded
3410 * SplitFrame, and the (width, height) of the AlignFrame component
3412 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3413 AlignFrame newTopFrame = new AlignFrame(topPanel);
3414 newTopFrame.setSize(oldTopFrame.getSize());
3415 newTopFrame.setVisible(true);
3416 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3417 .getExplodedGeometry();
3418 if (geometry != null)
3420 newTopFrame.setSize(geometry.getSize());
3423 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3424 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3425 newBottomFrame.setSize(oldBottomFrame.getSize());
3426 newBottomFrame.setVisible(true);
3427 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3428 .getExplodedGeometry();
3429 if (geometry != null)
3431 newBottomFrame.setSize(geometry.getSize());
3434 topPanel.av.setGatherViewsHere(false);
3435 bottomPanel.av.setGatherViewsHere(false);
3436 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3438 if (geometry != null)
3440 splitFrame.setLocation(geometry.getLocation());
3442 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3446 * Clear references to the panels (now relocated in the new SplitFrames)
3447 * before closing the old SplitFrame.
3450 bottomPanels.clear();
3455 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3456 * back into the given SplitFrame as additional views. Note that the gathered
3457 * frames may themselves have multiple views.
3461 public void gatherViews(GSplitFrame source)
3464 * special handling of explodedGeometry for a view within a SplitFrame: - it
3465 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3466 * height) of the AlignFrame component
3468 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3469 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3470 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3471 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3472 myBottomFrame.viewport
3473 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3474 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3475 myTopFrame.viewport.setGatherViewsHere(true);
3476 myBottomFrame.viewport.setGatherViewsHere(true);
3477 String topViewId = myTopFrame.viewport.getSequenceSetId();
3478 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3480 JInternalFrame[] frames = desktop.getAllFrames();
3481 for (JInternalFrame frame : frames)
3483 if (frame instanceof SplitFrame && frame != source)
3485 SplitFrame sf = (SplitFrame) frame;
3486 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3487 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3488 boolean gatherThis = false;
3489 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3491 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3492 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3493 if (topViewId.equals(topPanel.av.getSequenceSetId())
3494 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3497 topPanel.av.setGatherViewsHere(false);
3498 bottomPanel.av.setGatherViewsHere(false);
3499 topPanel.av.setExplodedGeometry(
3500 new Rectangle(sf.getLocation(), topFrame.getSize()));
3501 bottomPanel.av.setExplodedGeometry(
3502 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3503 myTopFrame.addAlignmentPanel(topPanel, false);
3504 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3510 topFrame.getAlignPanels().clear();
3511 bottomFrame.getAlignPanels().clear();
3518 * The dust settles...give focus to the tab we did this from.
3520 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3523 public static groovy.ui.Console getGroovyConsole()
3525 return groovyConsole;
3529 * handles the payload of a drag and drop event.
3531 * TODO refactor to desktop utilities class
3534 * - Data source strings extracted from the drop event
3536 * - protocol for each data source extracted from the drop event
3540 * - the payload from the drop event
3543 public static void transferFromDropTarget(List<String> files,
3544 List<DataSourceType> protocols, DropTargetDropEvent evt,
3545 Transferable t) throws Exception
3548 DataFlavor uriListFlavor = new DataFlavor(
3549 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3552 urlFlavour = new DataFlavor(
3553 "application/x-java-url; class=java.net.URL");
3554 } catch (ClassNotFoundException cfe)
3556 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3559 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3564 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3565 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3566 // means url may be null.
3569 protocols.add(DataSourceType.URL);
3570 files.add(url.toString());
3571 Cache.log.debug("Drop handled as URL dataflavor "
3572 + files.get(files.size() - 1));
3577 if (Platform.isAMac())
3580 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3584 } catch (Throwable ex)
3586 Cache.log.debug("URL drop handler failed.", ex);
3589 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3591 // Works on Windows and MacOSX
3592 Cache.log.debug("Drop handled as javaFileListFlavor");
3593 for (Object file : (List) t
3594 .getTransferData(DataFlavor.javaFileListFlavor))
3596 files.add(((File) file).toString());
3597 protocols.add(DataSourceType.FILE);
3602 // Unix like behaviour
3603 boolean added = false;
3605 if (t.isDataFlavorSupported(uriListFlavor))
3607 Cache.log.debug("Drop handled as uriListFlavor");
3608 // This is used by Unix drag system
3609 data = (String) t.getTransferData(uriListFlavor);
3613 // fallback to text: workaround - on OSX where there's a JVM bug
3614 Cache.log.debug("standard URIListFlavor failed. Trying text");
3615 // try text fallback
3616 DataFlavor textDf = new DataFlavor(
3617 "text/plain;class=java.lang.String");
3618 if (t.isDataFlavorSupported(textDf))
3620 data = (String) t.getTransferData(textDf);
3623 Cache.log.debug("Plain text drop content returned "
3624 + (data == null ? "Null - failed" : data));
3629 while (protocols.size() < files.size())
3631 Cache.log.debug("Adding missing FILE protocol for "
3632 + files.get(protocols.size()));
3633 protocols.add(DataSourceType.FILE);
3635 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3636 data, "\r\n"); st.hasMoreTokens();)
3639 String s = st.nextToken();
3640 if (s.startsWith("#"))
3642 // the line is a comment (as per the RFC 2483)
3645 java.net.URI uri = new java.net.URI(s);
3646 if (uri.getScheme().toLowerCase().startsWith("http"))
3648 protocols.add(DataSourceType.URL);
3649 files.add(uri.toString());
3653 // otherwise preserve old behaviour: catch all for file objects
3654 java.io.File file = new java.io.File(uri);
3655 protocols.add(DataSourceType.FILE);
3656 files.add(file.toString());
3661 if (Cache.log.isDebugEnabled())
3663 if (data == null || !added)
3666 if (t.getTransferDataFlavors() != null
3667 && t.getTransferDataFlavors().length > 0)
3670 "Couldn't resolve drop data. Here are the supported flavors:");
3671 for (DataFlavor fl : t.getTransferDataFlavors())
3674 "Supported transfer dataflavor: " + fl.toString());
3675 Object df = t.getTransferData(fl);
3678 Cache.log.debug("Retrieves: " + df);
3682 Cache.log.debug("Retrieved nothing");
3688 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3694 if (Platform.isWindows())
3697 Cache.log.debug("Scanning dropped content for Windows Link Files");
3699 // resolve any .lnk files in the file drop
3700 for (int f = 0; f < files.size(); f++)
3702 String source = files.get(f).toLowerCase();
3703 if (protocols.get(f).equals(DataSourceType.FILE)
3704 && (source.endsWith(".lnk") || source.endsWith(".url")
3705 || source.endsWith(".site")))
3709 File lf = new File(files.get(f));
3710 // process link file to get a URL
3711 Cache.log.debug("Found potential link file: " + lf);
3712 WindowsShortcut wscfile = new WindowsShortcut(lf);
3713 String fullname = wscfile.getRealFilename();
3714 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3715 files.set(f, fullname);
3716 Cache.log.debug("Parsed real filename " + fullname
3717 + " to extract protocol: " + protocols.get(f));
3718 } catch (Exception ex)
3721 "Couldn't parse " + files.get(f) + " as a link file.",
3730 * Sets the Preferences property for experimental features to True or False
3731 * depending on the state of the controlling menu item
3734 protected void showExperimental_actionPerformed(boolean selected)
3736 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3740 * Answers a (possibly empty) list of any structure viewer frames (currently
3741 * for either Jmol or Chimera) which are currently open. This may optionally
3742 * be restricted to viewers of a specified class, or viewers linked to a
3743 * specified alignment panel.
3746 * if not null, only return viewers linked to this panel
3747 * @param structureViewerClass
3748 * if not null, only return viewers of this class
3751 public List<StructureViewerBase> getStructureViewers(
3752 AlignmentPanel apanel,
3753 Class<? extends StructureViewerBase> structureViewerClass)
3755 List<StructureViewerBase> result = new ArrayList<>();
3756 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3758 for (JInternalFrame frame : frames)
3760 if (frame instanceof StructureViewerBase)
3762 if (structureViewerClass == null
3763 || structureViewerClass.isInstance(frame))
3766 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3768 result.add((StructureViewerBase) frame);