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")
557 + (jalview.bin.Cache.getProperty("VERSION").equals("DEVELOPMENT")
559 + System.getProperty(
561 + File.separator + "bin"
562 + File.separator + "java"
566 showConsole(showjconsole);
568 showNews.setVisible(false);
570 experimentalFeatures.setSelected(showExperimental());
572 getIdentifiersOrgData();
576 this.addWindowListener(new WindowAdapter()
579 public void windowClosing(WindowEvent evt)
586 this.addMouseListener(ma = new MouseAdapter()
589 public void mousePressed(MouseEvent evt)
591 if (evt.isPopupTrigger()) // Mac
593 showPasteMenu(evt.getX(), evt.getY());
598 public void mouseReleased(MouseEvent evt)
600 if (evt.isPopupTrigger()) // Windows
602 showPasteMenu(evt.getX(), evt.getY());
606 desktop.addMouseListener(ma);
608 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
609 // Spawn a thread that shows the splashscreen
610 SwingUtilities.invokeLater(new Runnable()
619 // Thread off a new instance of the file chooser - this reduces the time it
620 // takes to open it later on.
621 new Thread(new Runnable()
626 Cache.log.debug("Filechooser init thread started.");
627 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
628 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
630 Cache.log.debug("Filechooser init thread finished.");
633 // Add the service change listener
634 changeSupport.addJalviewPropertyChangeListener("services",
635 new PropertyChangeListener()
639 public void propertyChange(PropertyChangeEvent evt)
641 Cache.log.debug("Firing service changed event for "
642 + evt.getNewValue());
643 JalviewServicesChanged(evt);
650 * Answers true if user preferences to enable experimental features is True
655 public boolean showExperimental()
657 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
658 Boolean.FALSE.toString());
659 return Boolean.valueOf(experimental).booleanValue();
662 public void doConfigureStructurePrefs()
664 // configure services
665 StructureSelectionManager ssm = StructureSelectionManager
666 .getStructureSelectionManager(this);
667 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
669 ssm.setAddTempFacAnnot(jalview.bin.Cache
670 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
671 ssm.setProcessSecondaryStructure(jalview.bin.Cache
672 .getDefault(Preferences.STRUCT_FROM_PDB, true));
673 ssm.setSecStructServices(
674 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
678 ssm.setAddTempFacAnnot(false);
679 ssm.setProcessSecondaryStructure(false);
680 ssm.setSecStructServices(false);
684 public void checkForNews()
686 final Desktop me = this;
687 // Thread off the news reader, in case there are connection problems.
688 new Thread(new Runnable()
693 Cache.log.debug("Starting news thread.");
695 jvnews = new BlogReader(me);
696 showNews.setVisible(true);
697 Cache.log.debug("Completed news thread.");
702 public void getIdentifiersOrgData()
704 // Thread off the identifiers fetcher
705 new Thread(new Runnable()
710 Cache.log.debug("Downloading data from identifiers.org");
711 UrlDownloadClient client = new UrlDownloadClient();
714 client.download(IdOrgSettings.getUrl(),
715 IdOrgSettings.getDownloadLocation());
716 } catch (IOException e)
718 Cache.log.debug("Exception downloading identifiers.org data"
727 protected void showNews_actionPerformed(ActionEvent e)
729 showNews(showNews.isSelected());
732 void showNews(boolean visible)
735 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
736 showNews.setSelected(visible);
737 if (visible && !jvnews.isVisible())
739 new Thread(new Runnable()
744 long now = System.currentTimeMillis();
745 Desktop.instance.setProgressBar(
746 MessageManager.getString("status.refreshing_news"),
748 jvnews.refreshNews();
749 Desktop.instance.setProgressBar(null, now);
758 * recover the last known dimensions for a jalview window
761 * - empty string is desktop, all other windows have unique prefix
762 * @return null or last known dimensions scaled to current geometry (if last
763 * window geom was known)
765 Rectangle getLastKnownDimensions(String windowName)
767 // TODO: lock aspect ratio for scaling desktop Bug #0058199
768 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
769 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
770 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
771 String width = jalview.bin.Cache
772 .getProperty(windowName + "SCREEN_WIDTH");
773 String height = jalview.bin.Cache
774 .getProperty(windowName + "SCREEN_HEIGHT");
775 if ((x != null) && (y != null) && (width != null) && (height != null))
777 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
778 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
779 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
781 // attempt #1 - try to cope with change in screen geometry - this
782 // version doesn't preserve original jv aspect ratio.
783 // take ratio of current screen size vs original screen size.
784 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
785 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
786 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
787 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
788 // rescale the bounds depending upon the current screen geometry.
789 ix = (int) (ix * sw);
790 iw = (int) (iw * sw);
791 iy = (int) (iy * sh);
792 ih = (int) (ih * sh);
793 while (ix >= screenSize.width)
795 jalview.bin.Cache.log.debug(
796 "Window geometry location recall error: shifting horizontal to within screenbounds.");
797 ix -= screenSize.width;
799 while (iy >= screenSize.height)
801 jalview.bin.Cache.log.debug(
802 "Window geometry location recall error: shifting vertical to within screenbounds.");
803 iy -= screenSize.height;
805 jalview.bin.Cache.log.debug(
806 "Got last known dimensions for " + windowName + ": x:" + ix
807 + " y:" + iy + " width:" + iw + " height:" + ih);
809 // return dimensions for new instance
810 return new Rectangle(ix, iy, iw, ih);
815 private void doVamsasClientCheck()
817 if (jalview.bin.Cache.vamsasJarsPresent())
819 setupVamsasDisconnectedGui();
820 VamsasMenu.setVisible(true);
821 final Desktop us = this;
822 VamsasMenu.addMenuListener(new MenuListener()
824 // this listener remembers when the menu was first selected, and
825 // doesn't rebuild the session list until it has been cleared and
827 boolean refresh = true;
830 public void menuCanceled(MenuEvent e)
836 public void menuDeselected(MenuEvent e)
842 public void menuSelected(MenuEvent e)
846 us.buildVamsasStMenu();
851 vamsasStart.setVisible(true);
855 void showPasteMenu(int x, int y)
857 JPopupMenu popup = new JPopupMenu();
858 JMenuItem item = new JMenuItem(
859 MessageManager.getString("label.paste_new_window"));
860 item.addActionListener(new ActionListener()
863 public void actionPerformed(ActionEvent evt)
870 popup.show(this, x, y);
877 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
878 Transferable contents = c.getContents(this);
880 if (contents != null)
882 String file = (String) contents
883 .getTransferData(DataFlavor.stringFlavor);
885 FileFormatI format = new IdentifyFile().identify(file,
886 DataSourceType.PASTE);
888 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
891 } catch (Exception ex)
894 "Unable to paste alignment from system clipboard:\n" + ex);
899 * Adds and opens the given frame to the desktop
910 public static synchronized void addInternalFrame(
911 final JInternalFrame frame, String title, int w, int h)
913 addInternalFrame(frame, title, true, w, h, true, false);
917 * Add an internal frame to the Jalview desktop
924 * When true, display frame immediately, otherwise, caller must call
925 * setVisible themselves.
931 public static synchronized void addInternalFrame(
932 final JInternalFrame frame, String title, boolean makeVisible,
935 addInternalFrame(frame, title, makeVisible, w, h, true, false);
939 * Add an internal frame to the Jalview desktop and make it visible
952 public static synchronized void addInternalFrame(
953 final JInternalFrame frame, String title, int w, int h,
956 addInternalFrame(frame, title, true, w, h, resizable, false);
960 * Add an internal frame to the Jalview desktop
967 * When true, display frame immediately, otherwise, caller must call
968 * setVisible themselves.
975 * @param ignoreMinSize
976 * Do not set the default minimum size for frame
978 public static synchronized void addInternalFrame(
979 final JInternalFrame frame, String title, boolean makeVisible,
980 int w, int h, boolean resizable, boolean ignoreMinSize)
983 // TODO: allow callers to determine X and Y position of frame (eg. via
985 // TODO: consider fixing method to update entries in the window submenu with
986 // the current window title
988 frame.setTitle(title);
989 if (frame.getWidth() < 1 || frame.getHeight() < 1)
993 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
994 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
995 // IF JALVIEW IS RUNNING HEADLESS
996 // ///////////////////////////////////////////////
997 if (instance == null || (System.getProperty("java.awt.headless") != null
998 && System.getProperty("java.awt.headless").equals("true")))
1007 frame.setMinimumSize(
1008 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
1010 // Set default dimension for Alignment Frame window.
1011 // The Alignment Frame window could be added from a number of places,
1013 // I did this here in order not to miss out on any Alignment frame.
1014 if (frame instanceof AlignFrame)
1016 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
1017 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
1021 frame.setVisible(makeVisible);
1022 frame.setClosable(true);
1023 frame.setResizable(resizable);
1024 frame.setMaximizable(resizable);
1025 frame.setIconifiable(resizable);
1026 frame.setOpaque(false);
1028 if (frame.getX() < 1 && frame.getY() < 1)
1030 frame.setLocation(xOffset * openFrameCount,
1031 yOffset * ((openFrameCount - 1) % 10) + yOffset);
1035 * add an entry for the new frame in the Window menu
1036 * (and remove it when the frame is closed)
1038 final JMenuItem menuItem = new JMenuItem(title);
1039 frame.addInternalFrameListener(new InternalFrameAdapter()
1042 public void internalFrameActivated(InternalFrameEvent evt)
1044 JInternalFrame itf = desktop.getSelectedFrame();
1047 if (itf instanceof AlignFrame)
1049 Jalview.setCurrentAlignFrame((AlignFrame) itf);
1056 public void internalFrameClosed(InternalFrameEvent evt)
1058 PaintRefresher.RemoveComponent(frame);
1061 * defensive check to prevent frames being
1062 * added half off the window
1064 if (openFrameCount > 0)
1070 * ensure no reference to alignFrame retained by menu item listener
1072 if (menuItem.getActionListeners().length > 0)
1074 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
1076 windowMenu.remove(menuItem);
1080 menuItem.addActionListener(new ActionListener()
1083 public void actionPerformed(ActionEvent e)
1087 frame.setSelected(true);
1088 frame.setIcon(false);
1089 } catch (java.beans.PropertyVetoException ex)
1096 setKeyBindings(frame);
1100 windowMenu.add(menuItem);
1105 frame.setSelected(true);
1106 frame.requestFocus();
1107 } catch (java.beans.PropertyVetoException ve)
1109 } catch (java.lang.ClassCastException cex)
1112 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
1118 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
1123 private static void setKeyBindings(JInternalFrame frame)
1125 @SuppressWarnings("serial")
1126 final Action closeAction = new AbstractAction()
1129 public void actionPerformed(ActionEvent e)
1136 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1138 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1139 InputEvent.CTRL_DOWN_MASK);
1140 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1141 Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx());
1143 InputMap inputMap = frame
1144 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1145 String ctrlW = ctrlWKey.toString();
1146 inputMap.put(ctrlWKey, ctrlW);
1147 inputMap.put(cmdWKey, ctrlW);
1149 ActionMap actionMap = frame.getActionMap();
1150 actionMap.put(ctrlW, closeAction);
1154 public void lostOwnership(Clipboard clipboard, Transferable contents)
1158 Desktop.jalviewClipboard = null;
1161 internalCopy = false;
1165 public void dragEnter(DropTargetDragEvent evt)
1170 public void dragExit(DropTargetEvent evt)
1175 public void dragOver(DropTargetDragEvent evt)
1180 public void dropActionChanged(DropTargetDragEvent evt)
1191 public void drop(DropTargetDropEvent evt)
1193 boolean success = true;
1194 // JAL-1552 - acceptDrop required before getTransferable call for
1195 // Java's Transferable for native dnd
1196 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1197 Transferable t = evt.getTransferable();
1198 List<String> files = new ArrayList<>();
1199 List<DataSourceType> protocols = new ArrayList<>();
1203 Desktop.transferFromDropTarget(files, protocols, evt, t);
1204 } catch (Exception e)
1206 e.printStackTrace();
1214 for (int i = 0; i < files.size(); i++)
1216 String file = files.get(i).toString();
1217 DataSourceType protocol = (protocols == null)
1218 ? DataSourceType.FILE
1220 FileFormatI format = null;
1222 if (file.endsWith(".jar"))
1224 format = FileFormat.Jalview;
1229 format = new IdentifyFile().identify(file, protocol);
1232 new FileLoader().LoadFile(file, protocol, format);
1235 } catch (Exception ex)
1240 evt.dropComplete(success); // need this to ensure input focus is properly
1241 // transfered to any new windows created
1251 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1253 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1254 JalviewFileChooser chooser = JalviewFileChooser
1255 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, true);
1257 chooser.setFileView(new JalviewFileView());
1258 chooser.setDialogTitle(
1259 MessageManager.getString("label.open_local_file"));
1260 chooser.setToolTipText(MessageManager.getString("action.open"));
1262 int value = chooser.showOpenDialog(this);
1264 if (value == JalviewFileChooser.APPROVE_OPTION)
1266 String choice = chooser.getSelectedFile().getPath();
1267 Cache.setProperty("LAST_DIRECTORY",
1268 chooser.getSelectedFile().getParent());
1270 FileFormatI format = chooser.getSelectedFormat();
1273 * Call IdentifyFile to verify the file contains what its extension implies.
1274 * Skip this step for dynamically added file formats, because
1275 * IdentifyFile does not know how to recognise them.
1277 if (FileFormats.getInstance().isIdentifiable(format))
1281 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1282 } catch (FileFormatException e)
1284 // format = null; //??
1288 if (viewport != null)
1290 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1295 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1307 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1309 // This construct allows us to have a wider textfield
1311 JLabel label = new JLabel(
1312 MessageManager.getString("label.input_file_url"));
1313 final JComboBox history = new JComboBox();
1315 JPanel panel = new JPanel(new GridLayout(2, 1));
1318 history.setPreferredSize(new Dimension(400, 20));
1319 history.setEditable(true);
1320 history.addItem("http://www.");
1322 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1326 if (historyItems != null)
1328 st = new StringTokenizer(historyItems, "\t");
1330 while (st.hasMoreTokens())
1332 history.addItem(st.nextElement());
1336 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1337 MessageManager.getString("label.input_alignment_from_url"),
1338 JvOptionPane.OK_CANCEL_OPTION);
1340 if (reply != JvOptionPane.OK_OPTION)
1345 String url = history.getSelectedItem().toString();
1347 if (url.toLowerCase().endsWith(".jar"))
1349 if (viewport != null)
1351 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1352 FileFormat.Jalview);
1356 new FileLoader().LoadFile(url, DataSourceType.URL,
1357 FileFormat.Jalview);
1362 FileFormatI format = null;
1365 format = new IdentifyFile().identify(url, DataSourceType.URL);
1366 } catch (FileFormatException e)
1368 // TODO revise error handling, distinguish between
1369 // URL not found and response not valid
1374 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1375 MessageManager.formatMessage("label.couldnt_locate",
1378 MessageManager.getString("label.url_not_found"),
1379 JvOptionPane.WARNING_MESSAGE);
1384 if (viewport != null)
1386 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1391 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1397 * Opens the CutAndPaste window for the user to paste an alignment in to
1400 * - if not null, the pasted alignment is added to the current
1401 * alignment; if null, to a new alignment window
1404 public void inputTextboxMenuItem_actionPerformed(
1405 AlignmentViewPanel viewPanel)
1407 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1408 cap.setForInput(viewPanel);
1409 Desktop.addInternalFrame(cap,
1410 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1420 //System.out.println("********** Desktop.quit()");
1421 //System.out.println(savingFiles.toString());
1422 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1423 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1425 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1426 screen.height + "");
1427 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1428 getWidth(), getHeight()));
1430 if (jconsole != null)
1432 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1433 jconsole.stopConsole();
1437 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1440 if (dialogExecutor != null)
1442 dialogExecutor.shutdownNow();
1444 closeAll_actionPerformed(null);
1446 if (groovyConsole != null)
1448 // suppress a possible repeat prompt to save script
1449 groovyConsole.setDirty(false);
1450 groovyConsole.exit();
1455 private void storeLastKnownDimensions(String string, Rectangle jc)
1457 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1458 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1459 + " height:" + jc.height);
1461 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1462 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1463 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1464 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1474 public void aboutMenuItem_actionPerformed(ActionEvent e)
1476 // StringBuffer message = getAboutMessage(false);
1477 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1479 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1480 new Thread(new Runnable()
1485 new SplashScreen(true);
1490 public StringBuffer getAboutMessage(boolean shortv)
1492 StringBuffer message = new StringBuffer();
1493 message.append("<html>");
1496 message.append("<h1><strong>Version: "
1497 + jalview.bin.Cache.getProperty("VERSION")
1498 + "</strong></h1>");
1499 message.append("<strong>Last Updated: <em>"
1500 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1501 + "</em></strong>");
1507 message.append("<strong>Version "
1508 + jalview.bin.Cache.getProperty("VERSION")
1509 + "; last updated: "
1510 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1513 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1514 .equals("Checking"))
1516 message.append("<br>...Checking latest version...</br>");
1518 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1519 .equals(jalview.bin.Cache.getProperty("VERSION")))
1521 boolean red = false;
1522 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1523 .indexOf("automated build") == -1)
1526 // Displayed when code version and jnlp version do not match and code
1527 // version is not a development build
1528 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1531 message.append("<br>!! Version "
1532 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1534 + " is available for download from "
1535 + jalview.bin.Cache.getDefault("www.jalview.org",
1536 "http://www.jalview.org")
1540 message.append("</div>");
1543 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1545 "The Jalview Authors (See AUTHORS file for current list)")
1546 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1547 + "<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"
1548 + "<br><br>If you use Jalview, please cite:"
1549 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1550 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1551 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1563 public void documentationMenuItem_actionPerformed(ActionEvent e)
1567 Help.showHelpWindow();
1568 } catch (Exception ex)
1574 public void closeAll_actionPerformed(ActionEvent e)
1576 // TODO show a progress bar while closing?
1577 JInternalFrame[] frames = desktop.getAllFrames();
1578 for (int i = 0; i < frames.length; i++)
1582 frames[i].setClosed(true);
1583 } catch (java.beans.PropertyVetoException ex)
1587 Jalview.setCurrentAlignFrame(null);
1588 System.out.println("ALL CLOSED");
1589 if (v_client != null)
1591 // TODO clear binding to vamsas document objects on close_all
1595 * reset state of singleton objects as appropriate (clear down session state
1596 * when all windows are closed)
1598 StructureSelectionManager ssm = StructureSelectionManager
1599 .getStructureSelectionManager(this);
1607 public void raiseRelated_actionPerformed(ActionEvent e)
1609 reorderAssociatedWindows(false, false);
1613 public void minimizeAssociated_actionPerformed(ActionEvent e)
1615 reorderAssociatedWindows(true, false);
1618 void closeAssociatedWindows()
1620 reorderAssociatedWindows(false, true);
1626 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1630 protected void garbageCollect_actionPerformed(ActionEvent e)
1632 // We simply collect the garbage
1633 jalview.bin.Cache.log.debug("Collecting garbage...");
1635 jalview.bin.Cache.log.debug("Finished garbage collection.");
1642 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1646 protected void showMemusage_actionPerformed(ActionEvent e)
1648 desktop.showMemoryUsage(showMemusage.isSelected());
1655 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1659 protected void showConsole_actionPerformed(ActionEvent e)
1661 showConsole(showConsole.isSelected());
1664 Console jconsole = null;
1667 * control whether the java console is visible or not
1671 void showConsole(boolean selected)
1673 showConsole.setSelected(selected);
1674 // TODO: decide if we should update properties file
1675 Cache.setProperty("SHOW_JAVA_CONSOLE",
1676 Boolean.valueOf(selected).toString());
1677 jconsole.setVisible(selected);
1680 void reorderAssociatedWindows(boolean minimize, boolean close)
1682 JInternalFrame[] frames = desktop.getAllFrames();
1683 if (frames == null || frames.length < 1)
1688 AlignmentViewport source = null, target = null;
1689 if (frames[0] instanceof AlignFrame)
1691 source = ((AlignFrame) frames[0]).getCurrentView();
1693 else if (frames[0] instanceof TreePanel)
1695 source = ((TreePanel) frames[0]).getViewPort();
1697 else if (frames[0] instanceof PCAPanel)
1699 source = ((PCAPanel) frames[0]).av;
1701 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1703 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1708 for (int i = 0; i < frames.length; i++)
1711 if (frames[i] == null)
1715 if (frames[i] instanceof AlignFrame)
1717 target = ((AlignFrame) frames[i]).getCurrentView();
1719 else if (frames[i] instanceof TreePanel)
1721 target = ((TreePanel) frames[i]).getViewPort();
1723 else if (frames[i] instanceof PCAPanel)
1725 target = ((PCAPanel) frames[i]).av;
1727 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1729 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1732 if (source == target)
1738 frames[i].setClosed(true);
1742 frames[i].setIcon(minimize);
1745 frames[i].toFront();
1749 } catch (java.beans.PropertyVetoException ex)
1764 protected void preferences_actionPerformed(ActionEvent e)
1770 * Shows a file chooser dialog and writes out the current session as a Jalview
1774 public void saveState_actionPerformed()
1776 saveState_actionPerformed(false);
1779 public void saveState_actionPerformed(boolean saveAs)
1781 java.io.File projectFile = getProjectFile();
1782 // autoSave indicates we already have a file and don't need to ask
1783 boolean autoSave = projectFile != null && !saveAs
1784 && BackupFiles.getEnabled();
1786 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1787 // saveAs="+saveAs+", Backups
1788 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1790 boolean approveSave = false;
1793 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1796 chooser.setFileView(new JalviewFileView());
1797 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1799 int value = chooser.showSaveDialog(this);
1801 if (value == JalviewFileChooser.APPROVE_OPTION)
1803 projectFile = chooser.getSelectedFile();
1804 setProjectFile(projectFile);
1809 if (approveSave || autoSave)
1811 final Desktop me = this;
1812 final java.io.File chosenFile = projectFile;
1813 new Thread(new Runnable()
1818 // TODO: refactor to Jalview desktop session controller action.
1819 setProgressBar(MessageManager.formatMessage(
1820 "label.saving_jalview_project", new Object[]
1821 { chosenFile.getName() }), chosenFile.hashCode());
1822 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1823 chosenFile.getParent());
1824 // TODO catch and handle errors for savestate
1825 // TODO prevent user from messing with the Desktop whilst we're saving
1828 BackupFiles backupfiles = new BackupFiles(chosenFile);
1830 new Jalview2XML().saveState(backupfiles.getTempFile());
1832 backupfiles.setWriteSuccess(true);
1833 backupfiles.rollBackupsAndRenameTempFile();
1834 } catch (OutOfMemoryError oom)
1836 new OOMWarning("Whilst saving current state to "
1837 + chosenFile.getName(), oom);
1838 } catch (Exception ex)
1840 Cache.log.error("Problems whilst trying to save to "
1841 + chosenFile.getName(), ex);
1842 JvOptionPane.showMessageDialog(me,
1843 MessageManager.formatMessage(
1844 "label.error_whilst_saving_current_state_to",
1846 { chosenFile.getName() }),
1847 MessageManager.getString("label.couldnt_save_project"),
1848 JvOptionPane.WARNING_MESSAGE);
1850 setProgressBar(null, chosenFile.hashCode());
1857 public void saveAsState_actionPerformed(ActionEvent e)
1859 saveState_actionPerformed(true);
1862 private void setProjectFile(File choice)
1864 this.projectFile = choice;
1867 public File getProjectFile()
1869 return this.projectFile;
1873 * Shows a file chooser dialog and tries to read in the selected file as a
1877 public void loadState_actionPerformed()
1879 final String[] suffix = new String[] { "jvp", "jar" };
1880 final String[] desc = new String[] { "Jalview Project",
1881 "Jalview Project (old)" };
1882 JalviewFileChooser chooser = new JalviewFileChooser(
1883 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1884 "Jalview Project", true, true); // last two booleans: allFiles,
1886 chooser.setFileView(new JalviewFileView());
1887 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1889 int value = chooser.showOpenDialog(this);
1891 if (value == JalviewFileChooser.APPROVE_OPTION)
1893 final File selectedFile = chooser.getSelectedFile();
1894 setProjectFile(selectedFile);
1895 final String choice = selectedFile.getAbsolutePath();
1896 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1897 new Thread(new Runnable()
1902 setProgressBar(MessageManager.formatMessage(
1903 "label.loading_jalview_project", new Object[]
1904 { choice }), choice.hashCode());
1907 new Jalview2XML().loadJalviewAlign(choice);
1908 } catch (OutOfMemoryError oom)
1910 new OOMWarning("Whilst loading project from " + choice, oom);
1911 } catch (Exception ex)
1914 "Problems whilst loading project from " + choice, ex);
1915 JvOptionPane.showMessageDialog(Desktop.desktop,
1916 MessageManager.formatMessage(
1917 "label.error_whilst_loading_project_from",
1920 MessageManager.getString("label.couldnt_load_project"),
1921 JvOptionPane.WARNING_MESSAGE);
1923 setProgressBar(null, choice.hashCode());
1930 public void inputSequence_actionPerformed(ActionEvent e)
1932 new SequenceFetcher(this);
1935 JPanel progressPanel;
1937 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1939 public void startLoading(final String fileName)
1941 if (fileLoadingCount == 0)
1943 fileLoadingPanels.add(addProgressPanel(MessageManager
1944 .formatMessage("label.loading_file", new Object[]
1950 private JPanel addProgressPanel(String string)
1952 if (progressPanel == null)
1954 progressPanel = new JPanel(new GridLayout(1, 1));
1955 totalProgressCount = 0;
1956 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1958 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1959 JProgressBar progressBar = new JProgressBar();
1960 progressBar.setIndeterminate(true);
1962 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1964 thisprogress.add(progressBar, BorderLayout.CENTER);
1965 progressPanel.add(thisprogress);
1966 ((GridLayout) progressPanel.getLayout()).setRows(
1967 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1968 ++totalProgressCount;
1969 instance.validate();
1970 return thisprogress;
1973 int totalProgressCount = 0;
1975 private void removeProgressPanel(JPanel progbar)
1977 if (progressPanel != null)
1979 synchronized (progressPanel)
1981 progressPanel.remove(progbar);
1982 GridLayout gl = (GridLayout) progressPanel.getLayout();
1983 gl.setRows(gl.getRows() - 1);
1984 if (--totalProgressCount < 1)
1986 this.getContentPane().remove(progressPanel);
1987 progressPanel = null;
1994 public void stopLoading()
1997 if (fileLoadingCount < 1)
1999 while (fileLoadingPanels.size() > 0)
2001 removeProgressPanel(fileLoadingPanels.remove(0));
2003 fileLoadingPanels.clear();
2004 fileLoadingCount = 0;
2009 public static int getViewCount(String alignmentId)
2011 AlignmentViewport[] aps = getViewports(alignmentId);
2012 return (aps == null) ? 0 : aps.length;
2017 * @param alignmentId
2018 * - if null, all sets are returned
2019 * @return all AlignmentPanels concerning the alignmentId sequence set
2021 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
2023 if (Desktop.desktop == null)
2025 // no frames created and in headless mode
2026 // TODO: verify that frames are recoverable when in headless mode
2029 List<AlignmentPanel> aps = new ArrayList<>();
2030 AlignFrame[] frames = getAlignFrames();
2035 for (AlignFrame af : frames)
2037 for (AlignmentPanel ap : af.alignPanels)
2039 if (alignmentId == null
2040 || alignmentId.equals(ap.av.getSequenceSetId()))
2046 if (aps.size() == 0)
2050 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
2055 * get all the viewports on an alignment.
2057 * @param sequenceSetId
2058 * unique alignment id (may be null - all viewports returned in that
2060 * @return all viewports on the alignment bound to sequenceSetId
2062 public static AlignmentViewport[] getViewports(String sequenceSetId)
2064 List<AlignmentViewport> viewp = new ArrayList<>();
2065 if (desktop != null)
2067 AlignFrame[] frames = Desktop.getAlignFrames();
2069 for (AlignFrame afr : frames)
2071 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
2072 .equals(sequenceSetId))
2074 if (afr.alignPanels != null)
2076 for (AlignmentPanel ap : afr.alignPanels)
2078 if (sequenceSetId == null
2079 || sequenceSetId.equals(ap.av.getSequenceSetId()))
2087 viewp.add(afr.getViewport());
2091 if (viewp.size() > 0)
2093 return viewp.toArray(new AlignmentViewport[viewp.size()]);
2100 * Explode the views in the given frame into separate AlignFrame
2104 public static void explodeViews(AlignFrame af)
2106 int size = af.alignPanels.size();
2112 for (int i = 0; i < size; i++)
2114 AlignmentPanel ap = af.alignPanels.get(i);
2115 AlignFrame newaf = new AlignFrame(ap);
2118 * Restore the view's last exploded frame geometry if known. Multiple
2119 * views from one exploded frame share and restore the same (frame)
2120 * position and size.
2122 Rectangle geometry = ap.av.getExplodedGeometry();
2123 if (geometry != null)
2125 newaf.setBounds(geometry);
2128 ap.av.setGatherViewsHere(false);
2130 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2131 AlignFrame.DEFAULT_HEIGHT);
2134 af.alignPanels.clear();
2135 af.closeMenuItem_actionPerformed(true);
2140 * Gather expanded views (separate AlignFrame's) with the same sequence set
2141 * identifier back in to this frame as additional views, and close the
2142 * expanded views. Note the expanded frames may themselves have multiple
2143 * views. We take the lot.
2147 public void gatherViews(AlignFrame source)
2149 source.viewport.setGatherViewsHere(true);
2150 source.viewport.setExplodedGeometry(source.getBounds());
2151 JInternalFrame[] frames = desktop.getAllFrames();
2152 String viewId = source.viewport.getSequenceSetId();
2154 for (int t = 0; t < frames.length; t++)
2156 if (frames[t] instanceof AlignFrame && frames[t] != source)
2158 AlignFrame af = (AlignFrame) frames[t];
2159 boolean gatherThis = false;
2160 for (int a = 0; a < af.alignPanels.size(); a++)
2162 AlignmentPanel ap = af.alignPanels.get(a);
2163 if (viewId.equals(ap.av.getSequenceSetId()))
2166 ap.av.setGatherViewsHere(false);
2167 ap.av.setExplodedGeometry(af.getBounds());
2168 source.addAlignmentPanel(ap, false);
2174 af.alignPanels.clear();
2175 af.closeMenuItem_actionPerformed(true);
2182 jalview.gui.VamsasApplication v_client = null;
2185 public void vamsasImport_actionPerformed(ActionEvent e)
2187 if (v_client == null)
2189 // Load and try to start a session.
2190 JalviewFileChooser chooser = new JalviewFileChooser(
2191 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2193 chooser.setFileView(new JalviewFileView());
2194 chooser.setDialogTitle(
2195 MessageManager.getString("label.open_saved_vamsas_session"));
2196 chooser.setToolTipText(MessageManager.getString(
2197 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2199 int value = chooser.showOpenDialog(this);
2201 if (value == JalviewFileChooser.APPROVE_OPTION)
2203 String fle = chooser.getSelectedFile().toString();
2204 if (!vamsasImport(chooser.getSelectedFile()))
2206 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2207 MessageManager.formatMessage(
2208 "label.couldnt_import_as_vamsas_session",
2212 .getString("label.vamsas_document_import_failed"),
2213 JvOptionPane.ERROR_MESSAGE);
2219 jalview.bin.Cache.log.error(
2220 "Implementation error - load session from a running session is not supported.");
2225 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2228 * @return true if import was a success and a session was started.
2230 public boolean vamsasImport(URL url)
2232 // TODO: create progress bar
2233 if (v_client != null)
2236 jalview.bin.Cache.log.error(
2237 "Implementation error - load session from a running session is not supported.");
2243 // copy the URL content to a temporary local file
2244 // TODO: be a bit cleverer here with nio (?!)
2245 File file = File.createTempFile("vdocfromurl", ".vdj");
2246 FileOutputStream fos = new FileOutputStream(file);
2247 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2248 byte[] buffer = new byte[2048];
2250 while ((ln = bis.read(buffer)) > -1)
2252 fos.write(buffer, 0, ln);
2256 v_client = new jalview.gui.VamsasApplication(this, file,
2257 url.toExternalForm());
2258 } catch (Exception ex)
2260 jalview.bin.Cache.log.error(
2261 "Failed to create new vamsas session from contents of URL "
2266 setupVamsasConnectedGui();
2267 v_client.initial_update(); // TODO: thread ?
2268 return v_client.inSession();
2272 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2275 * @return true if import was a success and a session was started.
2277 public boolean vamsasImport(File file)
2279 if (v_client != null)
2282 jalview.bin.Cache.log.error(
2283 "Implementation error - load session from a running session is not supported.");
2287 setProgressBar(MessageManager.formatMessage(
2288 "status.importing_vamsas_session_from", new Object[]
2289 { file.getName() }), file.hashCode());
2292 v_client = new jalview.gui.VamsasApplication(this, file, null);
2293 } catch (Exception ex)
2295 setProgressBar(MessageManager.formatMessage(
2296 "status.importing_vamsas_session_from", new Object[]
2297 { file.getName() }), file.hashCode());
2298 jalview.bin.Cache.log.error(
2299 "New vamsas session from existing session file failed:", ex);
2302 setupVamsasConnectedGui();
2303 v_client.initial_update(); // TODO: thread ?
2304 setProgressBar(MessageManager.formatMessage(
2305 "status.importing_vamsas_session_from", new Object[]
2306 { file.getName() }), file.hashCode());
2307 return v_client.inSession();
2310 public boolean joinVamsasSession(String mysesid)
2312 if (v_client != null)
2314 throw new Error(MessageManager
2315 .getString("error.try_join_vamsas_session_another"));
2317 if (mysesid == null)
2320 MessageManager.getString("error.invalid_vamsas_session_id"));
2322 v_client = new VamsasApplication(this, mysesid);
2323 setupVamsasConnectedGui();
2324 v_client.initial_update();
2325 return (v_client.inSession());
2329 public void vamsasStart_actionPerformed(ActionEvent e)
2331 if (v_client == null)
2334 // we just start a default session for moment.
2336 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2337 * getProperty("LAST_DIRECTORY"));
2339 * chooser.setFileView(new JalviewFileView());
2340 * chooser.setDialogTitle("Load Vamsas file");
2341 * chooser.setToolTipText("Import");
2343 * int value = chooser.showOpenDialog(this);
2345 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2346 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2348 v_client = new VamsasApplication(this);
2349 setupVamsasConnectedGui();
2350 v_client.initial_update(); // TODO: thread ?
2354 // store current data in session.
2355 v_client.push_update(); // TODO: thread
2359 protected void setupVamsasConnectedGui()
2361 vamsasStart.setText(MessageManager.getString("label.session_update"));
2362 vamsasSave.setVisible(true);
2363 vamsasStop.setVisible(true);
2364 vamsasImport.setVisible(false); // Document import to existing session is
2365 // not possible for vamsas-client-1.0.
2368 protected void setupVamsasDisconnectedGui()
2370 vamsasSave.setVisible(false);
2371 vamsasStop.setVisible(false);
2372 vamsasImport.setVisible(true);
2374 .setText(MessageManager.getString("label.new_vamsas_session"));
2378 public void vamsasStop_actionPerformed(ActionEvent e)
2380 if (v_client != null)
2382 v_client.end_session();
2384 setupVamsasDisconnectedGui();
2388 protected void buildVamsasStMenu()
2390 if (v_client == null)
2392 String[] sess = null;
2395 sess = VamsasApplication.getSessionList();
2396 } catch (Exception e)
2398 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2404 jalview.bin.Cache.log.debug(
2405 "Got current sessions list: " + sess.length + " entries.");
2406 VamsasStMenu.removeAll();
2407 for (int i = 0; i < sess.length; i++)
2409 JMenuItem sessit = new JMenuItem();
2410 sessit.setText(sess[i]);
2411 sessit.setToolTipText(MessageManager
2412 .formatMessage("label.connect_to_session", new Object[]
2414 final Desktop dsktp = this;
2415 final String mysesid = sess[i];
2416 sessit.addActionListener(new ActionListener()
2420 public void actionPerformed(ActionEvent e)
2422 if (dsktp.v_client == null)
2424 Thread rthr = new Thread(new Runnable()
2430 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2431 dsktp.setupVamsasConnectedGui();
2432 dsktp.v_client.initial_update();
2440 VamsasStMenu.add(sessit);
2442 // don't show an empty menu.
2443 VamsasStMenu.setVisible(sess.length > 0);
2448 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2449 VamsasStMenu.removeAll();
2450 VamsasStMenu.setVisible(false);
2455 // Not interested in the content. Just hide ourselves.
2456 VamsasStMenu.setVisible(false);
2461 public void vamsasSave_actionPerformed(ActionEvent e)
2463 if (v_client != null)
2465 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2466 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2469 chooser.setFileView(new JalviewFileView());
2470 chooser.setDialogTitle(MessageManager
2471 .getString("label.save_vamsas_document_archive"));
2473 int value = chooser.showSaveDialog(this);
2475 if (value == JalviewFileChooser.APPROVE_OPTION)
2477 java.io.File choice = chooser.getSelectedFile();
2478 JPanel progpanel = addProgressPanel(MessageManager
2479 .formatMessage("label.saving_vamsas_doc", new Object[]
2480 { choice.getName() }));
2481 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2482 String warnmsg = null;
2483 String warnttl = null;
2486 v_client.vclient.storeDocument(choice);
2489 warnttl = "Serious Problem saving Vamsas Document";
2490 warnmsg = ex.toString();
2491 jalview.bin.Cache.log
2492 .error("Error Whilst saving document to " + choice, ex);
2494 } catch (Exception ex)
2496 warnttl = "Problem saving Vamsas Document.";
2497 warnmsg = ex.toString();
2498 jalview.bin.Cache.log.warn(
2499 "Exception Whilst saving document to " + choice, ex);
2502 removeProgressPanel(progpanel);
2503 if (warnmsg != null)
2505 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2507 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2513 JPanel vamUpdate = null;
2516 * hide vamsas user gui bits when a vamsas document event is being handled.
2519 * true to hide gui, false to reveal gui
2521 public void setVamsasUpdate(boolean b)
2523 Cache.log.debug("Setting gui for Vamsas update "
2524 + (b ? "in progress" : "finished"));
2526 if (vamUpdate != null)
2528 this.removeProgressPanel(vamUpdate);
2532 vamUpdate = this.addProgressPanel(
2533 MessageManager.getString("label.updating_vamsas_session"));
2535 vamsasStart.setVisible(!b);
2536 vamsasStop.setVisible(!b);
2537 vamsasSave.setVisible(!b);
2540 public JInternalFrame[] getAllFrames()
2542 return desktop.getAllFrames();
2546 * Checks the given url to see if it gives a response indicating that the user
2547 * should be informed of a new questionnaire.
2551 public void checkForQuestionnaire(String url)
2553 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2554 // javax.swing.SwingUtilities.invokeLater(jvq);
2555 new Thread(jvq).start();
2558 public void checkURLLinks()
2560 // Thread off the URL link checker
2561 addDialogThread(new Runnable()
2566 if (Cache.getDefault("CHECKURLLINKS", true))
2568 // check what the actual links are - if it's just the default don't
2569 // bother with the warning
2570 List<String> links = Preferences.sequenceUrlLinks
2573 // only need to check links if there is one with a
2574 // SEQUENCE_ID which is not the default EMBL_EBI link
2575 ListIterator<String> li = links.listIterator();
2576 boolean check = false;
2577 List<JLabel> urls = new ArrayList<>();
2578 while (li.hasNext())
2580 String link = li.next();
2581 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2582 && !UrlConstants.isDefaultString(link))
2585 int barPos = link.indexOf("|");
2586 String urlMsg = barPos == -1 ? link
2587 : link.substring(0, barPos) + ": "
2588 + link.substring(barPos + 1);
2589 urls.add(new JLabel(urlMsg));
2597 // ask user to check in case URL links use old style tokens
2598 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2599 JPanel msgPanel = new JPanel();
2600 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2601 msgPanel.add(Box.createVerticalGlue());
2602 JLabel msg = new JLabel(MessageManager
2603 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2604 JLabel msg2 = new JLabel(MessageManager
2605 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2607 for (JLabel url : urls)
2613 final JCheckBox jcb = new JCheckBox(
2614 MessageManager.getString("label.do_not_display_again"));
2615 jcb.addActionListener(new ActionListener()
2618 public void actionPerformed(ActionEvent e)
2620 // update Cache settings for "don't show this again"
2621 boolean showWarningAgain = !jcb.isSelected();
2622 Cache.setProperty("CHECKURLLINKS",
2623 Boolean.valueOf(showWarningAgain).toString());
2628 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2630 .getString("label.SEQUENCE_ID_no_longer_used"),
2631 JvOptionPane.WARNING_MESSAGE);
2638 * Proxy class for JDesktopPane which optionally displays the current memory
2639 * usage and highlights the desktop area with a red bar if free memory runs
2644 public class MyDesktopPane extends JDesktopPane implements Runnable
2647 private static final float ONE_MB = 1048576f;
2649 boolean showMemoryUsage = false;
2653 java.text.NumberFormat df;
2655 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2658 public MyDesktopPane(boolean showMemoryUsage)
2660 showMemoryUsage(showMemoryUsage);
2663 public void showMemoryUsage(boolean showMemory)
2665 this.showMemoryUsage = showMemory;
2668 Thread worker = new Thread(this);
2674 public boolean isShowMemoryUsage()
2676 return showMemoryUsage;
2682 df = java.text.NumberFormat.getNumberInstance();
2683 df.setMaximumFractionDigits(2);
2684 runtime = Runtime.getRuntime();
2686 while (showMemoryUsage)
2690 maxMemory = runtime.maxMemory() / ONE_MB;
2691 allocatedMemory = runtime.totalMemory() / ONE_MB;
2692 freeMemory = runtime.freeMemory() / ONE_MB;
2693 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2695 percentUsage = (totalFreeMemory / maxMemory) * 100;
2697 // if (percentUsage < 20)
2699 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2701 // instance.set.setBorder(border1);
2704 // sleep after showing usage
2706 } catch (Exception ex)
2708 ex.printStackTrace();
2714 public void paintComponent(Graphics g)
2716 if (showMemoryUsage && g != null && df != null)
2718 if (percentUsage < 20)
2720 g.setColor(Color.red);
2722 FontMetrics fm = g.getFontMetrics();
2725 g.drawString(MessageManager.formatMessage("label.memory_stats",
2727 { df.format(totalFreeMemory), df.format(maxMemory),
2728 df.format(percentUsage) }),
2729 10, getHeight() - fm.getHeight());
2736 * Accessor method to quickly get all the AlignmentFrames loaded.
2738 * @return an array of AlignFrame, or null if none found
2740 public static AlignFrame[] getAlignFrames()
2742 if (Jalview.isHeadlessMode())
2744 // Desktop.desktop is null in headless mode
2745 return new AlignFrame[] { Jalview.currentAlignFrame };
2748 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2754 List<AlignFrame> avp = new ArrayList<>();
2756 for (int i = frames.length - 1; i > -1; i--)
2758 if (frames[i] instanceof AlignFrame)
2760 avp.add((AlignFrame) frames[i]);
2762 else if (frames[i] instanceof SplitFrame)
2765 * Also check for a split frame containing an AlignFrame
2767 GSplitFrame sf = (GSplitFrame) frames[i];
2768 if (sf.getTopFrame() instanceof AlignFrame)
2770 avp.add((AlignFrame) sf.getTopFrame());
2772 if (sf.getBottomFrame() instanceof AlignFrame)
2774 avp.add((AlignFrame) sf.getBottomFrame());
2778 if (avp.size() == 0)
2782 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2787 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2791 public GStructureViewer[] getJmols()
2793 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2799 List<GStructureViewer> avp = new ArrayList<>();
2801 for (int i = frames.length - 1; i > -1; i--)
2803 if (frames[i] instanceof AppJmol)
2805 GStructureViewer af = (GStructureViewer) frames[i];
2809 if (avp.size() == 0)
2813 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2818 * Add Groovy Support to Jalview
2821 public void groovyShell_actionPerformed()
2825 openGroovyConsole();
2826 } catch (Exception ex)
2828 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2829 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2831 MessageManager.getString("label.couldnt_create_groovy_shell"),
2832 MessageManager.getString("label.groovy_support_failed"),
2833 JvOptionPane.ERROR_MESSAGE);
2838 * Open the Groovy console
2840 void openGroovyConsole()
2842 if (groovyConsole == null)
2844 groovyConsole = new groovy.ui.Console();
2845 groovyConsole.setVariable("Jalview", this);
2846 groovyConsole.run();
2849 * We allow only one console at a time, so that AlignFrame menu option
2850 * 'Calculate | Run Groovy script' is unambiguous.
2851 * Disable 'Groovy Console', and enable 'Run script', when the console is
2852 * opened, and the reverse when it is closed
2854 Window window = (Window) groovyConsole.getFrame();
2855 window.addWindowListener(new WindowAdapter()
2858 public void windowClosed(WindowEvent e)
2861 * rebind CMD-Q from Groovy Console to Jalview Quit
2864 enableExecuteGroovy(false);
2870 * show Groovy console window (after close and reopen)
2872 ((Window) groovyConsole.getFrame()).setVisible(true);
2875 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2876 * and disable opening a second console
2878 enableExecuteGroovy(true);
2882 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2883 * binding when opened
2885 protected void addQuitHandler()
2887 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2888 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2889 Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()),
2891 getRootPane().getActionMap().put("Quit", new AbstractAction()
2894 public void actionPerformed(ActionEvent e)
2902 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2905 * true if Groovy console is open
2907 public void enableExecuteGroovy(boolean enabled)
2910 * disable opening a second Groovy console
2911 * (or re-enable when the console is closed)
2913 groovyShell.setEnabled(!enabled);
2915 AlignFrame[] alignFrames = getAlignFrames();
2916 if (alignFrames != null)
2918 for (AlignFrame af : alignFrames)
2920 af.setGroovyEnabled(enabled);
2926 * Progress bars managed by the IProgressIndicator method.
2928 private Hashtable<Long, JPanel> progressBars;
2930 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2935 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2938 public void setProgressBar(String message, long id)
2940 if (progressBars == null)
2942 progressBars = new Hashtable<>();
2943 progressBarHandlers = new Hashtable<>();
2946 if (progressBars.get(Long.valueOf(id)) != null)
2948 JPanel panel = progressBars.remove(Long.valueOf(id));
2949 if (progressBarHandlers.contains(Long.valueOf(id)))
2951 progressBarHandlers.remove(Long.valueOf(id));
2953 removeProgressPanel(panel);
2957 progressBars.put(Long.valueOf(id), addProgressPanel(message));
2964 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2965 * jalview.gui.IProgressIndicatorHandler)
2968 public void registerHandler(final long id,
2969 final IProgressIndicatorHandler handler)
2971 if (progressBarHandlers == null
2972 || !progressBars.containsKey(Long.valueOf(id)))
2974 throw new Error(MessageManager.getString(
2975 "error.call_setprogressbar_before_registering_handler"));
2977 progressBarHandlers.put(Long.valueOf(id), handler);
2978 final JPanel progressPanel = progressBars.get(Long.valueOf(id));
2979 if (handler.canCancel())
2981 JButton cancel = new JButton(
2982 MessageManager.getString("action.cancel"));
2983 final IProgressIndicator us = this;
2984 cancel.addActionListener(new ActionListener()
2988 public void actionPerformed(ActionEvent e)
2990 handler.cancelActivity(id);
2991 us.setProgressBar(MessageManager
2992 .formatMessage("label.cancelled_params", new Object[]
2993 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2997 progressPanel.add(cancel, BorderLayout.EAST);
3003 * @return true if any progress bars are still active
3006 public boolean operationInProgress()
3008 if (progressBars != null && progressBars.size() > 0)
3016 * This will return the first AlignFrame holding the given viewport instance.
3017 * It will break if there are more than one AlignFrames viewing a particular
3021 * @return alignFrame for viewport
3023 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
3025 if (desktop != null)
3027 AlignmentPanel[] aps = getAlignmentPanels(
3028 viewport.getSequenceSetId());
3029 for (int panel = 0; aps != null && panel < aps.length; panel++)
3031 if (aps[panel] != null && aps[panel].av == viewport)
3033 return aps[panel].alignFrame;
3040 public VamsasApplication getVamsasApplication()
3047 * flag set if jalview GUI is being operated programmatically
3049 private boolean inBatchMode = false;
3052 * check if jalview GUI is being operated programmatically
3054 * @return inBatchMode
3056 public boolean isInBatchMode()
3062 * set flag if jalview GUI is being operated programmatically
3064 * @param inBatchMode
3066 public void setInBatchMode(boolean inBatchMode)
3068 this.inBatchMode = inBatchMode;
3071 public void startServiceDiscovery()
3073 startServiceDiscovery(false);
3076 public void startServiceDiscovery(boolean blocking)
3078 boolean alive = true;
3079 Thread t0 = null, t1 = null, t2 = null;
3080 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3083 // todo: changesupport handlers need to be transferred
3084 if (discoverer == null)
3086 discoverer = new jalview.ws.jws1.Discoverer();
3087 // register PCS handler for desktop.
3088 discoverer.addPropertyChangeListener(changeSupport);
3090 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3091 // until we phase out completely
3092 (t0 = new Thread(discoverer)).start();
3095 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3097 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3098 .startDiscoverer(changeSupport);
3102 // TODO: do rest service discovery
3111 } catch (Exception e)
3114 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3115 || (t3 != null && t3.isAlive())
3116 || (t0 != null && t0.isAlive());
3122 * called to check if the service discovery process completed successfully.
3126 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3128 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3130 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3131 .getErrorMessages();
3134 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3136 if (serviceChangedDialog == null)
3138 // only run if we aren't already displaying one of these.
3139 addDialogThread(serviceChangedDialog = new Runnable()
3146 * JalviewDialog jd =new JalviewDialog() {
3148 * @Override protected void cancelPressed() { // TODO
3149 * Auto-generated method stub
3151 * }@Override protected void okPressed() { // TODO
3152 * Auto-generated method stub
3154 * }@Override protected void raiseClosed() { // TODO
3155 * Auto-generated method stub
3157 * } }; jd.initDialogFrame(new
3158 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3159 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3160 * + " or mis-configured HTTP proxy settings.<br/>" +
3161 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3163 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3164 * ), true, true, "Web Service Configuration Problem", 450,
3167 * jd.waitForInput();
3169 JvOptionPane.showConfirmDialog(Desktop.desktop,
3170 new JLabel("<html><table width=\"450\"><tr><td>"
3171 + ermsg + "</td></tr></table>"
3172 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3173 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3174 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3175 + " Tools->Preferences dialog box to change them.</p></html>"),
3176 "Web Service Configuration Problem",
3177 JvOptionPane.DEFAULT_OPTION,
3178 JvOptionPane.ERROR_MESSAGE);
3179 serviceChangedDialog = null;
3188 "Errors reported by JABA discovery service. Check web services preferences.\n"
3195 private Runnable serviceChangedDialog = null;
3198 * start a thread to open a URL in the configured browser. Pops up a warning
3199 * dialog to the user if there is an exception when calling out to the browser
3204 public static void showUrl(final String url)
3206 showUrl(url, Desktop.instance);
3210 * Like showUrl but allows progress handler to be specified
3214 * (null) or object implementing IProgressIndicator
3216 public static void showUrl(final String url,
3217 final IProgressIndicator progress)
3219 new Thread(new Runnable()
3226 if (progress != null)
3228 progress.setProgressBar(MessageManager
3229 .formatMessage("status.opening_params", new Object[]
3230 { url }), this.hashCode());
3232 jalview.util.BrowserLauncher.openURL(url);
3233 } catch (Exception ex)
3235 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3237 .getString("label.web_browser_not_found_unix"),
3238 MessageManager.getString("label.web_browser_not_found"),
3239 JvOptionPane.WARNING_MESSAGE);
3241 ex.printStackTrace();
3243 if (progress != null)
3245 progress.setProgressBar(null, this.hashCode());
3251 public static WsParamSetManager wsparamManager = null;
3253 public static ParamManager getUserParameterStore()
3255 if (wsparamManager == null)
3257 wsparamManager = new WsParamSetManager();
3259 return wsparamManager;
3263 * static hyperlink handler proxy method for use by Jalview's internal windows
3267 public static void hyperlinkUpdate(HyperlinkEvent e)
3269 if (e.getEventType() == EventType.ACTIVATED)
3274 url = e.getURL().toString();
3275 Desktop.showUrl(url);
3276 } catch (Exception x)
3280 if (Cache.log != null)
3282 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3287 "Couldn't handle string " + url + " as a URL.");
3290 // ignore any exceptions due to dud links.
3297 * single thread that handles display of dialogs to user.
3299 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3302 * flag indicating if dialogExecutor should try to acquire a permit
3304 private volatile boolean dialogPause = true;
3309 private java.util.concurrent.Semaphore block = new Semaphore(0);
3311 private static groovy.ui.Console groovyConsole;
3314 * add another dialog thread to the queue
3318 public void addDialogThread(final Runnable prompter)
3320 dialogExecutor.submit(new Runnable()
3330 } catch (InterruptedException x)
3335 if (instance == null)
3341 SwingUtilities.invokeAndWait(prompter);
3342 } catch (Exception q)
3344 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3350 public void startDialogQueue()
3352 // set the flag so we don't pause waiting for another permit and semaphore
3353 // the current task to begin
3354 dialogPause = false;
3359 protected void snapShotWindow_actionPerformed(ActionEvent e)
3363 ImageMaker im = new jalview.util.ImageMaker(
3364 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3365 getHeight(), of = new File("Jalview_snapshot"
3366 + System.currentTimeMillis() + ".eps"),
3367 "View of desktop", null, 0, false);
3370 paintAll(im.getGraphics());
3372 } catch (Exception q)
3374 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3378 Cache.log.info("Successfully written snapshot to file "
3379 + of.getAbsolutePath());
3383 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3384 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3385 * and location last time the view was expanded (if any). However it does not
3386 * remember the split pane divider location - this is set to match the
3387 * 'exploding' frame.
3391 public void explodeViews(SplitFrame sf)
3393 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3394 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3395 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3397 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3399 int viewCount = topPanels.size();
3406 * Processing in reverse order works, forwards order leaves the first panels
3407 * not visible. I don't know why!
3409 for (int i = viewCount - 1; i >= 0; i--)
3412 * Make new top and bottom frames. These take over the respective
3413 * AlignmentPanel objects, including their AlignmentViewports, so the
3414 * cdna/protein relationships between the viewports is carried over to the
3417 * explodedGeometry holds the (x, y) position of the previously exploded
3418 * SplitFrame, and the (width, height) of the AlignFrame component
3420 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3421 AlignFrame newTopFrame = new AlignFrame(topPanel);
3422 newTopFrame.setSize(oldTopFrame.getSize());
3423 newTopFrame.setVisible(true);
3424 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3425 .getExplodedGeometry();
3426 if (geometry != null)
3428 newTopFrame.setSize(geometry.getSize());
3431 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3432 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3433 newBottomFrame.setSize(oldBottomFrame.getSize());
3434 newBottomFrame.setVisible(true);
3435 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3436 .getExplodedGeometry();
3437 if (geometry != null)
3439 newBottomFrame.setSize(geometry.getSize());
3442 topPanel.av.setGatherViewsHere(false);
3443 bottomPanel.av.setGatherViewsHere(false);
3444 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3446 if (geometry != null)
3448 splitFrame.setLocation(geometry.getLocation());
3450 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3454 * Clear references to the panels (now relocated in the new SplitFrames)
3455 * before closing the old SplitFrame.
3458 bottomPanels.clear();
3463 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3464 * back into the given SplitFrame as additional views. Note that the gathered
3465 * frames may themselves have multiple views.
3469 public void gatherViews(GSplitFrame source)
3472 * special handling of explodedGeometry for a view within a SplitFrame: - it
3473 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3474 * height) of the AlignFrame component
3476 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3477 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3478 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3479 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3480 myBottomFrame.viewport
3481 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3482 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3483 myTopFrame.viewport.setGatherViewsHere(true);
3484 myBottomFrame.viewport.setGatherViewsHere(true);
3485 String topViewId = myTopFrame.viewport.getSequenceSetId();
3486 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3488 JInternalFrame[] frames = desktop.getAllFrames();
3489 for (JInternalFrame frame : frames)
3491 if (frame instanceof SplitFrame && frame != source)
3493 SplitFrame sf = (SplitFrame) frame;
3494 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3495 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3496 boolean gatherThis = false;
3497 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3499 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3500 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3501 if (topViewId.equals(topPanel.av.getSequenceSetId())
3502 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3505 topPanel.av.setGatherViewsHere(false);
3506 bottomPanel.av.setGatherViewsHere(false);
3507 topPanel.av.setExplodedGeometry(
3508 new Rectangle(sf.getLocation(), topFrame.getSize()));
3509 bottomPanel.av.setExplodedGeometry(
3510 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3511 myTopFrame.addAlignmentPanel(topPanel, false);
3512 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3518 topFrame.getAlignPanels().clear();
3519 bottomFrame.getAlignPanels().clear();
3526 * The dust settles...give focus to the tab we did this from.
3528 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3531 public static groovy.ui.Console getGroovyConsole()
3533 return groovyConsole;
3537 * handles the payload of a drag and drop event.
3539 * TODO refactor to desktop utilities class
3542 * - Data source strings extracted from the drop event
3544 * - protocol for each data source extracted from the drop event
3548 * - the payload from the drop event
3551 public static void transferFromDropTarget(List<String> files,
3552 List<DataSourceType> protocols, DropTargetDropEvent evt,
3553 Transferable t) throws Exception
3556 DataFlavor uriListFlavor = new DataFlavor(
3557 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3560 urlFlavour = new DataFlavor(
3561 "application/x-java-url; class=java.net.URL");
3562 } catch (ClassNotFoundException cfe)
3564 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3567 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3572 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3573 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3574 // means url may be null.
3577 protocols.add(DataSourceType.URL);
3578 files.add(url.toString());
3579 Cache.log.debug("Drop handled as URL dataflavor "
3580 + files.get(files.size() - 1));
3585 if (Platform.isAMac())
3588 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3592 } catch (Throwable ex)
3594 Cache.log.debug("URL drop handler failed.", ex);
3597 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3599 // Works on Windows and MacOSX
3600 Cache.log.debug("Drop handled as javaFileListFlavor");
3601 for (Object file : (List) t
3602 .getTransferData(DataFlavor.javaFileListFlavor))
3604 files.add(((File) file).toString());
3605 protocols.add(DataSourceType.FILE);
3610 // Unix like behaviour
3611 boolean added = false;
3613 if (t.isDataFlavorSupported(uriListFlavor))
3615 Cache.log.debug("Drop handled as uriListFlavor");
3616 // This is used by Unix drag system
3617 data = (String) t.getTransferData(uriListFlavor);
3621 // fallback to text: workaround - on OSX where there's a JVM bug
3622 Cache.log.debug("standard URIListFlavor failed. Trying text");
3623 // try text fallback
3624 DataFlavor textDf = new DataFlavor(
3625 "text/plain;class=java.lang.String");
3626 if (t.isDataFlavorSupported(textDf))
3628 data = (String) t.getTransferData(textDf);
3631 Cache.log.debug("Plain text drop content returned "
3632 + (data == null ? "Null - failed" : data));
3637 while (protocols.size() < files.size())
3639 Cache.log.debug("Adding missing FILE protocol for "
3640 + files.get(protocols.size()));
3641 protocols.add(DataSourceType.FILE);
3643 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3644 data, "\r\n"); st.hasMoreTokens();)
3647 String s = st.nextToken();
3648 if (s.startsWith("#"))
3650 // the line is a comment (as per the RFC 2483)
3653 java.net.URI uri = new java.net.URI(s);
3654 if (uri.getScheme().toLowerCase().startsWith("http"))
3656 protocols.add(DataSourceType.URL);
3657 files.add(uri.toString());
3661 // otherwise preserve old behaviour: catch all for file objects
3662 java.io.File file = new java.io.File(uri);
3663 protocols.add(DataSourceType.FILE);
3664 files.add(file.toString());
3669 if (Cache.log.isDebugEnabled())
3671 if (data == null || !added)
3674 if (t.getTransferDataFlavors() != null
3675 && t.getTransferDataFlavors().length > 0)
3678 "Couldn't resolve drop data. Here are the supported flavors:");
3679 for (DataFlavor fl : t.getTransferDataFlavors())
3682 "Supported transfer dataflavor: " + fl.toString());
3683 Object df = t.getTransferData(fl);
3686 Cache.log.debug("Retrieves: " + df);
3690 Cache.log.debug("Retrieved nothing");
3696 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3702 if (Platform.isWindows())
3705 Cache.log.debug("Scanning dropped content for Windows Link Files");
3707 // resolve any .lnk files in the file drop
3708 for (int f = 0; f < files.size(); f++)
3710 String source = files.get(f).toLowerCase();
3711 if (protocols.get(f).equals(DataSourceType.FILE)
3712 && (source.endsWith(".lnk") || source.endsWith(".url")
3713 || source.endsWith(".site")))
3717 File lf = new File(files.get(f));
3718 // process link file to get a URL
3719 Cache.log.debug("Found potential link file: " + lf);
3720 WindowsShortcut wscfile = new WindowsShortcut(lf);
3721 String fullname = wscfile.getRealFilename();
3722 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3723 files.set(f, fullname);
3724 Cache.log.debug("Parsed real filename " + fullname
3725 + " to extract protocol: " + protocols.get(f));
3726 } catch (Exception ex)
3729 "Couldn't parse " + files.get(f) + " as a link file.",
3738 * Sets the Preferences property for experimental features to True or False
3739 * depending on the state of the controlling menu item
3742 protected void showExperimental_actionPerformed(boolean selected)
3744 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3748 * Answers a (possibly empty) list of any structure viewer frames (currently
3749 * for either Jmol or Chimera) which are currently open. This may optionally
3750 * be restricted to viewers of a specified class, or viewers linked to a
3751 * specified alignment panel.
3754 * if not null, only return viewers linked to this panel
3755 * @param structureViewerClass
3756 * if not null, only return viewers of this class
3759 public List<StructureViewerBase> getStructureViewers(
3760 AlignmentPanel apanel,
3761 Class<? extends StructureViewerBase> structureViewerClass)
3763 List<StructureViewerBase> result = new ArrayList<>();
3764 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3766 for (JInternalFrame frame : frames)
3768 if (frame instanceof StructureViewerBase)
3770 if (structureViewerClass == null
3771 || structureViewerClass.isInstance(frame))
3774 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3776 result.add((StructureViewerBase) frame);