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.DataSourceType;
28 import jalview.io.FileFormat;
29 import jalview.io.FileFormatException;
30 import jalview.io.FileFormatI;
31 import jalview.io.FileFormats;
32 import jalview.io.FileLoader;
33 import jalview.io.FormatAdapter;
34 import jalview.io.IdentifyFile;
35 import jalview.io.JalviewFileChooser;
36 import jalview.io.JalviewFileView;
37 import jalview.jbgui.GSplitFrame;
38 import jalview.jbgui.GStructureViewer;
39 import jalview.structure.StructureSelectionManager;
40 import jalview.urls.IdOrgSettings;
41 import jalview.util.ImageMaker;
42 import jalview.util.MessageManager;
43 import jalview.util.Platform;
44 import jalview.util.UrlConstants;
45 import jalview.viewmodel.AlignmentViewport;
46 import jalview.ws.params.ParamManager;
47 import jalview.ws.utils.UrlDownloadClient;
49 import java.awt.BorderLayout;
50 import java.awt.Color;
51 import java.awt.Dimension;
52 import java.awt.FontMetrics;
53 import java.awt.Graphics;
54 import java.awt.GridLayout;
55 import java.awt.Point;
56 import java.awt.Rectangle;
57 import java.awt.Toolkit;
58 import java.awt.Window;
59 import java.awt.datatransfer.Clipboard;
60 import java.awt.datatransfer.ClipboardOwner;
61 import java.awt.datatransfer.DataFlavor;
62 import java.awt.datatransfer.Transferable;
63 import java.awt.desktop.AboutEvent;
64 import java.awt.desktop.AboutHandler;
65 import java.awt.desktop.PreferencesEvent;
66 import java.awt.desktop.PreferencesHandler;
67 import java.awt.desktop.QuitEvent;
68 import java.awt.desktop.QuitHandler;
69 import java.awt.desktop.QuitResponse;
70 import java.awt.desktop.QuitStrategy;
71 import java.awt.dnd.DnDConstants;
72 import java.awt.dnd.DropTargetDragEvent;
73 import java.awt.dnd.DropTargetDropEvent;
74 import java.awt.dnd.DropTargetEvent;
75 import java.awt.dnd.DropTargetListener;
76 import java.awt.event.ActionEvent;
77 import java.awt.event.ActionListener;
78 import java.awt.event.InputEvent;
79 import java.awt.event.KeyEvent;
80 import java.awt.event.MouseAdapter;
81 import java.awt.event.MouseEvent;
82 import java.awt.event.WindowAdapter;
83 import java.awt.event.WindowEvent;
84 import java.beans.PropertyChangeEvent;
85 import java.beans.PropertyChangeListener;
86 import java.io.BufferedInputStream;
88 import java.io.FileOutputStream;
89 import java.io.FileWriter;
90 import java.io.IOException;
92 import java.util.ArrayList;
93 import java.util.HashMap;
94 import java.util.Hashtable;
95 import java.util.List;
96 import java.util.ListIterator;
97 import java.util.StringTokenizer;
98 import java.util.Vector;
99 import java.util.concurrent.ExecutorService;
100 import java.util.concurrent.Executors;
101 import java.util.concurrent.Semaphore;
103 import javax.swing.AbstractAction;
104 import javax.swing.Action;
105 import javax.swing.ActionMap;
106 import javax.swing.Box;
107 import javax.swing.BoxLayout;
108 import javax.swing.DefaultDesktopManager;
109 import javax.swing.DesktopManager;
110 import javax.swing.InputMap;
111 import javax.swing.JButton;
112 import javax.swing.JCheckBox;
113 import javax.swing.JComboBox;
114 import javax.swing.JComponent;
115 import javax.swing.JDesktopPane;
116 import javax.swing.JInternalFrame;
117 import javax.swing.JLabel;
118 import javax.swing.JMenuItem;
119 import javax.swing.JOptionPane;
120 import javax.swing.JPanel;
121 import javax.swing.JPopupMenu;
122 import javax.swing.JProgressBar;
123 import javax.swing.KeyStroke;
124 import javax.swing.SwingUtilities;
125 import javax.swing.event.HyperlinkEvent;
126 import javax.swing.event.HyperlinkEvent.EventType;
127 import javax.swing.event.InternalFrameAdapter;
128 import javax.swing.event.InternalFrameEvent;
129 import javax.swing.event.MenuEvent;
130 import javax.swing.event.MenuListener;
132 import org.stackoverflowusers.file.WindowsShortcut;
139 * @version $Revision: 1.155 $
141 public class Desktop extends jalview.jbgui.GDesktop
142 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
143 jalview.api.StructureSelectionManagerProvider
145 private static int DEFAULT_MIN_WIDTH = 300;
147 private static int DEFAULT_MIN_HEIGHT = 250;
149 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
151 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
153 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
155 private static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
157 public static HashMap<String, FileWriter> savingFiles = new HashMap<>();
159 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
162 * news reader - null if it was never started.
164 private BlogReader jvnews = null;
166 private File projectFile;
168 private static boolean setAPQHandlers = false;
172 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
174 public void addJalviewPropertyChangeListener(
175 PropertyChangeListener listener)
177 changeSupport.addJalviewPropertyChangeListener(listener);
181 * @param propertyName
183 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
184 * java.beans.PropertyChangeListener)
186 public void addJalviewPropertyChangeListener(String propertyName,
187 PropertyChangeListener listener)
189 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
193 * @param propertyName
195 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
196 * java.beans.PropertyChangeListener)
198 public void removeJalviewPropertyChangeListener(String propertyName,
199 PropertyChangeListener listener)
201 changeSupport.removeJalviewPropertyChangeListener(propertyName,
205 /** Singleton Desktop instance */
206 public static Desktop instance;
208 public static MyDesktopPane desktop;
210 static int openFrameCount = 0;
212 static final int xOffset = 30;
214 static final int yOffset = 30;
216 public static jalview.ws.jws1.Discoverer discoverer;
218 public static Object[] jalviewClipboard;
220 public static boolean internalCopy = false;
222 static int fileLoadingCount = 0;
224 class MyDesktopManager implements DesktopManager
227 private DesktopManager delegate;
229 public MyDesktopManager(DesktopManager delegate)
231 this.delegate = delegate;
235 public void activateFrame(JInternalFrame f)
239 delegate.activateFrame(f);
240 } catch (NullPointerException npe)
242 Point p = getMousePosition();
243 instance.showPasteMenu(p.x, p.y);
248 public void beginDraggingFrame(JComponent f)
250 delegate.beginDraggingFrame(f);
254 public void beginResizingFrame(JComponent f, int direction)
256 delegate.beginResizingFrame(f, direction);
260 public void closeFrame(JInternalFrame f)
262 delegate.closeFrame(f);
266 public void deactivateFrame(JInternalFrame f)
268 delegate.deactivateFrame(f);
272 public void deiconifyFrame(JInternalFrame f)
274 delegate.deiconifyFrame(f);
278 public void dragFrame(JComponent f, int newX, int newY)
284 delegate.dragFrame(f, newX, newY);
288 public void endDraggingFrame(JComponent f)
290 delegate.endDraggingFrame(f);
295 public void endResizingFrame(JComponent f)
297 delegate.endResizingFrame(f);
302 public void iconifyFrame(JInternalFrame f)
304 delegate.iconifyFrame(f);
308 public void maximizeFrame(JInternalFrame f)
310 delegate.maximizeFrame(f);
314 public void minimizeFrame(JInternalFrame f)
316 delegate.minimizeFrame(f);
320 public void openFrame(JInternalFrame f)
322 delegate.openFrame(f);
326 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
333 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
337 public void setBoundsForFrame(JComponent f, int newX, int newY,
338 int newWidth, int newHeight)
340 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
343 // All other methods, simply delegate
348 * Creates a new Desktop object.
353 * A note to implementors. It is ESSENTIAL that any activities that might
354 * block are spawned off as threads rather than waited for during this
358 doVamsasClientCheck();
360 doConfigureStructurePrefs();
361 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
363 if (!Platform.isAMac())
365 // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
369 this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
373 // flagging this test to avoid unnecessary reflection
376 // see if the Quit, About and Preferences handlers are available
377 Class desktopClass = java.awt.Desktop.class;
378 java.awt.Desktop hdesktop = java.awt.Desktop.getDesktop();
383 if (desktopClass.getDeclaredMethod("setAboutHandler",
385 { AboutHandler.class }) != null)
388 hdesktop.setAboutHandler(new AboutHandler()
391 public void handleAbout(AboutEvent e)
393 aboutMenuItem_actionPerformed(null);
399 if (desktopClass.getDeclaredMethod("setPreferencesHandler",
401 { PreferencesHandler.class }) != null)
404 hdesktop.setPreferencesHandler(new PreferencesHandler()
407 public void handlePreferences(PreferencesEvent e)
409 preferences_actionPerformed(null);
415 if (desktopClass.getDeclaredMethod("setQuitHandler",
417 { QuitHandler.class }) != null)
420 hdesktop.setQuitHandler(new QuitHandler()
423 public void handleQuitRequestWith(QuitEvent e, QuitResponse r)
425 boolean confirmQuit = jalview.bin.Cache
426 .getDefault(CONFIRM_KEYBOARD_QUIT, true);
430 n = JOptionPane.showConfirmDialog(null,
431 MessageManager.getString("label.quit_jalview"),
432 MessageManager.getString("action.quit"),
433 JOptionPane.OK_CANCEL_OPTION,
434 JOptionPane.PLAIN_MESSAGE, null);
438 n = JOptionPane.OK_OPTION;
440 if (n == JOptionPane.OK_OPTION)
442 System.out.println("Shortcut Quit confirmed by user");
444 r.performQuit(); // probably won't reach this line, but just in
450 System.out.println("Shortcut Quit cancelled by user");
454 hdesktop.setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
458 } catch (NoSuchMethodException e)
461 "NoSuchMethodException when looking for About, Preferences, Quit Handlers");
465 setAPQHandlers = true;
468 addWindowListener(new WindowAdapter()
472 public void windowClosing(WindowEvent ev)
478 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
481 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
483 desktop = new MyDesktopPane(selmemusage);
484 showMemusage.setSelected(selmemusage);
485 desktop.setBackground(Color.white);
487 getContentPane().setLayout(new BorderLayout());
488 // alternate config - have scrollbars - see notes in JAL-153
489 // JScrollPane sp = new JScrollPane();
490 // sp.getViewport().setView(desktop);
491 // getContentPane().add(sp, BorderLayout.CENTER);
492 getContentPane().add(desktop, BorderLayout.CENTER);
493 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
495 // This line prevents Windows Look&Feel resizing all new windows to maximum
496 // if previous window was maximised
497 desktop.setDesktopManager(new MyDesktopManager(
498 (Platform.isWindows() ? new DefaultDesktopManager()
500 ? new AquaInternalFrameManager(
501 desktop.getDesktopManager())
502 : desktop.getDesktopManager())));
504 Rectangle dims = getLastKnownDimensions("");
511 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
512 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
515 jconsole = new Console(this, showjconsole);
516 // add essential build information
518 "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
519 + "\n" + "Jalview Installation: "
520 + jalview.bin.Cache.getDefault("INSTALLATION",
522 + "\n" + "Build Date: "
523 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
524 + "\n" + "Java version: "
525 + System.getProperty("java.version") + "\n"
526 + System.getProperty("os.arch") + " "
527 + System.getProperty("os.name") + " "
528 + System.getProperty("os.version"));
530 showConsole(showjconsole);
532 showNews.setVisible(false);
534 experimentalFeatures.setSelected(showExperimental());
536 getIdentifiersOrgData();
540 this.addWindowListener(new WindowAdapter()
543 public void windowClosing(WindowEvent evt)
550 this.addMouseListener(ma = new MouseAdapter()
553 public void mousePressed(MouseEvent evt)
555 if (evt.isPopupTrigger()) // Mac
557 showPasteMenu(evt.getX(), evt.getY());
562 public void mouseReleased(MouseEvent evt)
564 if (evt.isPopupTrigger()) // Windows
566 showPasteMenu(evt.getX(), evt.getY());
570 desktop.addMouseListener(ma);
572 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
573 // Spawn a thread that shows the splashscreen
574 SwingUtilities.invokeLater(new Runnable()
583 // Thread off a new instance of the file chooser - this reduces the time it
584 // takes to open it later on.
585 new Thread(new Runnable()
590 Cache.log.debug("Filechooser init thread started.");
591 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
592 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
594 Cache.log.debug("Filechooser init thread finished.");
597 // Add the service change listener
598 changeSupport.addJalviewPropertyChangeListener("services",
599 new PropertyChangeListener()
603 public void propertyChange(PropertyChangeEvent evt)
605 Cache.log.debug("Firing service changed event for "
606 + evt.getNewValue());
607 JalviewServicesChanged(evt);
614 * Answers true if user preferences to enable experimental features is True
619 public boolean showExperimental()
621 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
622 Boolean.FALSE.toString());
623 return Boolean.valueOf(experimental).booleanValue();
626 public void doConfigureStructurePrefs()
628 // configure services
629 StructureSelectionManager ssm = StructureSelectionManager
630 .getStructureSelectionManager(this);
631 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
633 ssm.setAddTempFacAnnot(jalview.bin.Cache
634 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
635 ssm.setProcessSecondaryStructure(jalview.bin.Cache
636 .getDefault(Preferences.STRUCT_FROM_PDB, true));
637 ssm.setSecStructServices(
638 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
642 ssm.setAddTempFacAnnot(false);
643 ssm.setProcessSecondaryStructure(false);
644 ssm.setSecStructServices(false);
648 public void checkForNews()
650 final Desktop me = this;
651 // Thread off the news reader, in case there are connection problems.
652 new Thread(new Runnable()
657 Cache.log.debug("Starting news thread.");
659 jvnews = new BlogReader(me);
660 showNews.setVisible(true);
661 Cache.log.debug("Completed news thread.");
666 public void getIdentifiersOrgData()
668 // Thread off the identifiers fetcher
669 new Thread(new Runnable()
674 Cache.log.debug("Downloading data from identifiers.org");
675 UrlDownloadClient client = new UrlDownloadClient();
678 client.download(IdOrgSettings.getUrl(),
679 IdOrgSettings.getDownloadLocation());
680 } catch (IOException e)
682 Cache.log.debug("Exception downloading identifiers.org data"
691 protected void showNews_actionPerformed(ActionEvent e)
693 showNews(showNews.isSelected());
696 void showNews(boolean visible)
699 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
700 showNews.setSelected(visible);
701 if (visible && !jvnews.isVisible())
703 new Thread(new Runnable()
708 long now = System.currentTimeMillis();
709 Desktop.instance.setProgressBar(
710 MessageManager.getString("status.refreshing_news"),
712 jvnews.refreshNews();
713 Desktop.instance.setProgressBar(null, now);
722 * recover the last known dimensions for a jalview window
725 * - empty string is desktop, all other windows have unique prefix
726 * @return null or last known dimensions scaled to current geometry (if last
727 * window geom was known)
729 Rectangle getLastKnownDimensions(String windowName)
731 // TODO: lock aspect ratio for scaling desktop Bug #0058199
732 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
733 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
734 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
735 String width = jalview.bin.Cache
736 .getProperty(windowName + "SCREEN_WIDTH");
737 String height = jalview.bin.Cache
738 .getProperty(windowName + "SCREEN_HEIGHT");
739 if ((x != null) && (y != null) && (width != null) && (height != null))
741 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
742 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
743 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
745 // attempt #1 - try to cope with change in screen geometry - this
746 // version doesn't preserve original jv aspect ratio.
747 // take ratio of current screen size vs original screen size.
748 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
749 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
750 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
751 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
752 // rescale the bounds depending upon the current screen geometry.
753 ix = (int) (ix * sw);
754 iw = (int) (iw * sw);
755 iy = (int) (iy * sh);
756 ih = (int) (ih * sh);
757 while (ix >= screenSize.width)
759 jalview.bin.Cache.log.debug(
760 "Window geometry location recall error: shifting horizontal to within screenbounds.");
761 ix -= screenSize.width;
763 while (iy >= screenSize.height)
765 jalview.bin.Cache.log.debug(
766 "Window geometry location recall error: shifting vertical to within screenbounds.");
767 iy -= screenSize.height;
769 jalview.bin.Cache.log.debug(
770 "Got last known dimensions for " + windowName + ": x:" + ix
771 + " y:" + iy + " width:" + iw + " height:" + ih);
773 // return dimensions for new instance
774 return new Rectangle(ix, iy, iw, ih);
779 private void doVamsasClientCheck()
781 if (jalview.bin.Cache.vamsasJarsPresent())
783 setupVamsasDisconnectedGui();
784 VamsasMenu.setVisible(true);
785 final Desktop us = this;
786 VamsasMenu.addMenuListener(new MenuListener()
788 // this listener remembers when the menu was first selected, and
789 // doesn't rebuild the session list until it has been cleared and
791 boolean refresh = true;
794 public void menuCanceled(MenuEvent e)
800 public void menuDeselected(MenuEvent e)
806 public void menuSelected(MenuEvent e)
810 us.buildVamsasStMenu();
815 vamsasStart.setVisible(true);
819 void showPasteMenu(int x, int y)
821 JPopupMenu popup = new JPopupMenu();
822 JMenuItem item = new JMenuItem(
823 MessageManager.getString("label.paste_new_window"));
824 item.addActionListener(new ActionListener()
827 public void actionPerformed(ActionEvent evt)
834 popup.show(this, x, y);
841 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
842 Transferable contents = c.getContents(this);
844 if (contents != null)
846 String file = (String) contents
847 .getTransferData(DataFlavor.stringFlavor);
849 FileFormatI format = new IdentifyFile().identify(file,
850 DataSourceType.PASTE);
852 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
855 } catch (Exception ex)
858 "Unable to paste alignment from system clipboard:\n" + ex);
863 * Adds and opens the given frame to the desktop
874 public static synchronized void addInternalFrame(
875 final JInternalFrame frame, String title, int w, int h)
877 addInternalFrame(frame, title, true, w, h, true, false);
881 * Add an internal frame to the Jalview desktop
888 * When true, display frame immediately, otherwise, caller must call
889 * setVisible themselves.
895 public static synchronized void addInternalFrame(
896 final JInternalFrame frame, String title, boolean makeVisible,
899 addInternalFrame(frame, title, makeVisible, w, h, true, false);
903 * Add an internal frame to the Jalview desktop and make it visible
916 public static synchronized void addInternalFrame(
917 final JInternalFrame frame, String title, int w, int h,
920 addInternalFrame(frame, title, true, w, h, resizable, false);
924 * Add an internal frame to the Jalview desktop
931 * When true, display frame immediately, otherwise, caller must call
932 * setVisible themselves.
939 * @param ignoreMinSize
940 * Do not set the default minimum size for frame
942 public static synchronized void addInternalFrame(
943 final JInternalFrame frame, String title, boolean makeVisible,
944 int w, int h, boolean resizable, boolean ignoreMinSize)
947 // TODO: allow callers to determine X and Y position of frame (eg. via
949 // TODO: consider fixing method to update entries in the window submenu with
950 // the current window title
952 frame.setTitle(title);
953 if (frame.getWidth() < 1 || frame.getHeight() < 1)
957 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
958 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
959 // IF JALVIEW IS RUNNING HEADLESS
960 // ///////////////////////////////////////////////
961 if (instance == null || (System.getProperty("java.awt.headless") != null
962 && System.getProperty("java.awt.headless").equals("true")))
971 frame.setMinimumSize(
972 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
974 // Set default dimension for Alignment Frame window.
975 // The Alignment Frame window could be added from a number of places,
977 // I did this here in order not to miss out on any Alignment frame.
978 if (frame instanceof AlignFrame)
980 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
981 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
985 frame.setVisible(makeVisible);
986 frame.setClosable(true);
987 frame.setResizable(resizable);
988 frame.setMaximizable(resizable);
989 frame.setIconifiable(resizable);
990 frame.setOpaque(false);
992 if (frame.getX() < 1 && frame.getY() < 1)
994 frame.setLocation(xOffset * openFrameCount,
995 yOffset * ((openFrameCount - 1) % 10) + yOffset);
999 * add an entry for the new frame in the Window menu
1000 * (and remove it when the frame is closed)
1002 final JMenuItem menuItem = new JMenuItem(title);
1003 frame.addInternalFrameListener(new InternalFrameAdapter()
1006 public void internalFrameActivated(InternalFrameEvent evt)
1008 JInternalFrame itf = desktop.getSelectedFrame();
1011 if (itf instanceof AlignFrame)
1013 Jalview.setCurrentAlignFrame((AlignFrame) itf);
1020 public void internalFrameClosed(InternalFrameEvent evt)
1022 PaintRefresher.RemoveComponent(frame);
1025 * defensive check to prevent frames being
1026 * added half off the window
1028 if (openFrameCount > 0)
1034 * ensure no reference to alignFrame retained by menu item listener
1036 if (menuItem.getActionListeners().length > 0)
1038 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
1040 windowMenu.remove(menuItem);
1044 menuItem.addActionListener(new ActionListener()
1047 public void actionPerformed(ActionEvent e)
1051 frame.setSelected(true);
1052 frame.setIcon(false);
1053 } catch (java.beans.PropertyVetoException ex)
1060 setKeyBindings(frame);
1064 windowMenu.add(menuItem);
1069 frame.setSelected(true);
1070 frame.requestFocus();
1071 } catch (java.beans.PropertyVetoException ve)
1073 } catch (java.lang.ClassCastException cex)
1076 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
1082 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
1087 private static void setKeyBindings(JInternalFrame frame)
1089 @SuppressWarnings("serial")
1090 final Action closeAction = new AbstractAction()
1093 public void actionPerformed(ActionEvent e)
1100 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1102 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1103 InputEvent.CTRL_DOWN_MASK);
1104 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1105 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1107 InputMap inputMap = frame
1108 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1109 String ctrlW = ctrlWKey.toString();
1110 inputMap.put(ctrlWKey, ctrlW);
1111 inputMap.put(cmdWKey, ctrlW);
1113 ActionMap actionMap = frame.getActionMap();
1114 actionMap.put(ctrlW, closeAction);
1118 public void lostOwnership(Clipboard clipboard, Transferable contents)
1122 Desktop.jalviewClipboard = null;
1125 internalCopy = false;
1129 public void dragEnter(DropTargetDragEvent evt)
1134 public void dragExit(DropTargetEvent evt)
1139 public void dragOver(DropTargetDragEvent evt)
1144 public void dropActionChanged(DropTargetDragEvent evt)
1155 public void drop(DropTargetDropEvent evt)
1157 boolean success = true;
1158 // JAL-1552 - acceptDrop required before getTransferable call for
1159 // Java's Transferable for native dnd
1160 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1161 Transferable t = evt.getTransferable();
1162 List<String> files = new ArrayList<>();
1163 List<DataSourceType> protocols = new ArrayList<>();
1167 Desktop.transferFromDropTarget(files, protocols, evt, t);
1168 } catch (Exception e)
1170 e.printStackTrace();
1178 for (int i = 0; i < files.size(); i++)
1180 String file = files.get(i).toString();
1181 DataSourceType protocol = (protocols == null)
1182 ? DataSourceType.FILE
1184 FileFormatI format = null;
1186 if (file.endsWith(".jar"))
1188 format = FileFormat.Jalview;
1193 format = new IdentifyFile().identify(file, protocol);
1196 new FileLoader().LoadFile(file, protocol, format);
1199 } catch (Exception ex)
1204 evt.dropComplete(success); // need this to ensure input focus is properly
1205 // transfered to any new windows created
1215 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1217 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1218 JalviewFileChooser chooser = JalviewFileChooser
1219 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1221 chooser.setFileView(new JalviewFileView());
1222 chooser.setDialogTitle(
1223 MessageManager.getString("label.open_local_file"));
1224 chooser.setToolTipText(MessageManager.getString("action.open"));
1226 int value = chooser.showOpenDialog(this);
1228 if (value == JalviewFileChooser.APPROVE_OPTION)
1230 String choice = chooser.getSelectedFile().getPath();
1231 Cache.setProperty("LAST_DIRECTORY",
1232 chooser.getSelectedFile().getParent());
1234 FileFormatI format = chooser.getSelectedFormat();
1237 * Call IdentifyFile to verify the file contains what its extension implies.
1238 * Skip this step for dynamically added file formats, because
1239 * IdentifyFile does not know how to recognise them.
1241 if (FileFormats.getInstance().isIdentifiable(format))
1245 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1246 } catch (FileFormatException e)
1248 // format = null; //??
1252 if (viewport != null)
1254 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1259 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1271 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1273 // This construct allows us to have a wider textfield
1275 JLabel label = new JLabel(
1276 MessageManager.getString("label.input_file_url"));
1277 final JComboBox history = new JComboBox();
1279 JPanel panel = new JPanel(new GridLayout(2, 1));
1282 history.setPreferredSize(new Dimension(400, 20));
1283 history.setEditable(true);
1284 history.addItem("http://www.");
1286 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1290 if (historyItems != null)
1292 st = new StringTokenizer(historyItems, "\t");
1294 while (st.hasMoreTokens())
1296 history.addItem(st.nextElement());
1300 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1301 MessageManager.getString("label.input_alignment_from_url"),
1302 JvOptionPane.OK_CANCEL_OPTION);
1304 if (reply != JvOptionPane.OK_OPTION)
1309 String url = history.getSelectedItem().toString();
1311 if (url.toLowerCase().endsWith(".jar"))
1313 if (viewport != null)
1315 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1316 FileFormat.Jalview);
1320 new FileLoader().LoadFile(url, DataSourceType.URL,
1321 FileFormat.Jalview);
1326 FileFormatI format = null;
1329 format = new IdentifyFile().identify(url, DataSourceType.URL);
1330 } catch (FileFormatException e)
1332 // TODO revise error handling, distinguish between
1333 // URL not found and response not valid
1338 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1339 MessageManager.formatMessage("label.couldnt_locate",
1342 MessageManager.getString("label.url_not_found"),
1343 JvOptionPane.WARNING_MESSAGE);
1348 if (viewport != null)
1350 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1355 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1361 * Opens the CutAndPaste window for the user to paste an alignment in to
1364 * - if not null, the pasted alignment is added to the current
1365 * alignment; if null, to a new alignment window
1368 public void inputTextboxMenuItem_actionPerformed(
1369 AlignmentViewPanel viewPanel)
1371 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1372 cap.setForInput(viewPanel);
1373 Desktop.addInternalFrame(cap,
1374 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1384 System.out.println("********** Desktop.quit()");
1385 System.out.println(savingFiles.toString());
1386 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1387 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1389 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1390 screen.height + "");
1391 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1392 getWidth(), getHeight()));
1394 if (jconsole != null)
1396 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1397 jconsole.stopConsole();
1401 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1404 if (dialogExecutor != null)
1406 dialogExecutor.shutdownNow();
1408 closeAll_actionPerformed(null);
1410 if (groovyConsole != null)
1412 // suppress a possible repeat prompt to save script
1413 groovyConsole.setDirty(false);
1414 groovyConsole.exit();
1419 private void storeLastKnownDimensions(String string, Rectangle jc)
1421 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1422 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1423 + " height:" + jc.height);
1425 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1426 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1427 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1428 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1438 public void aboutMenuItem_actionPerformed(ActionEvent e)
1440 // StringBuffer message = getAboutMessage(false);
1441 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1443 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1444 new Thread(new Runnable()
1449 new SplashScreen(true);
1454 public StringBuffer getAboutMessage(boolean shortv)
1456 StringBuffer message = new StringBuffer();
1457 message.append("<html>");
1460 message.append("<h1><strong>Version: "
1461 + jalview.bin.Cache.getProperty("VERSION")
1462 + "</strong></h1>");
1463 message.append("<strong>Last Updated: <em>"
1464 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1465 + "</em></strong>");
1471 message.append("<strong>Version "
1472 + jalview.bin.Cache.getProperty("VERSION")
1473 + "; last updated: "
1474 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1477 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1478 .equals("Checking"))
1480 message.append("<br>...Checking latest version...</br>");
1482 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1483 .equals(jalview.bin.Cache.getProperty("VERSION")))
1485 boolean red = false;
1486 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1487 .indexOf("automated build") == -1)
1490 // Displayed when code version and jnlp version do not match and code
1491 // version is not a development build
1492 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1495 message.append("<br>!! Version "
1496 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1498 + " is available for download from "
1499 + jalview.bin.Cache.getDefault("www.jalview.org",
1500 "http://www.jalview.org")
1504 message.append("</div>");
1507 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1509 "The Jalview Authors (See AUTHORS file for current list)")
1510 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1511 + "<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"
1512 + "<br><br>If you use Jalview, please cite:"
1513 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1514 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1515 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1527 public void documentationMenuItem_actionPerformed(ActionEvent e)
1531 Help.showHelpWindow();
1532 } catch (Exception ex)
1538 public void closeAll_actionPerformed(ActionEvent e)
1540 // TODO show a progress bar while closing?
1541 JInternalFrame[] frames = desktop.getAllFrames();
1542 for (int i = 0; i < frames.length; i++)
1546 frames[i].setClosed(true);
1547 } catch (java.beans.PropertyVetoException ex)
1551 Jalview.setCurrentAlignFrame(null);
1552 System.out.println("ALL CLOSED");
1553 if (v_client != null)
1555 // TODO clear binding to vamsas document objects on close_all
1559 * reset state of singleton objects as appropriate (clear down session state
1560 * when all windows are closed)
1562 StructureSelectionManager ssm = StructureSelectionManager
1563 .getStructureSelectionManager(this);
1571 public void raiseRelated_actionPerformed(ActionEvent e)
1573 reorderAssociatedWindows(false, false);
1577 public void minimizeAssociated_actionPerformed(ActionEvent e)
1579 reorderAssociatedWindows(true, false);
1582 void closeAssociatedWindows()
1584 reorderAssociatedWindows(false, true);
1590 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1594 protected void garbageCollect_actionPerformed(ActionEvent e)
1596 // We simply collect the garbage
1597 jalview.bin.Cache.log.debug("Collecting garbage...");
1599 jalview.bin.Cache.log.debug("Finished garbage collection.");
1606 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1610 protected void showMemusage_actionPerformed(ActionEvent e)
1612 desktop.showMemoryUsage(showMemusage.isSelected());
1619 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1623 protected void showConsole_actionPerformed(ActionEvent e)
1625 showConsole(showConsole.isSelected());
1628 Console jconsole = null;
1631 * control whether the java console is visible or not
1635 void showConsole(boolean selected)
1637 showConsole.setSelected(selected);
1638 // TODO: decide if we should update properties file
1639 Cache.setProperty("SHOW_JAVA_CONSOLE",
1640 Boolean.valueOf(selected).toString());
1641 jconsole.setVisible(selected);
1644 void reorderAssociatedWindows(boolean minimize, boolean close)
1646 JInternalFrame[] frames = desktop.getAllFrames();
1647 if (frames == null || frames.length < 1)
1652 AlignmentViewport source = null, target = null;
1653 if (frames[0] instanceof AlignFrame)
1655 source = ((AlignFrame) frames[0]).getCurrentView();
1657 else if (frames[0] instanceof TreePanel)
1659 source = ((TreePanel) frames[0]).getViewPort();
1661 else if (frames[0] instanceof PCAPanel)
1663 source = ((PCAPanel) frames[0]).av;
1665 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1667 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1672 for (int i = 0; i < frames.length; i++)
1675 if (frames[i] == null)
1679 if (frames[i] instanceof AlignFrame)
1681 target = ((AlignFrame) frames[i]).getCurrentView();
1683 else if (frames[i] instanceof TreePanel)
1685 target = ((TreePanel) frames[i]).getViewPort();
1687 else if (frames[i] instanceof PCAPanel)
1689 target = ((PCAPanel) frames[i]).av;
1691 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1693 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1696 if (source == target)
1702 frames[i].setClosed(true);
1706 frames[i].setIcon(minimize);
1709 frames[i].toFront();
1713 } catch (java.beans.PropertyVetoException ex)
1728 protected void preferences_actionPerformed(ActionEvent e)
1740 public void saveState_actionPerformed(ActionEvent e)
1742 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1745 chooser.setFileView(new JalviewFileView());
1746 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1748 int value = chooser.showSaveDialog(this);
1750 if (value == JalviewFileChooser.APPROVE_OPTION)
1752 final Desktop me = this;
1753 final java.io.File choice = chooser.getSelectedFile();
1754 setProjectFile(choice);
1756 new Thread(new Runnable()
1761 // TODO: refactor to Jalview desktop session controller action.
1762 setProgressBar(MessageManager.formatMessage(
1763 "label.saving_jalview_project", new Object[]
1764 { choice.getName() }), choice.hashCode());
1765 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1766 choice.getParent());
1767 // TODO catch and handle errors for savestate
1768 // TODO prevent user from messing with the Desktop whilst we're saving
1771 new Jalview2XML().saveState(choice);
1772 } catch (OutOfMemoryError oom)
1775 "Whilst saving current state to " + choice.getName(),
1777 } catch (Exception ex)
1780 "Problems whilst trying to save to " + choice.getName(),
1782 JvOptionPane.showMessageDialog(me,
1783 MessageManager.formatMessage(
1784 "label.error_whilst_saving_current_state_to",
1786 { choice.getName() }),
1787 MessageManager.getString("label.couldnt_save_project"),
1788 JvOptionPane.WARNING_MESSAGE);
1790 setProgressBar(null, choice.hashCode());
1796 private void setProjectFile(File choice)
1798 this.projectFile = choice;
1801 public File getProjectFile()
1803 return this.projectFile;
1813 public void loadState_actionPerformed(ActionEvent e)
1815 JalviewFileChooser chooser = new JalviewFileChooser(
1816 Cache.getProperty("LAST_DIRECTORY"), new String[]
1819 { "Jalview Project", "Jalview Project (old)" },
1821 chooser.setFileView(new JalviewFileView());
1822 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1824 int value = chooser.showOpenDialog(this);
1826 if (value == JalviewFileChooser.APPROVE_OPTION)
1828 final File selectedFile = chooser.getSelectedFile();
1829 setProjectFile(selectedFile);
1830 final String choice = selectedFile.getAbsolutePath();
1831 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1832 new Thread(new Runnable()
1837 setProgressBar(MessageManager.formatMessage(
1838 "label.loading_jalview_project", new Object[]
1839 { choice }), choice.hashCode());
1842 new Jalview2XML().loadJalviewAlign(choice);
1843 } catch (OutOfMemoryError oom)
1845 new OOMWarning("Whilst loading project from " + choice, oom);
1846 } catch (Exception ex)
1849 "Problems whilst loading project from " + choice, ex);
1850 JvOptionPane.showMessageDialog(Desktop.desktop,
1851 MessageManager.formatMessage(
1852 "label.error_whilst_loading_project_from",
1855 MessageManager.getString("label.couldnt_load_project"),
1856 JvOptionPane.WARNING_MESSAGE);
1858 setProgressBar(null, choice.hashCode());
1865 public void inputSequence_actionPerformed(ActionEvent e)
1867 new SequenceFetcher(this);
1870 JPanel progressPanel;
1872 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1874 public void startLoading(final String fileName)
1876 if (fileLoadingCount == 0)
1878 fileLoadingPanels.add(addProgressPanel(MessageManager
1879 .formatMessage("label.loading_file", new Object[]
1885 private JPanel addProgressPanel(String string)
1887 if (progressPanel == null)
1889 progressPanel = new JPanel(new GridLayout(1, 1));
1890 totalProgressCount = 0;
1891 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1893 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1894 JProgressBar progressBar = new JProgressBar();
1895 progressBar.setIndeterminate(true);
1897 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1899 thisprogress.add(progressBar, BorderLayout.CENTER);
1900 progressPanel.add(thisprogress);
1901 ((GridLayout) progressPanel.getLayout()).setRows(
1902 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1903 ++totalProgressCount;
1904 instance.validate();
1905 return thisprogress;
1908 int totalProgressCount = 0;
1910 private void removeProgressPanel(JPanel progbar)
1912 if (progressPanel != null)
1914 synchronized (progressPanel)
1916 progressPanel.remove(progbar);
1917 GridLayout gl = (GridLayout) progressPanel.getLayout();
1918 gl.setRows(gl.getRows() - 1);
1919 if (--totalProgressCount < 1)
1921 this.getContentPane().remove(progressPanel);
1922 progressPanel = null;
1929 public void stopLoading()
1932 if (fileLoadingCount < 1)
1934 while (fileLoadingPanels.size() > 0)
1936 removeProgressPanel(fileLoadingPanels.remove(0));
1938 fileLoadingPanels.clear();
1939 fileLoadingCount = 0;
1944 public static int getViewCount(String alignmentId)
1946 AlignmentViewport[] aps = getViewports(alignmentId);
1947 return (aps == null) ? 0 : aps.length;
1952 * @param alignmentId
1953 * - if null, all sets are returned
1954 * @return all AlignmentPanels concerning the alignmentId sequence set
1956 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1958 if (Desktop.desktop == null)
1960 // no frames created and in headless mode
1961 // TODO: verify that frames are recoverable when in headless mode
1964 List<AlignmentPanel> aps = new ArrayList<>();
1965 AlignFrame[] frames = getAlignFrames();
1970 for (AlignFrame af : frames)
1972 for (AlignmentPanel ap : af.alignPanels)
1974 if (alignmentId == null
1975 || alignmentId.equals(ap.av.getSequenceSetId()))
1981 if (aps.size() == 0)
1985 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1990 * get all the viewports on an alignment.
1992 * @param sequenceSetId
1993 * unique alignment id (may be null - all viewports returned in that
1995 * @return all viewports on the alignment bound to sequenceSetId
1997 public static AlignmentViewport[] getViewports(String sequenceSetId)
1999 List<AlignmentViewport> viewp = new ArrayList<>();
2000 if (desktop != null)
2002 AlignFrame[] frames = Desktop.getAlignFrames();
2004 for (AlignFrame afr : frames)
2006 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
2007 .equals(sequenceSetId))
2009 if (afr.alignPanels != null)
2011 for (AlignmentPanel ap : afr.alignPanels)
2013 if (sequenceSetId == null
2014 || sequenceSetId.equals(ap.av.getSequenceSetId()))
2022 viewp.add(afr.getViewport());
2026 if (viewp.size() > 0)
2028 return viewp.toArray(new AlignmentViewport[viewp.size()]);
2035 * Explode the views in the given frame into separate AlignFrame
2039 public static void explodeViews(AlignFrame af)
2041 int size = af.alignPanels.size();
2047 for (int i = 0; i < size; i++)
2049 AlignmentPanel ap = af.alignPanels.get(i);
2050 AlignFrame newaf = new AlignFrame(ap);
2053 * Restore the view's last exploded frame geometry if known. Multiple
2054 * views from one exploded frame share and restore the same (frame)
2055 * position and size.
2057 Rectangle geometry = ap.av.getExplodedGeometry();
2058 if (geometry != null)
2060 newaf.setBounds(geometry);
2063 ap.av.setGatherViewsHere(false);
2065 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2066 AlignFrame.DEFAULT_HEIGHT);
2069 af.alignPanels.clear();
2070 af.closeMenuItem_actionPerformed(true);
2075 * Gather expanded views (separate AlignFrame's) with the same sequence set
2076 * identifier back in to this frame as additional views, and close the
2077 * expanded views. Note the expanded frames may themselves have multiple
2078 * views. We take the lot.
2082 public void gatherViews(AlignFrame source)
2084 source.viewport.setGatherViewsHere(true);
2085 source.viewport.setExplodedGeometry(source.getBounds());
2086 JInternalFrame[] frames = desktop.getAllFrames();
2087 String viewId = source.viewport.getSequenceSetId();
2089 for (int t = 0; t < frames.length; t++)
2091 if (frames[t] instanceof AlignFrame && frames[t] != source)
2093 AlignFrame af = (AlignFrame) frames[t];
2094 boolean gatherThis = false;
2095 for (int a = 0; a < af.alignPanels.size(); a++)
2097 AlignmentPanel ap = af.alignPanels.get(a);
2098 if (viewId.equals(ap.av.getSequenceSetId()))
2101 ap.av.setGatherViewsHere(false);
2102 ap.av.setExplodedGeometry(af.getBounds());
2103 source.addAlignmentPanel(ap, false);
2109 af.alignPanels.clear();
2110 af.closeMenuItem_actionPerformed(true);
2117 jalview.gui.VamsasApplication v_client = null;
2120 public void vamsasImport_actionPerformed(ActionEvent e)
2122 if (v_client == null)
2124 // Load and try to start a session.
2125 JalviewFileChooser chooser = new JalviewFileChooser(
2126 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2128 chooser.setFileView(new JalviewFileView());
2129 chooser.setDialogTitle(
2130 MessageManager.getString("label.open_saved_vamsas_session"));
2131 chooser.setToolTipText(MessageManager.getString(
2132 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2134 int value = chooser.showOpenDialog(this);
2136 if (value == JalviewFileChooser.APPROVE_OPTION)
2138 String fle = chooser.getSelectedFile().toString();
2139 if (!vamsasImport(chooser.getSelectedFile()))
2141 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2142 MessageManager.formatMessage(
2143 "label.couldnt_import_as_vamsas_session",
2147 .getString("label.vamsas_document_import_failed"),
2148 JvOptionPane.ERROR_MESSAGE);
2154 jalview.bin.Cache.log.error(
2155 "Implementation error - load session from a running session is not supported.");
2160 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2163 * @return true if import was a success and a session was started.
2165 public boolean vamsasImport(URL url)
2167 // TODO: create progress bar
2168 if (v_client != null)
2171 jalview.bin.Cache.log.error(
2172 "Implementation error - load session from a running session is not supported.");
2178 // copy the URL content to a temporary local file
2179 // TODO: be a bit cleverer here with nio (?!)
2180 File file = File.createTempFile("vdocfromurl", ".vdj");
2181 FileOutputStream fos = new FileOutputStream(file);
2182 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2183 byte[] buffer = new byte[2048];
2185 while ((ln = bis.read(buffer)) > -1)
2187 fos.write(buffer, 0, ln);
2191 v_client = new jalview.gui.VamsasApplication(this, file,
2192 url.toExternalForm());
2193 } catch (Exception ex)
2195 jalview.bin.Cache.log.error(
2196 "Failed to create new vamsas session from contents of URL "
2201 setupVamsasConnectedGui();
2202 v_client.initial_update(); // TODO: thread ?
2203 return v_client.inSession();
2207 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2210 * @return true if import was a success and a session was started.
2212 public boolean vamsasImport(File file)
2214 if (v_client != null)
2217 jalview.bin.Cache.log.error(
2218 "Implementation error - load session from a running session is not supported.");
2222 setProgressBar(MessageManager.formatMessage(
2223 "status.importing_vamsas_session_from", new Object[]
2224 { file.getName() }), file.hashCode());
2227 v_client = new jalview.gui.VamsasApplication(this, file, null);
2228 } catch (Exception ex)
2230 setProgressBar(MessageManager.formatMessage(
2231 "status.importing_vamsas_session_from", new Object[]
2232 { file.getName() }), file.hashCode());
2233 jalview.bin.Cache.log.error(
2234 "New vamsas session from existing session file failed:", ex);
2237 setupVamsasConnectedGui();
2238 v_client.initial_update(); // TODO: thread ?
2239 setProgressBar(MessageManager.formatMessage(
2240 "status.importing_vamsas_session_from", new Object[]
2241 { file.getName() }), file.hashCode());
2242 return v_client.inSession();
2245 public boolean joinVamsasSession(String mysesid)
2247 if (v_client != null)
2249 throw new Error(MessageManager
2250 .getString("error.try_join_vamsas_session_another"));
2252 if (mysesid == null)
2255 MessageManager.getString("error.invalid_vamsas_session_id"));
2257 v_client = new VamsasApplication(this, mysesid);
2258 setupVamsasConnectedGui();
2259 v_client.initial_update();
2260 return (v_client.inSession());
2264 public void vamsasStart_actionPerformed(ActionEvent e)
2266 if (v_client == null)
2269 // we just start a default session for moment.
2271 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2272 * getProperty("LAST_DIRECTORY"));
2274 * chooser.setFileView(new JalviewFileView());
2275 * chooser.setDialogTitle("Load Vamsas file");
2276 * chooser.setToolTipText("Import");
2278 * int value = chooser.showOpenDialog(this);
2280 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2281 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2283 v_client = new VamsasApplication(this);
2284 setupVamsasConnectedGui();
2285 v_client.initial_update(); // TODO: thread ?
2289 // store current data in session.
2290 v_client.push_update(); // TODO: thread
2294 protected void setupVamsasConnectedGui()
2296 vamsasStart.setText(MessageManager.getString("label.session_update"));
2297 vamsasSave.setVisible(true);
2298 vamsasStop.setVisible(true);
2299 vamsasImport.setVisible(false); // Document import to existing session is
2300 // not possible for vamsas-client-1.0.
2303 protected void setupVamsasDisconnectedGui()
2305 vamsasSave.setVisible(false);
2306 vamsasStop.setVisible(false);
2307 vamsasImport.setVisible(true);
2309 .setText(MessageManager.getString("label.new_vamsas_session"));
2313 public void vamsasStop_actionPerformed(ActionEvent e)
2315 if (v_client != null)
2317 v_client.end_session();
2319 setupVamsasDisconnectedGui();
2323 protected void buildVamsasStMenu()
2325 if (v_client == null)
2327 String[] sess = null;
2330 sess = VamsasApplication.getSessionList();
2331 } catch (Exception e)
2333 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2339 jalview.bin.Cache.log.debug(
2340 "Got current sessions list: " + sess.length + " entries.");
2341 VamsasStMenu.removeAll();
2342 for (int i = 0; i < sess.length; i++)
2344 JMenuItem sessit = new JMenuItem();
2345 sessit.setText(sess[i]);
2346 sessit.setToolTipText(MessageManager
2347 .formatMessage("label.connect_to_session", new Object[]
2349 final Desktop dsktp = this;
2350 final String mysesid = sess[i];
2351 sessit.addActionListener(new ActionListener()
2355 public void actionPerformed(ActionEvent e)
2357 if (dsktp.v_client == null)
2359 Thread rthr = new Thread(new Runnable()
2365 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2366 dsktp.setupVamsasConnectedGui();
2367 dsktp.v_client.initial_update();
2375 VamsasStMenu.add(sessit);
2377 // don't show an empty menu.
2378 VamsasStMenu.setVisible(sess.length > 0);
2383 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2384 VamsasStMenu.removeAll();
2385 VamsasStMenu.setVisible(false);
2390 // Not interested in the content. Just hide ourselves.
2391 VamsasStMenu.setVisible(false);
2396 public void vamsasSave_actionPerformed(ActionEvent e)
2398 if (v_client != null)
2400 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2401 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2404 chooser.setFileView(new JalviewFileView());
2405 chooser.setDialogTitle(MessageManager
2406 .getString("label.save_vamsas_document_archive"));
2408 int value = chooser.showSaveDialog(this);
2410 if (value == JalviewFileChooser.APPROVE_OPTION)
2412 java.io.File choice = chooser.getSelectedFile();
2413 JPanel progpanel = addProgressPanel(MessageManager
2414 .formatMessage("label.saving_vamsas_doc", new Object[]
2415 { choice.getName() }));
2416 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2417 String warnmsg = null;
2418 String warnttl = null;
2421 v_client.vclient.storeDocument(choice);
2424 warnttl = "Serious Problem saving Vamsas Document";
2425 warnmsg = ex.toString();
2426 jalview.bin.Cache.log
2427 .error("Error Whilst saving document to " + choice, ex);
2429 } catch (Exception ex)
2431 warnttl = "Problem saving Vamsas Document.";
2432 warnmsg = ex.toString();
2433 jalview.bin.Cache.log.warn(
2434 "Exception Whilst saving document to " + choice, ex);
2437 removeProgressPanel(progpanel);
2438 if (warnmsg != null)
2440 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2442 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2448 JPanel vamUpdate = null;
2451 * hide vamsas user gui bits when a vamsas document event is being handled.
2454 * true to hide gui, false to reveal gui
2456 public void setVamsasUpdate(boolean b)
2458 Cache.log.debug("Setting gui for Vamsas update "
2459 + (b ? "in progress" : "finished"));
2461 if (vamUpdate != null)
2463 this.removeProgressPanel(vamUpdate);
2467 vamUpdate = this.addProgressPanel(
2468 MessageManager.getString("label.updating_vamsas_session"));
2470 vamsasStart.setVisible(!b);
2471 vamsasStop.setVisible(!b);
2472 vamsasSave.setVisible(!b);
2475 public JInternalFrame[] getAllFrames()
2477 return desktop.getAllFrames();
2481 * Checks the given url to see if it gives a response indicating that the user
2482 * should be informed of a new questionnaire.
2486 public void checkForQuestionnaire(String url)
2488 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2489 // javax.swing.SwingUtilities.invokeLater(jvq);
2490 new Thread(jvq).start();
2493 public void checkURLLinks()
2495 // Thread off the URL link checker
2496 addDialogThread(new Runnable()
2501 if (Cache.getDefault("CHECKURLLINKS", true))
2503 // check what the actual links are - if it's just the default don't
2504 // bother with the warning
2505 List<String> links = Preferences.sequenceUrlLinks
2508 // only need to check links if there is one with a
2509 // SEQUENCE_ID which is not the default EMBL_EBI link
2510 ListIterator<String> li = links.listIterator();
2511 boolean check = false;
2512 List<JLabel> urls = new ArrayList<>();
2513 while (li.hasNext())
2515 String link = li.next();
2516 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2517 && !UrlConstants.isDefaultString(link))
2520 int barPos = link.indexOf("|");
2521 String urlMsg = barPos == -1 ? link
2522 : link.substring(0, barPos) + ": "
2523 + link.substring(barPos + 1);
2524 urls.add(new JLabel(urlMsg));
2532 // ask user to check in case URL links use old style tokens
2533 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2534 JPanel msgPanel = new JPanel();
2535 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2536 msgPanel.add(Box.createVerticalGlue());
2537 JLabel msg = new JLabel(MessageManager
2538 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2539 JLabel msg2 = new JLabel(MessageManager
2540 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2542 for (JLabel url : urls)
2548 final JCheckBox jcb = new JCheckBox(
2549 MessageManager.getString("label.do_not_display_again"));
2550 jcb.addActionListener(new ActionListener()
2553 public void actionPerformed(ActionEvent e)
2555 // update Cache settings for "don't show this again"
2556 boolean showWarningAgain = !jcb.isSelected();
2557 Cache.setProperty("CHECKURLLINKS",
2558 Boolean.valueOf(showWarningAgain).toString());
2563 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2565 .getString("label.SEQUENCE_ID_no_longer_used"),
2566 JvOptionPane.WARNING_MESSAGE);
2573 * Proxy class for JDesktopPane which optionally displays the current memory
2574 * usage and highlights the desktop area with a red bar if free memory runs
2579 public class MyDesktopPane extends JDesktopPane implements Runnable
2582 private static final float ONE_MB = 1048576f;
2584 boolean showMemoryUsage = false;
2588 java.text.NumberFormat df;
2590 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2593 public MyDesktopPane(boolean showMemoryUsage)
2595 showMemoryUsage(showMemoryUsage);
2598 public void showMemoryUsage(boolean showMemory)
2600 this.showMemoryUsage = showMemory;
2603 Thread worker = new Thread(this);
2609 public boolean isShowMemoryUsage()
2611 return showMemoryUsage;
2617 df = java.text.NumberFormat.getNumberInstance();
2618 df.setMaximumFractionDigits(2);
2619 runtime = Runtime.getRuntime();
2621 while (showMemoryUsage)
2625 maxMemory = runtime.maxMemory() / ONE_MB;
2626 allocatedMemory = runtime.totalMemory() / ONE_MB;
2627 freeMemory = runtime.freeMemory() / ONE_MB;
2628 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2630 percentUsage = (totalFreeMemory / maxMemory) * 100;
2632 // if (percentUsage < 20)
2634 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2636 // instance.set.setBorder(border1);
2639 // sleep after showing usage
2641 } catch (Exception ex)
2643 ex.printStackTrace();
2649 public void paintComponent(Graphics g)
2651 if (showMemoryUsage && g != null && df != null)
2653 if (percentUsage < 20)
2655 g.setColor(Color.red);
2657 FontMetrics fm = g.getFontMetrics();
2660 g.drawString(MessageManager.formatMessage("label.memory_stats",
2662 { df.format(totalFreeMemory), df.format(maxMemory),
2663 df.format(percentUsage) }),
2664 10, getHeight() - fm.getHeight());
2671 * Accessor method to quickly get all the AlignmentFrames loaded.
2673 * @return an array of AlignFrame, or null if none found
2675 public static AlignFrame[] getAlignFrames()
2677 if (Jalview.isHeadlessMode())
2679 // Desktop.desktop is null in headless mode
2680 return new AlignFrame[] { Jalview.currentAlignFrame };
2683 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2689 List<AlignFrame> avp = new ArrayList<>();
2691 for (int i = frames.length - 1; i > -1; i--)
2693 if (frames[i] instanceof AlignFrame)
2695 avp.add((AlignFrame) frames[i]);
2697 else if (frames[i] instanceof SplitFrame)
2700 * Also check for a split frame containing an AlignFrame
2702 GSplitFrame sf = (GSplitFrame) frames[i];
2703 if (sf.getTopFrame() instanceof AlignFrame)
2705 avp.add((AlignFrame) sf.getTopFrame());
2707 if (sf.getBottomFrame() instanceof AlignFrame)
2709 avp.add((AlignFrame) sf.getBottomFrame());
2713 if (avp.size() == 0)
2717 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2722 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2726 public GStructureViewer[] getJmols()
2728 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2734 List<GStructureViewer> avp = new ArrayList<>();
2736 for (int i = frames.length - 1; i > -1; i--)
2738 if (frames[i] instanceof AppJmol)
2740 GStructureViewer af = (GStructureViewer) frames[i];
2744 if (avp.size() == 0)
2748 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2753 * Add Groovy Support to Jalview
2756 public void groovyShell_actionPerformed()
2760 openGroovyConsole();
2761 } catch (Exception ex)
2763 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2764 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2766 MessageManager.getString("label.couldnt_create_groovy_shell"),
2767 MessageManager.getString("label.groovy_support_failed"),
2768 JvOptionPane.ERROR_MESSAGE);
2773 * Open the Groovy console
2775 void openGroovyConsole()
2777 if (groovyConsole == null)
2779 groovyConsole = new groovy.ui.Console();
2780 groovyConsole.setVariable("Jalview", this);
2781 groovyConsole.run();
2784 * We allow only one console at a time, so that AlignFrame menu option
2785 * 'Calculate | Run Groovy script' is unambiguous.
2786 * Disable 'Groovy Console', and enable 'Run script', when the console is
2787 * opened, and the reverse when it is closed
2789 Window window = (Window) groovyConsole.getFrame();
2790 window.addWindowListener(new WindowAdapter()
2793 public void windowClosed(WindowEvent e)
2796 * rebind CMD-Q from Groovy Console to Jalview Quit
2799 enableExecuteGroovy(false);
2805 * show Groovy console window (after close and reopen)
2807 ((Window) groovyConsole.getFrame()).setVisible(true);
2810 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2811 * and disable opening a second console
2813 enableExecuteGroovy(true);
2817 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2818 * binding when opened
2820 protected void addQuitHandler()
2822 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2823 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2824 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2826 getRootPane().getActionMap().put("Quit", new AbstractAction()
2829 public void actionPerformed(ActionEvent e)
2837 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2840 * true if Groovy console is open
2842 public void enableExecuteGroovy(boolean enabled)
2845 * disable opening a second Groovy console
2846 * (or re-enable when the console is closed)
2848 groovyShell.setEnabled(!enabled);
2850 AlignFrame[] alignFrames = getAlignFrames();
2851 if (alignFrames != null)
2853 for (AlignFrame af : alignFrames)
2855 af.setGroovyEnabled(enabled);
2861 * Progress bars managed by the IProgressIndicator method.
2863 private Hashtable<Long, JPanel> progressBars;
2865 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2870 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2873 public void setProgressBar(String message, long id)
2875 if (progressBars == null)
2877 progressBars = new Hashtable<>();
2878 progressBarHandlers = new Hashtable<>();
2881 if (progressBars.get(new Long(id)) != null)
2883 JPanel panel = progressBars.remove(new Long(id));
2884 if (progressBarHandlers.contains(new Long(id)))
2886 progressBarHandlers.remove(new Long(id));
2888 removeProgressPanel(panel);
2892 progressBars.put(new Long(id), addProgressPanel(message));
2899 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2900 * jalview.gui.IProgressIndicatorHandler)
2903 public void registerHandler(final long id,
2904 final IProgressIndicatorHandler handler)
2906 if (progressBarHandlers == null
2907 || !progressBars.containsKey(new Long(id)))
2909 throw new Error(MessageManager.getString(
2910 "error.call_setprogressbar_before_registering_handler"));
2912 progressBarHandlers.put(new Long(id), handler);
2913 final JPanel progressPanel = progressBars.get(new Long(id));
2914 if (handler.canCancel())
2916 JButton cancel = new JButton(
2917 MessageManager.getString("action.cancel"));
2918 final IProgressIndicator us = this;
2919 cancel.addActionListener(new ActionListener()
2923 public void actionPerformed(ActionEvent e)
2925 handler.cancelActivity(id);
2926 us.setProgressBar(MessageManager
2927 .formatMessage("label.cancelled_params", new Object[]
2928 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2932 progressPanel.add(cancel, BorderLayout.EAST);
2938 * @return true if any progress bars are still active
2941 public boolean operationInProgress()
2943 if (progressBars != null && progressBars.size() > 0)
2951 * This will return the first AlignFrame holding the given viewport instance.
2952 * It will break if there are more than one AlignFrames viewing a particular
2956 * @return alignFrame for viewport
2958 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2960 if (desktop != null)
2962 AlignmentPanel[] aps = getAlignmentPanels(
2963 viewport.getSequenceSetId());
2964 for (int panel = 0; aps != null && panel < aps.length; panel++)
2966 if (aps[panel] != null && aps[panel].av == viewport)
2968 return aps[panel].alignFrame;
2975 public VamsasApplication getVamsasApplication()
2982 * flag set if jalview GUI is being operated programmatically
2984 private boolean inBatchMode = false;
2987 * check if jalview GUI is being operated programmatically
2989 * @return inBatchMode
2991 public boolean isInBatchMode()
2997 * set flag if jalview GUI is being operated programmatically
2999 * @param inBatchMode
3001 public void setInBatchMode(boolean inBatchMode)
3003 this.inBatchMode = inBatchMode;
3006 public void startServiceDiscovery()
3008 startServiceDiscovery(false);
3011 public void startServiceDiscovery(boolean blocking)
3013 boolean alive = true;
3014 Thread t0 = null, t1 = null, t2 = null;
3015 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3018 // todo: changesupport handlers need to be transferred
3019 if (discoverer == null)
3021 discoverer = new jalview.ws.jws1.Discoverer();
3022 // register PCS handler for desktop.
3023 discoverer.addPropertyChangeListener(changeSupport);
3025 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3026 // until we phase out completely
3027 (t0 = new Thread(discoverer)).start();
3030 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3032 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3033 .startDiscoverer(changeSupport);
3037 // TODO: do rest service discovery
3046 } catch (Exception e)
3049 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3050 || (t3 != null && t3.isAlive())
3051 || (t0 != null && t0.isAlive());
3057 * called to check if the service discovery process completed successfully.
3061 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3063 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3065 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3066 .getErrorMessages();
3069 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3071 if (serviceChangedDialog == null)
3073 // only run if we aren't already displaying one of these.
3074 addDialogThread(serviceChangedDialog = new Runnable()
3081 * JalviewDialog jd =new JalviewDialog() {
3083 * @Override protected void cancelPressed() { // TODO
3084 * Auto-generated method stub
3086 * }@Override protected void okPressed() { // TODO
3087 * Auto-generated method stub
3089 * }@Override protected void raiseClosed() { // TODO
3090 * Auto-generated method stub
3092 * } }; jd.initDialogFrame(new
3093 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3094 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3095 * + " or mis-configured HTTP proxy settings.<br/>" +
3096 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3098 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3099 * ), true, true, "Web Service Configuration Problem", 450,
3102 * jd.waitForInput();
3104 JvOptionPane.showConfirmDialog(Desktop.desktop,
3105 new JLabel("<html><table width=\"450\"><tr><td>"
3106 + ermsg + "</td></tr></table>"
3107 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3108 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3109 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3110 + " Tools->Preferences dialog box to change them.</p></html>"),
3111 "Web Service Configuration Problem",
3112 JvOptionPane.DEFAULT_OPTION,
3113 JvOptionPane.ERROR_MESSAGE);
3114 serviceChangedDialog = null;
3123 "Errors reported by JABA discovery service. Check web services preferences.\n"
3130 private Runnable serviceChangedDialog = null;
3133 * start a thread to open a URL in the configured browser. Pops up a warning
3134 * dialog to the user if there is an exception when calling out to the browser
3139 public static void showUrl(final String url)
3141 showUrl(url, Desktop.instance);
3145 * Like showUrl but allows progress handler to be specified
3149 * (null) or object implementing IProgressIndicator
3151 public static void showUrl(final String url,
3152 final IProgressIndicator progress)
3154 new Thread(new Runnable()
3161 if (progress != null)
3163 progress.setProgressBar(MessageManager
3164 .formatMessage("status.opening_params", new Object[]
3165 { url }), this.hashCode());
3167 jalview.util.BrowserLauncher.openURL(url);
3168 } catch (Exception ex)
3170 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3172 .getString("label.web_browser_not_found_unix"),
3173 MessageManager.getString("label.web_browser_not_found"),
3174 JvOptionPane.WARNING_MESSAGE);
3176 ex.printStackTrace();
3178 if (progress != null)
3180 progress.setProgressBar(null, this.hashCode());
3186 public static WsParamSetManager wsparamManager = null;
3188 public static ParamManager getUserParameterStore()
3190 if (wsparamManager == null)
3192 wsparamManager = new WsParamSetManager();
3194 return wsparamManager;
3198 * static hyperlink handler proxy method for use by Jalview's internal windows
3202 public static void hyperlinkUpdate(HyperlinkEvent e)
3204 if (e.getEventType() == EventType.ACTIVATED)
3209 url = e.getURL().toString();
3210 Desktop.showUrl(url);
3211 } catch (Exception x)
3215 if (Cache.log != null)
3217 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3222 "Couldn't handle string " + url + " as a URL.");
3225 // ignore any exceptions due to dud links.
3232 * single thread that handles display of dialogs to user.
3234 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3237 * flag indicating if dialogExecutor should try to acquire a permit
3239 private volatile boolean dialogPause = true;
3244 private java.util.concurrent.Semaphore block = new Semaphore(0);
3246 private static groovy.ui.Console groovyConsole;
3249 * add another dialog thread to the queue
3253 public void addDialogThread(final Runnable prompter)
3255 dialogExecutor.submit(new Runnable()
3265 } catch (InterruptedException x)
3270 if (instance == null)
3276 SwingUtilities.invokeAndWait(prompter);
3277 } catch (Exception q)
3279 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3285 public void startDialogQueue()
3287 // set the flag so we don't pause waiting for another permit and semaphore
3288 // the current task to begin
3289 dialogPause = false;
3294 protected void snapShotWindow_actionPerformed(ActionEvent e)
3298 ImageMaker im = new jalview.util.ImageMaker(
3299 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3300 getHeight(), of = new File("Jalview_snapshot"
3301 + System.currentTimeMillis() + ".eps"),
3302 "View of desktop", null, 0, false);
3305 paintAll(im.getGraphics());
3307 } catch (Exception q)
3309 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3313 Cache.log.info("Successfully written snapshot to file "
3314 + of.getAbsolutePath());
3318 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3319 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3320 * and location last time the view was expanded (if any). However it does not
3321 * remember the split pane divider location - this is set to match the
3322 * 'exploding' frame.
3326 public void explodeViews(SplitFrame sf)
3328 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3329 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3330 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3332 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3334 int viewCount = topPanels.size();
3341 * Processing in reverse order works, forwards order leaves the first panels
3342 * not visible. I don't know why!
3344 for (int i = viewCount - 1; i >= 0; i--)
3347 * Make new top and bottom frames. These take over the respective
3348 * AlignmentPanel objects, including their AlignmentViewports, so the
3349 * cdna/protein relationships between the viewports is carried over to the
3352 * explodedGeometry holds the (x, y) position of the previously exploded
3353 * SplitFrame, and the (width, height) of the AlignFrame component
3355 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3356 AlignFrame newTopFrame = new AlignFrame(topPanel);
3357 newTopFrame.setSize(oldTopFrame.getSize());
3358 newTopFrame.setVisible(true);
3359 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3360 .getExplodedGeometry();
3361 if (geometry != null)
3363 newTopFrame.setSize(geometry.getSize());
3366 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3367 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3368 newBottomFrame.setSize(oldBottomFrame.getSize());
3369 newBottomFrame.setVisible(true);
3370 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3371 .getExplodedGeometry();
3372 if (geometry != null)
3374 newBottomFrame.setSize(geometry.getSize());
3377 topPanel.av.setGatherViewsHere(false);
3378 bottomPanel.av.setGatherViewsHere(false);
3379 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3381 if (geometry != null)
3383 splitFrame.setLocation(geometry.getLocation());
3385 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3389 * Clear references to the panels (now relocated in the new SplitFrames)
3390 * before closing the old SplitFrame.
3393 bottomPanels.clear();
3398 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3399 * back into the given SplitFrame as additional views. Note that the gathered
3400 * frames may themselves have multiple views.
3404 public void gatherViews(GSplitFrame source)
3407 * special handling of explodedGeometry for a view within a SplitFrame: - it
3408 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3409 * height) of the AlignFrame component
3411 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3412 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3413 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3414 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3415 myBottomFrame.viewport
3416 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3417 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3418 myTopFrame.viewport.setGatherViewsHere(true);
3419 myBottomFrame.viewport.setGatherViewsHere(true);
3420 String topViewId = myTopFrame.viewport.getSequenceSetId();
3421 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3423 JInternalFrame[] frames = desktop.getAllFrames();
3424 for (JInternalFrame frame : frames)
3426 if (frame instanceof SplitFrame && frame != source)
3428 SplitFrame sf = (SplitFrame) frame;
3429 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3430 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3431 boolean gatherThis = false;
3432 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3434 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3435 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3436 if (topViewId.equals(topPanel.av.getSequenceSetId())
3437 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3440 topPanel.av.setGatherViewsHere(false);
3441 bottomPanel.av.setGatherViewsHere(false);
3442 topPanel.av.setExplodedGeometry(
3443 new Rectangle(sf.getLocation(), topFrame.getSize()));
3444 bottomPanel.av.setExplodedGeometry(
3445 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3446 myTopFrame.addAlignmentPanel(topPanel, false);
3447 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3453 topFrame.getAlignPanels().clear();
3454 bottomFrame.getAlignPanels().clear();
3461 * The dust settles...give focus to the tab we did this from.
3463 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3466 public static groovy.ui.Console getGroovyConsole()
3468 return groovyConsole;
3472 * handles the payload of a drag and drop event.
3474 * TODO refactor to desktop utilities class
3477 * - Data source strings extracted from the drop event
3479 * - protocol for each data source extracted from the drop event
3483 * - the payload from the drop event
3486 public static void transferFromDropTarget(List<String> files,
3487 List<DataSourceType> protocols, DropTargetDropEvent evt,
3488 Transferable t) throws Exception
3491 DataFlavor uriListFlavor = new DataFlavor(
3492 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3495 urlFlavour = new DataFlavor(
3496 "application/x-java-url; class=java.net.URL");
3497 } catch (ClassNotFoundException cfe)
3499 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3502 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3507 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3508 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3509 // means url may be null.
3512 protocols.add(DataSourceType.URL);
3513 files.add(url.toString());
3514 Cache.log.debug("Drop handled as URL dataflavor "
3515 + files.get(files.size() - 1));
3520 if (Platform.isAMac())
3523 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3527 } catch (Throwable ex)
3529 Cache.log.debug("URL drop handler failed.", ex);
3532 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3534 // Works on Windows and MacOSX
3535 Cache.log.debug("Drop handled as javaFileListFlavor");
3536 for (Object file : (List) t
3537 .getTransferData(DataFlavor.javaFileListFlavor))
3539 files.add(((File) file).toString());
3540 protocols.add(DataSourceType.FILE);
3545 // Unix like behaviour
3546 boolean added = false;
3548 if (t.isDataFlavorSupported(uriListFlavor))
3550 Cache.log.debug("Drop handled as uriListFlavor");
3551 // This is used by Unix drag system
3552 data = (String) t.getTransferData(uriListFlavor);
3556 // fallback to text: workaround - on OSX where there's a JVM bug
3557 Cache.log.debug("standard URIListFlavor failed. Trying text");
3558 // try text fallback
3559 DataFlavor textDf = new DataFlavor(
3560 "text/plain;class=java.lang.String");
3561 if (t.isDataFlavorSupported(textDf))
3563 data = (String) t.getTransferData(textDf);
3566 Cache.log.debug("Plain text drop content returned "
3567 + (data == null ? "Null - failed" : data));
3572 while (protocols.size() < files.size())
3574 Cache.log.debug("Adding missing FILE protocol for "
3575 + files.get(protocols.size()));
3576 protocols.add(DataSourceType.FILE);
3578 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3579 data, "\r\n"); st.hasMoreTokens();)
3582 String s = st.nextToken();
3583 if (s.startsWith("#"))
3585 // the line is a comment (as per the RFC 2483)
3588 java.net.URI uri = new java.net.URI(s);
3589 if (uri.getScheme().toLowerCase().startsWith("http"))
3591 protocols.add(DataSourceType.URL);
3592 files.add(uri.toString());
3596 // otherwise preserve old behaviour: catch all for file objects
3597 java.io.File file = new java.io.File(uri);
3598 protocols.add(DataSourceType.FILE);
3599 files.add(file.toString());
3604 if (Cache.log.isDebugEnabled())
3606 if (data == null || !added)
3609 if (t.getTransferDataFlavors() != null
3610 && t.getTransferDataFlavors().length > 0)
3613 "Couldn't resolve drop data. Here are the supported flavors:");
3614 for (DataFlavor fl : t.getTransferDataFlavors())
3617 "Supported transfer dataflavor: " + fl.toString());
3618 Object df = t.getTransferData(fl);
3621 Cache.log.debug("Retrieves: " + df);
3625 Cache.log.debug("Retrieved nothing");
3631 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3637 if (Platform.isWindows())
3640 Cache.log.debug("Scanning dropped content for Windows Link Files");
3642 // resolve any .lnk files in the file drop
3643 for (int f = 0; f < files.size(); f++)
3645 String source = files.get(f).toLowerCase();
3646 if (protocols.get(f).equals(DataSourceType.FILE)
3647 && (source.endsWith(".lnk") || source.endsWith(".url")
3648 || source.endsWith(".site")))
3652 File lf = new File(files.get(f));
3653 // process link file to get a URL
3654 Cache.log.debug("Found potential link file: " + lf);
3655 WindowsShortcut wscfile = new WindowsShortcut(lf);
3656 String fullname = wscfile.getRealFilename();
3657 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3658 files.set(f, fullname);
3659 Cache.log.debug("Parsed real filename " + fullname
3660 + " to extract protocol: " + protocols.get(f));
3661 } catch (Exception ex)
3664 "Couldn't parse " + files.get(f) + " as a link file.",
3673 * Sets the Preferences property for experimental features to True or False
3674 * depending on the state of the controlling menu item
3677 protected void showExperimental_actionPerformed(boolean selected)
3679 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3683 * Answers a (possibly empty) list of any structure viewer frames (currently
3684 * for either Jmol or Chimera) which are currently open. This may optionally
3685 * be restricted to viewers of a specified class, or viewers linked to a
3686 * specified alignment panel.
3689 * if not null, only return viewers linked to this panel
3690 * @param structureViewerClass
3691 * if not null, only return viewers of this class
3694 public List<StructureViewerBase> getStructureViewers(
3695 AlignmentPanel apanel,
3696 Class<? extends StructureViewerBase> structureViewerClass)
3698 List<StructureViewerBase> result = new ArrayList<>();
3699 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3701 for (JInternalFrame frame : frames)
3703 if (frame instanceof StructureViewerBase)
3705 if (structureViewerClass == null
3706 || structureViewerClass.isInstance(frame))
3709 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3711 result.add((StructureViewerBase) frame);