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.project.Jalview2XML;
40 import jalview.structure.StructureSelectionManager;
41 import jalview.urls.IdOrgSettings;
42 import jalview.util.ImageMaker;
43 import jalview.util.MessageManager;
44 import jalview.util.Platform;
45 import jalview.util.UrlConstants;
46 import jalview.viewmodel.AlignmentViewport;
47 import jalview.ws.params.ParamManager;
48 import jalview.ws.utils.UrlDownloadClient;
50 import java.awt.BorderLayout;
51 import java.awt.Color;
52 import java.awt.Dimension;
53 import java.awt.FontMetrics;
54 import java.awt.Graphics;
55 import java.awt.GridLayout;
56 import java.awt.Point;
57 import java.awt.Rectangle;
58 import java.awt.Toolkit;
59 import java.awt.Window;
60 import java.awt.datatransfer.Clipboard;
61 import java.awt.datatransfer.ClipboardOwner;
62 import java.awt.datatransfer.DataFlavor;
63 import java.awt.datatransfer.Transferable;
64 import java.awt.desktop.AboutEvent;
65 import java.awt.desktop.AboutHandler;
66 import java.awt.desktop.PreferencesEvent;
67 import java.awt.desktop.PreferencesHandler;
68 import java.awt.desktop.QuitEvent;
69 import java.awt.desktop.QuitHandler;
70 import java.awt.desktop.QuitResponse;
71 import java.awt.desktop.QuitStrategy;
72 import java.awt.dnd.DnDConstants;
73 import java.awt.dnd.DropTargetDragEvent;
74 import java.awt.dnd.DropTargetDropEvent;
75 import java.awt.dnd.DropTargetEvent;
76 import java.awt.dnd.DropTargetListener;
77 import java.awt.event.ActionEvent;
78 import java.awt.event.ActionListener;
79 import java.awt.event.InputEvent;
80 import java.awt.event.KeyEvent;
81 import java.awt.event.MouseAdapter;
82 import java.awt.event.MouseEvent;
83 import java.awt.event.WindowAdapter;
84 import java.awt.event.WindowEvent;
85 import java.beans.PropertyChangeEvent;
86 import java.beans.PropertyChangeListener;
87 import java.io.BufferedInputStream;
89 import java.io.FileOutputStream;
90 import java.io.FileWriter;
91 import java.io.IOException;
93 import java.util.ArrayList;
94 import java.util.HashMap;
95 import java.util.Hashtable;
96 import java.util.List;
97 import java.util.ListIterator;
98 import java.util.StringTokenizer;
99 import java.util.Vector;
100 import java.util.concurrent.ExecutorService;
101 import java.util.concurrent.Executors;
102 import java.util.concurrent.Semaphore;
104 import javax.swing.AbstractAction;
105 import javax.swing.Action;
106 import javax.swing.ActionMap;
107 import javax.swing.Box;
108 import javax.swing.BoxLayout;
109 import javax.swing.DefaultDesktopManager;
110 import javax.swing.DesktopManager;
111 import javax.swing.InputMap;
112 import javax.swing.JButton;
113 import javax.swing.JCheckBox;
114 import javax.swing.JComboBox;
115 import javax.swing.JComponent;
116 import javax.swing.JDesktopPane;
117 import javax.swing.JInternalFrame;
118 import javax.swing.JLabel;
119 import javax.swing.JMenuItem;
120 import javax.swing.JOptionPane;
121 import javax.swing.JPanel;
122 import javax.swing.JPopupMenu;
123 import javax.swing.JProgressBar;
124 import javax.swing.KeyStroke;
125 import javax.swing.SwingUtilities;
126 import javax.swing.event.HyperlinkEvent;
127 import javax.swing.event.HyperlinkEvent.EventType;
128 import javax.swing.event.InternalFrameAdapter;
129 import javax.swing.event.InternalFrameEvent;
130 import javax.swing.event.MenuEvent;
131 import javax.swing.event.MenuListener;
133 import org.stackoverflowusers.file.WindowsShortcut;
140 * @version $Revision: 1.155 $
142 public class Desktop extends jalview.jbgui.GDesktop
143 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
144 jalview.api.StructureSelectionManagerProvider
146 private static int DEFAULT_MIN_WIDTH = 300;
148 private static int DEFAULT_MIN_HEIGHT = 250;
150 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
152 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
154 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
156 private static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
158 public static HashMap<String, FileWriter> savingFiles = new HashMap<>();
160 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
163 * news reader - null if it was never started.
165 private BlogReader jvnews = null;
167 private File projectFile;
169 private static boolean setAPQHandlers = false;
173 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
175 public void addJalviewPropertyChangeListener(
176 PropertyChangeListener listener)
178 changeSupport.addJalviewPropertyChangeListener(listener);
182 * @param propertyName
184 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
185 * java.beans.PropertyChangeListener)
187 public void addJalviewPropertyChangeListener(String propertyName,
188 PropertyChangeListener listener)
190 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
194 * @param propertyName
196 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
197 * java.beans.PropertyChangeListener)
199 public void removeJalviewPropertyChangeListener(String propertyName,
200 PropertyChangeListener listener)
202 changeSupport.removeJalviewPropertyChangeListener(propertyName,
206 /** Singleton Desktop instance */
207 public static Desktop instance;
209 public static MyDesktopPane desktop;
211 static int openFrameCount = 0;
213 static final int xOffset = 30;
215 static final int yOffset = 30;
217 public static jalview.ws.jws1.Discoverer discoverer;
219 public static Object[] jalviewClipboard;
221 public static boolean internalCopy = false;
223 static int fileLoadingCount = 0;
225 class MyDesktopManager implements DesktopManager
228 private DesktopManager delegate;
230 public MyDesktopManager(DesktopManager delegate)
232 this.delegate = delegate;
236 public void activateFrame(JInternalFrame f)
240 delegate.activateFrame(f);
241 } catch (NullPointerException npe)
243 Point p = getMousePosition();
244 instance.showPasteMenu(p.x, p.y);
249 public void beginDraggingFrame(JComponent f)
251 delegate.beginDraggingFrame(f);
255 public void beginResizingFrame(JComponent f, int direction)
257 delegate.beginResizingFrame(f, direction);
261 public void closeFrame(JInternalFrame f)
263 delegate.closeFrame(f);
267 public void deactivateFrame(JInternalFrame f)
269 delegate.deactivateFrame(f);
273 public void deiconifyFrame(JInternalFrame f)
275 delegate.deiconifyFrame(f);
279 public void dragFrame(JComponent f, int newX, int newY)
285 delegate.dragFrame(f, newX, newY);
289 public void endDraggingFrame(JComponent f)
291 delegate.endDraggingFrame(f);
296 public void endResizingFrame(JComponent f)
298 delegate.endResizingFrame(f);
303 public void iconifyFrame(JInternalFrame f)
305 delegate.iconifyFrame(f);
309 public void maximizeFrame(JInternalFrame f)
311 delegate.maximizeFrame(f);
315 public void minimizeFrame(JInternalFrame f)
317 delegate.minimizeFrame(f);
321 public void openFrame(JInternalFrame f)
323 delegate.openFrame(f);
327 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
334 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
338 public void setBoundsForFrame(JComponent f, int newX, int newY,
339 int newWidth, int newHeight)
341 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
344 // All other methods, simply delegate
349 * Creates a new Desktop object.
354 * A note to implementors. It is ESSENTIAL that any activities that might
355 * block are spawned off as threads rather than waited for during this
359 doVamsasClientCheck();
361 doConfigureStructurePrefs();
362 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
364 if (!Platform.isAMac())
366 // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
370 this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
374 // flagging this test to avoid unnecessary reflection
377 // see if the Quit, About and Preferences handlers are available
378 Class desktopClass = java.awt.Desktop.class;
379 java.awt.Desktop hdesktop = java.awt.Desktop.getDesktop();
384 if (Platform.isAMac())
386 if (desktopClass.getDeclaredMethod("setAboutHandler",
388 { AboutHandler.class }) != null)
391 hdesktop.setAboutHandler(new AboutHandler()
394 public void handleAbout(AboutEvent e)
396 aboutMenuItem_actionPerformed(null);
402 if (desktopClass.getDeclaredMethod("setPreferencesHandler",
404 { PreferencesHandler.class }) != null)
407 hdesktop.setPreferencesHandler(new PreferencesHandler()
410 public void handlePreferences(PreferencesEvent e)
412 preferences_actionPerformed(null);
418 if (desktopClass.getDeclaredMethod("setQuitHandler",
420 { QuitHandler.class }) != null)
423 hdesktop.setQuitHandler(new QuitHandler()
426 public void handleQuitRequestWith(QuitEvent e, QuitResponse r)
428 boolean confirmQuit = jalview.bin.Cache
429 .getDefault(CONFIRM_KEYBOARD_QUIT, true);
433 n = JOptionPane.showConfirmDialog(null,
434 MessageManager.getString("label.quit_jalview"),
435 MessageManager.getString("action.quit"),
436 JOptionPane.OK_CANCEL_OPTION,
437 JOptionPane.PLAIN_MESSAGE, null);
441 n = JOptionPane.OK_OPTION;
443 if (n == JOptionPane.OK_OPTION)
445 System.out.println("Shortcut Quit confirmed by user");
447 r.performQuit(); // probably won't reach this line, but just in
453 System.out.println("Shortcut Quit cancelled by user");
457 hdesktop.setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
462 } catch (NoSuchMethodException e)
465 "NoSuchMethodException when looking for About, Preferences, Quit Handlers");
469 setAPQHandlers = true;
472 addWindowListener(new WindowAdapter()
476 public void windowClosing(WindowEvent ev)
482 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
485 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
487 desktop = new MyDesktopPane(selmemusage);
488 showMemusage.setSelected(selmemusage);
489 desktop.setBackground(Color.white);
491 getContentPane().setLayout(new BorderLayout());
492 // alternate config - have scrollbars - see notes in JAL-153
493 // JScrollPane sp = new JScrollPane();
494 // sp.getViewport().setView(desktop);
495 // getContentPane().add(sp, BorderLayout.CENTER);
496 getContentPane().add(desktop, BorderLayout.CENTER);
497 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
499 // This line prevents Windows Look&Feel resizing all new windows to maximum
500 // if previous window was maximised
501 desktop.setDesktopManager(new MyDesktopManager(
502 (Platform.isWindows() ? new DefaultDesktopManager()
504 ? new AquaInternalFrameManager(
505 desktop.getDesktopManager())
506 : desktop.getDesktopManager())));
508 Rectangle dims = getLastKnownDimensions("");
515 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
516 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
519 jconsole = new Console(this, showjconsole);
520 // add essential build information
522 "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
523 + "\n" + "Jalview Installation: "
524 + jalview.bin.Cache.getDefault("INSTALLATION",
526 + "\n" + "Build Date: "
527 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
528 + "\n" + "Java version: "
529 + System.getProperty("java.version") + "\n"
530 + System.getProperty("os.arch") + " "
531 + System.getProperty("os.name") + " "
532 + System.getProperty("os.version"));
534 showConsole(showjconsole);
536 showNews.setVisible(false);
538 experimentalFeatures.setSelected(showExperimental());
540 getIdentifiersOrgData();
544 this.addWindowListener(new WindowAdapter()
547 public void windowClosing(WindowEvent evt)
554 this.addMouseListener(ma = new MouseAdapter()
557 public void mousePressed(MouseEvent evt)
559 if (evt.isPopupTrigger()) // Mac
561 showPasteMenu(evt.getX(), evt.getY());
566 public void mouseReleased(MouseEvent evt)
568 if (evt.isPopupTrigger()) // Windows
570 showPasteMenu(evt.getX(), evt.getY());
574 desktop.addMouseListener(ma);
576 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
577 // Spawn a thread that shows the splashscreen
578 SwingUtilities.invokeLater(new Runnable()
587 // Thread off a new instance of the file chooser - this reduces the time it
588 // takes to open it later on.
589 new Thread(new Runnable()
594 Cache.log.debug("Filechooser init thread started.");
595 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
596 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
598 Cache.log.debug("Filechooser init thread finished.");
601 // Add the service change listener
602 changeSupport.addJalviewPropertyChangeListener("services",
603 new PropertyChangeListener()
607 public void propertyChange(PropertyChangeEvent evt)
609 Cache.log.debug("Firing service changed event for "
610 + evt.getNewValue());
611 JalviewServicesChanged(evt);
618 * Answers true if user preferences to enable experimental features is True
623 public boolean showExperimental()
625 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
626 Boolean.FALSE.toString());
627 return Boolean.valueOf(experimental).booleanValue();
630 public void doConfigureStructurePrefs()
632 // configure services
633 StructureSelectionManager ssm = StructureSelectionManager
634 .getStructureSelectionManager(this);
635 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
637 ssm.setAddTempFacAnnot(jalview.bin.Cache
638 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
639 ssm.setProcessSecondaryStructure(jalview.bin.Cache
640 .getDefault(Preferences.STRUCT_FROM_PDB, true));
641 ssm.setSecStructServices(
642 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
646 ssm.setAddTempFacAnnot(false);
647 ssm.setProcessSecondaryStructure(false);
648 ssm.setSecStructServices(false);
652 public void checkForNews()
654 final Desktop me = this;
655 // Thread off the news reader, in case there are connection problems.
656 new Thread(new Runnable()
661 Cache.log.debug("Starting news thread.");
663 jvnews = new BlogReader(me);
664 showNews.setVisible(true);
665 Cache.log.debug("Completed news thread.");
670 public void getIdentifiersOrgData()
672 // Thread off the identifiers fetcher
673 new Thread(new Runnable()
678 Cache.log.debug("Downloading data from identifiers.org");
679 UrlDownloadClient client = new UrlDownloadClient();
682 client.download(IdOrgSettings.getUrl(),
683 IdOrgSettings.getDownloadLocation());
684 } catch (IOException e)
686 Cache.log.debug("Exception downloading identifiers.org data"
695 protected void showNews_actionPerformed(ActionEvent e)
697 showNews(showNews.isSelected());
700 void showNews(boolean visible)
703 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
704 showNews.setSelected(visible);
705 if (visible && !jvnews.isVisible())
707 new Thread(new Runnable()
712 long now = System.currentTimeMillis();
713 Desktop.instance.setProgressBar(
714 MessageManager.getString("status.refreshing_news"),
716 jvnews.refreshNews();
717 Desktop.instance.setProgressBar(null, now);
726 * recover the last known dimensions for a jalview window
729 * - empty string is desktop, all other windows have unique prefix
730 * @return null or last known dimensions scaled to current geometry (if last
731 * window geom was known)
733 Rectangle getLastKnownDimensions(String windowName)
735 // TODO: lock aspect ratio for scaling desktop Bug #0058199
736 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
737 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
738 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
739 String width = jalview.bin.Cache
740 .getProperty(windowName + "SCREEN_WIDTH");
741 String height = jalview.bin.Cache
742 .getProperty(windowName + "SCREEN_HEIGHT");
743 if ((x != null) && (y != null) && (width != null) && (height != null))
745 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
746 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
747 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
749 // attempt #1 - try to cope with change in screen geometry - this
750 // version doesn't preserve original jv aspect ratio.
751 // take ratio of current screen size vs original screen size.
752 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
753 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
754 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
755 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
756 // rescale the bounds depending upon the current screen geometry.
757 ix = (int) (ix * sw);
758 iw = (int) (iw * sw);
759 iy = (int) (iy * sh);
760 ih = (int) (ih * sh);
761 while (ix >= screenSize.width)
763 jalview.bin.Cache.log.debug(
764 "Window geometry location recall error: shifting horizontal to within screenbounds.");
765 ix -= screenSize.width;
767 while (iy >= screenSize.height)
769 jalview.bin.Cache.log.debug(
770 "Window geometry location recall error: shifting vertical to within screenbounds.");
771 iy -= screenSize.height;
773 jalview.bin.Cache.log.debug(
774 "Got last known dimensions for " + windowName + ": x:" + ix
775 + " y:" + iy + " width:" + iw + " height:" + ih);
777 // return dimensions for new instance
778 return new Rectangle(ix, iy, iw, ih);
783 private void doVamsasClientCheck()
785 if (jalview.bin.Cache.vamsasJarsPresent())
787 setupVamsasDisconnectedGui();
788 VamsasMenu.setVisible(true);
789 final Desktop us = this;
790 VamsasMenu.addMenuListener(new MenuListener()
792 // this listener remembers when the menu was first selected, and
793 // doesn't rebuild the session list until it has been cleared and
795 boolean refresh = true;
798 public void menuCanceled(MenuEvent e)
804 public void menuDeselected(MenuEvent e)
810 public void menuSelected(MenuEvent e)
814 us.buildVamsasStMenu();
819 vamsasStart.setVisible(true);
823 void showPasteMenu(int x, int y)
825 JPopupMenu popup = new JPopupMenu();
826 JMenuItem item = new JMenuItem(
827 MessageManager.getString("label.paste_new_window"));
828 item.addActionListener(new ActionListener()
831 public void actionPerformed(ActionEvent evt)
838 popup.show(this, x, y);
845 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
846 Transferable contents = c.getContents(this);
848 if (contents != null)
850 String file = (String) contents
851 .getTransferData(DataFlavor.stringFlavor);
853 FileFormatI format = new IdentifyFile().identify(file,
854 DataSourceType.PASTE);
856 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
859 } catch (Exception ex)
862 "Unable to paste alignment from system clipboard:\n" + ex);
867 * Adds and opens the given frame to the desktop
878 public static synchronized void addInternalFrame(
879 final JInternalFrame frame, String title, int w, int h)
881 addInternalFrame(frame, title, true, w, h, true, false);
885 * Add an internal frame to the Jalview desktop
892 * When true, display frame immediately, otherwise, caller must call
893 * setVisible themselves.
899 public static synchronized void addInternalFrame(
900 final JInternalFrame frame, String title, boolean makeVisible,
903 addInternalFrame(frame, title, makeVisible, w, h, true, false);
907 * Add an internal frame to the Jalview desktop and make it visible
920 public static synchronized void addInternalFrame(
921 final JInternalFrame frame, String title, int w, int h,
924 addInternalFrame(frame, title, true, w, h, resizable, false);
928 * Add an internal frame to the Jalview desktop
935 * When true, display frame immediately, otherwise, caller must call
936 * setVisible themselves.
943 * @param ignoreMinSize
944 * Do not set the default minimum size for frame
946 public static synchronized void addInternalFrame(
947 final JInternalFrame frame, String title, boolean makeVisible,
948 int w, int h, boolean resizable, boolean ignoreMinSize)
951 // TODO: allow callers to determine X and Y position of frame (eg. via
953 // TODO: consider fixing method to update entries in the window submenu with
954 // the current window title
956 frame.setTitle(title);
957 if (frame.getWidth() < 1 || frame.getHeight() < 1)
961 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
962 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
963 // IF JALVIEW IS RUNNING HEADLESS
964 // ///////////////////////////////////////////////
965 if (instance == null || (System.getProperty("java.awt.headless") != null
966 && System.getProperty("java.awt.headless").equals("true")))
975 frame.setMinimumSize(
976 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
978 // Set default dimension for Alignment Frame window.
979 // The Alignment Frame window could be added from a number of places,
981 // I did this here in order not to miss out on any Alignment frame.
982 if (frame instanceof AlignFrame)
984 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
985 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
989 frame.setVisible(makeVisible);
990 frame.setClosable(true);
991 frame.setResizable(resizable);
992 frame.setMaximizable(resizable);
993 frame.setIconifiable(resizable);
994 frame.setOpaque(false);
996 if (frame.getX() < 1 && frame.getY() < 1)
998 frame.setLocation(xOffset * openFrameCount,
999 yOffset * ((openFrameCount - 1) % 10) + yOffset);
1003 * add an entry for the new frame in the Window menu
1004 * (and remove it when the frame is closed)
1006 final JMenuItem menuItem = new JMenuItem(title);
1007 frame.addInternalFrameListener(new InternalFrameAdapter()
1010 public void internalFrameActivated(InternalFrameEvent evt)
1012 JInternalFrame itf = desktop.getSelectedFrame();
1015 if (itf instanceof AlignFrame)
1017 Jalview.setCurrentAlignFrame((AlignFrame) itf);
1024 public void internalFrameClosed(InternalFrameEvent evt)
1026 PaintRefresher.RemoveComponent(frame);
1029 * defensive check to prevent frames being
1030 * added half off the window
1032 if (openFrameCount > 0)
1038 * ensure no reference to alignFrame retained by menu item listener
1040 if (menuItem.getActionListeners().length > 0)
1042 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
1044 windowMenu.remove(menuItem);
1048 menuItem.addActionListener(new ActionListener()
1051 public void actionPerformed(ActionEvent e)
1055 frame.setSelected(true);
1056 frame.setIcon(false);
1057 } catch (java.beans.PropertyVetoException ex)
1064 setKeyBindings(frame);
1068 windowMenu.add(menuItem);
1073 frame.setSelected(true);
1074 frame.requestFocus();
1075 } catch (java.beans.PropertyVetoException ve)
1077 } catch (java.lang.ClassCastException cex)
1080 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
1086 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
1091 private static void setKeyBindings(JInternalFrame frame)
1093 @SuppressWarnings("serial")
1094 final Action closeAction = new AbstractAction()
1097 public void actionPerformed(ActionEvent e)
1104 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1106 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1107 InputEvent.CTRL_DOWN_MASK);
1108 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1109 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1111 InputMap inputMap = frame
1112 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1113 String ctrlW = ctrlWKey.toString();
1114 inputMap.put(ctrlWKey, ctrlW);
1115 inputMap.put(cmdWKey, ctrlW);
1117 ActionMap actionMap = frame.getActionMap();
1118 actionMap.put(ctrlW, closeAction);
1122 public void lostOwnership(Clipboard clipboard, Transferable contents)
1126 Desktop.jalviewClipboard = null;
1129 internalCopy = false;
1133 public void dragEnter(DropTargetDragEvent evt)
1138 public void dragExit(DropTargetEvent evt)
1143 public void dragOver(DropTargetDragEvent evt)
1148 public void dropActionChanged(DropTargetDragEvent evt)
1159 public void drop(DropTargetDropEvent evt)
1161 boolean success = true;
1162 // JAL-1552 - acceptDrop required before getTransferable call for
1163 // Java's Transferable for native dnd
1164 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1165 Transferable t = evt.getTransferable();
1166 List<String> files = new ArrayList<>();
1167 List<DataSourceType> protocols = new ArrayList<>();
1171 Desktop.transferFromDropTarget(files, protocols, evt, t);
1172 } catch (Exception e)
1174 e.printStackTrace();
1182 for (int i = 0; i < files.size(); i++)
1184 String file = files.get(i).toString();
1185 DataSourceType protocol = (protocols == null)
1186 ? DataSourceType.FILE
1188 FileFormatI format = null;
1190 if (file.endsWith(".jar"))
1192 format = FileFormat.Jalview;
1197 format = new IdentifyFile().identify(file, protocol);
1200 new FileLoader().LoadFile(file, protocol, format);
1203 } catch (Exception ex)
1208 evt.dropComplete(success); // need this to ensure input focus is properly
1209 // transfered to any new windows created
1219 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1221 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1222 JalviewFileChooser chooser = JalviewFileChooser
1223 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1225 chooser.setFileView(new JalviewFileView());
1226 chooser.setDialogTitle(
1227 MessageManager.getString("label.open_local_file"));
1228 chooser.setToolTipText(MessageManager.getString("action.open"));
1230 int value = chooser.showOpenDialog(this);
1232 if (value == JalviewFileChooser.APPROVE_OPTION)
1234 String choice = chooser.getSelectedFile().getPath();
1235 Cache.setProperty("LAST_DIRECTORY",
1236 chooser.getSelectedFile().getParent());
1238 FileFormatI format = chooser.getSelectedFormat();
1241 * Call IdentifyFile to verify the file contains what its extension implies.
1242 * Skip this step for dynamically added file formats, because
1243 * IdentifyFile does not know how to recognise them.
1245 if (FileFormats.getInstance().isIdentifiable(format))
1249 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1250 } catch (FileFormatException e)
1252 // format = null; //??
1256 if (viewport != null)
1258 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1263 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1275 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1277 // This construct allows us to have a wider textfield
1279 JLabel label = new JLabel(
1280 MessageManager.getString("label.input_file_url"));
1281 final JComboBox history = new JComboBox();
1283 JPanel panel = new JPanel(new GridLayout(2, 1));
1286 history.setPreferredSize(new Dimension(400, 20));
1287 history.setEditable(true);
1288 history.addItem("http://www.");
1290 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1294 if (historyItems != null)
1296 st = new StringTokenizer(historyItems, "\t");
1298 while (st.hasMoreTokens())
1300 history.addItem(st.nextElement());
1304 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1305 MessageManager.getString("label.input_alignment_from_url"),
1306 JvOptionPane.OK_CANCEL_OPTION);
1308 if (reply != JvOptionPane.OK_OPTION)
1313 String url = history.getSelectedItem().toString();
1315 if (url.toLowerCase().endsWith(".jar"))
1317 if (viewport != null)
1319 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1320 FileFormat.Jalview);
1324 new FileLoader().LoadFile(url, DataSourceType.URL,
1325 FileFormat.Jalview);
1330 FileFormatI format = null;
1333 format = new IdentifyFile().identify(url, DataSourceType.URL);
1334 } catch (FileFormatException e)
1336 // TODO revise error handling, distinguish between
1337 // URL not found and response not valid
1342 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1343 MessageManager.formatMessage("label.couldnt_locate",
1346 MessageManager.getString("label.url_not_found"),
1347 JvOptionPane.WARNING_MESSAGE);
1352 if (viewport != null)
1354 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1359 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1365 * Opens the CutAndPaste window for the user to paste an alignment in to
1368 * - if not null, the pasted alignment is added to the current
1369 * alignment; if null, to a new alignment window
1372 public void inputTextboxMenuItem_actionPerformed(
1373 AlignmentViewPanel viewPanel)
1375 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1376 cap.setForInput(viewPanel);
1377 Desktop.addInternalFrame(cap,
1378 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1388 System.out.println("********** Desktop.quit()");
1389 System.out.println(savingFiles.toString());
1390 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1391 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1393 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1394 screen.height + "");
1395 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1396 getWidth(), getHeight()));
1398 if (jconsole != null)
1400 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1401 jconsole.stopConsole();
1405 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1408 if (dialogExecutor != null)
1410 dialogExecutor.shutdownNow();
1412 closeAll_actionPerformed(null);
1414 if (groovyConsole != null)
1416 // suppress a possible repeat prompt to save script
1417 groovyConsole.setDirty(false);
1418 groovyConsole.exit();
1423 private void storeLastKnownDimensions(String string, Rectangle jc)
1425 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1426 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1427 + " height:" + jc.height);
1429 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1430 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1431 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1432 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1442 public void aboutMenuItem_actionPerformed(ActionEvent e)
1444 // StringBuffer message = getAboutMessage(false);
1445 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1447 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1448 new Thread(new Runnable()
1453 new SplashScreen(true);
1458 public StringBuffer getAboutMessage(boolean shortv)
1460 StringBuffer message = new StringBuffer();
1461 message.append("<html>");
1464 message.append("<h1><strong>Version: "
1465 + jalview.bin.Cache.getProperty("VERSION")
1466 + "</strong></h1>");
1467 message.append("<strong>Last Updated: <em>"
1468 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1469 + "</em></strong>");
1475 message.append("<strong>Version "
1476 + jalview.bin.Cache.getProperty("VERSION")
1477 + "; last updated: "
1478 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1481 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1482 .equals("Checking"))
1484 message.append("<br>...Checking latest version...</br>");
1486 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1487 .equals(jalview.bin.Cache.getProperty("VERSION")))
1489 boolean red = false;
1490 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1491 .indexOf("automated build") == -1)
1494 // Displayed when code version and jnlp version do not match and code
1495 // version is not a development build
1496 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1499 message.append("<br>!! Version "
1500 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1502 + " is available for download from "
1503 + jalview.bin.Cache.getDefault("www.jalview.org",
1504 "http://www.jalview.org")
1508 message.append("</div>");
1511 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1513 "The Jalview Authors (See AUTHORS file for current list)")
1514 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1515 + "<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"
1516 + "<br><br>If you use Jalview, please cite:"
1517 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1518 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1519 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1531 public void documentationMenuItem_actionPerformed(ActionEvent e)
1535 Help.showHelpWindow();
1536 } catch (Exception ex)
1542 public void closeAll_actionPerformed(ActionEvent e)
1544 // TODO show a progress bar while closing?
1545 JInternalFrame[] frames = desktop.getAllFrames();
1546 for (int i = 0; i < frames.length; i++)
1550 frames[i].setClosed(true);
1551 } catch (java.beans.PropertyVetoException ex)
1555 Jalview.setCurrentAlignFrame(null);
1556 System.out.println("ALL CLOSED");
1557 if (v_client != null)
1559 // TODO clear binding to vamsas document objects on close_all
1563 * reset state of singleton objects as appropriate (clear down session state
1564 * when all windows are closed)
1566 StructureSelectionManager ssm = StructureSelectionManager
1567 .getStructureSelectionManager(this);
1575 public void raiseRelated_actionPerformed(ActionEvent e)
1577 reorderAssociatedWindows(false, false);
1581 public void minimizeAssociated_actionPerformed(ActionEvent e)
1583 reorderAssociatedWindows(true, false);
1586 void closeAssociatedWindows()
1588 reorderAssociatedWindows(false, true);
1594 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1598 protected void garbageCollect_actionPerformed(ActionEvent e)
1600 // We simply collect the garbage
1601 jalview.bin.Cache.log.debug("Collecting garbage...");
1603 jalview.bin.Cache.log.debug("Finished garbage collection.");
1610 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1614 protected void showMemusage_actionPerformed(ActionEvent e)
1616 desktop.showMemoryUsage(showMemusage.isSelected());
1623 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1627 protected void showConsole_actionPerformed(ActionEvent e)
1629 showConsole(showConsole.isSelected());
1632 Console jconsole = null;
1635 * control whether the java console is visible or not
1639 void showConsole(boolean selected)
1641 showConsole.setSelected(selected);
1642 // TODO: decide if we should update properties file
1643 Cache.setProperty("SHOW_JAVA_CONSOLE",
1644 Boolean.valueOf(selected).toString());
1645 jconsole.setVisible(selected);
1648 void reorderAssociatedWindows(boolean minimize, boolean close)
1650 JInternalFrame[] frames = desktop.getAllFrames();
1651 if (frames == null || frames.length < 1)
1656 AlignmentViewport source = null, target = null;
1657 if (frames[0] instanceof AlignFrame)
1659 source = ((AlignFrame) frames[0]).getCurrentView();
1661 else if (frames[0] instanceof TreePanel)
1663 source = ((TreePanel) frames[0]).getViewPort();
1665 else if (frames[0] instanceof PCAPanel)
1667 source = ((PCAPanel) frames[0]).av;
1669 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1671 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1676 for (int i = 0; i < frames.length; i++)
1679 if (frames[i] == null)
1683 if (frames[i] instanceof AlignFrame)
1685 target = ((AlignFrame) frames[i]).getCurrentView();
1687 else if (frames[i] instanceof TreePanel)
1689 target = ((TreePanel) frames[i]).getViewPort();
1691 else if (frames[i] instanceof PCAPanel)
1693 target = ((PCAPanel) frames[i]).av;
1695 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1697 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1700 if (source == target)
1706 frames[i].setClosed(true);
1710 frames[i].setIcon(minimize);
1713 frames[i].toFront();
1717 } catch (java.beans.PropertyVetoException ex)
1732 protected void preferences_actionPerformed(ActionEvent e)
1738 * Shows a file chooser dialog and writes out the current session as a Jalview
1742 public void saveState_actionPerformed()
1744 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1747 chooser.setFileView(new JalviewFileView());
1748 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1750 int value = chooser.showSaveDialog(this);
1752 if (value == JalviewFileChooser.APPROVE_OPTION)
1754 final Desktop me = this;
1755 final java.io.File choice = chooser.getSelectedFile();
1756 setProjectFile(choice);
1758 new Thread(new Runnable()
1763 // TODO: refactor to Jalview desktop session controller action.
1764 setProgressBar(MessageManager.formatMessage(
1765 "label.saving_jalview_project", new Object[]
1766 { choice.getName() }), choice.hashCode());
1767 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1768 choice.getParent());
1769 // TODO catch and handle errors for savestate
1770 // TODO prevent user from messing with the Desktop whilst we're saving
1773 new Jalview2XML().saveState(choice);
1774 } catch (OutOfMemoryError oom)
1777 "Whilst saving current state to " + choice.getName(),
1779 } catch (Exception ex)
1782 "Problems whilst trying to save to " + choice.getName(),
1784 JvOptionPane.showMessageDialog(me,
1785 MessageManager.formatMessage(
1786 "label.error_whilst_saving_current_state_to",
1788 { choice.getName() }),
1789 MessageManager.getString("label.couldnt_save_project"),
1790 JvOptionPane.WARNING_MESSAGE);
1792 setProgressBar(null, choice.hashCode());
1798 private void setProjectFile(File choice)
1800 this.projectFile = choice;
1803 public File getProjectFile()
1805 return this.projectFile;
1809 * Shows a file chooser dialog and tries to read in the selected file as a
1813 public void loadState_actionPerformed()
1815 final String[] suffix = new String[] { "jvp", "jar" };
1816 final String[] desc = new String[] { "Jalview Project",
1817 "Jalview Project (old)" };
1818 JalviewFileChooser chooser = new JalviewFileChooser(
1819 Cache.getProperty("LAST_DIRECTORY"), suffix,
1822 chooser.setFileView(new JalviewFileView());
1823 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1825 int value = chooser.showOpenDialog(this);
1827 if (value == JalviewFileChooser.APPROVE_OPTION)
1829 final File selectedFile = chooser.getSelectedFile();
1830 setProjectFile(selectedFile);
1831 final String choice = selectedFile.getAbsolutePath();
1832 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1833 new Thread(new Runnable()
1838 setProgressBar(MessageManager.formatMessage(
1839 "label.loading_jalview_project", new Object[]
1840 { choice }), choice.hashCode());
1843 new Jalview2XML().loadJalviewAlign(choice);
1844 } catch (OutOfMemoryError oom)
1846 new OOMWarning("Whilst loading project from " + choice, oom);
1847 } catch (Exception ex)
1850 "Problems whilst loading project from " + choice, ex);
1851 JvOptionPane.showMessageDialog(Desktop.desktop,
1852 MessageManager.formatMessage(
1853 "label.error_whilst_loading_project_from",
1856 MessageManager.getString("label.couldnt_load_project"),
1857 JvOptionPane.WARNING_MESSAGE);
1859 setProgressBar(null, choice.hashCode());
1866 public void inputSequence_actionPerformed(ActionEvent e)
1868 new SequenceFetcher(this);
1871 JPanel progressPanel;
1873 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1875 public void startLoading(final String fileName)
1877 if (fileLoadingCount == 0)
1879 fileLoadingPanels.add(addProgressPanel(MessageManager
1880 .formatMessage("label.loading_file", new Object[]
1886 private JPanel addProgressPanel(String string)
1888 if (progressPanel == null)
1890 progressPanel = new JPanel(new GridLayout(1, 1));
1891 totalProgressCount = 0;
1892 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1894 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1895 JProgressBar progressBar = new JProgressBar();
1896 progressBar.setIndeterminate(true);
1898 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1900 thisprogress.add(progressBar, BorderLayout.CENTER);
1901 progressPanel.add(thisprogress);
1902 ((GridLayout) progressPanel.getLayout()).setRows(
1903 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1904 ++totalProgressCount;
1905 instance.validate();
1906 return thisprogress;
1909 int totalProgressCount = 0;
1911 private void removeProgressPanel(JPanel progbar)
1913 if (progressPanel != null)
1915 synchronized (progressPanel)
1917 progressPanel.remove(progbar);
1918 GridLayout gl = (GridLayout) progressPanel.getLayout();
1919 gl.setRows(gl.getRows() - 1);
1920 if (--totalProgressCount < 1)
1922 this.getContentPane().remove(progressPanel);
1923 progressPanel = null;
1930 public void stopLoading()
1933 if (fileLoadingCount < 1)
1935 while (fileLoadingPanels.size() > 0)
1937 removeProgressPanel(fileLoadingPanels.remove(0));
1939 fileLoadingPanels.clear();
1940 fileLoadingCount = 0;
1945 public static int getViewCount(String alignmentId)
1947 AlignmentViewport[] aps = getViewports(alignmentId);
1948 return (aps == null) ? 0 : aps.length;
1953 * @param alignmentId
1954 * - if null, all sets are returned
1955 * @return all AlignmentPanels concerning the alignmentId sequence set
1957 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1959 if (Desktop.desktop == null)
1961 // no frames created and in headless mode
1962 // TODO: verify that frames are recoverable when in headless mode
1965 List<AlignmentPanel> aps = new ArrayList<>();
1966 AlignFrame[] frames = getAlignFrames();
1971 for (AlignFrame af : frames)
1973 for (AlignmentPanel ap : af.alignPanels)
1975 if (alignmentId == null
1976 || alignmentId.equals(ap.av.getSequenceSetId()))
1982 if (aps.size() == 0)
1986 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1991 * get all the viewports on an alignment.
1993 * @param sequenceSetId
1994 * unique alignment id (may be null - all viewports returned in that
1996 * @return all viewports on the alignment bound to sequenceSetId
1998 public static AlignmentViewport[] getViewports(String sequenceSetId)
2000 List<AlignmentViewport> viewp = new ArrayList<>();
2001 if (desktop != null)
2003 AlignFrame[] frames = Desktop.getAlignFrames();
2005 for (AlignFrame afr : frames)
2007 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
2008 .equals(sequenceSetId))
2010 if (afr.alignPanels != null)
2012 for (AlignmentPanel ap : afr.alignPanels)
2014 if (sequenceSetId == null
2015 || sequenceSetId.equals(ap.av.getSequenceSetId()))
2023 viewp.add(afr.getViewport());
2027 if (viewp.size() > 0)
2029 return viewp.toArray(new AlignmentViewport[viewp.size()]);
2036 * Explode the views in the given frame into separate AlignFrame
2040 public static void explodeViews(AlignFrame af)
2042 int size = af.alignPanels.size();
2048 for (int i = 0; i < size; i++)
2050 AlignmentPanel ap = af.alignPanels.get(i);
2051 AlignFrame newaf = new AlignFrame(ap);
2054 * Restore the view's last exploded frame geometry if known. Multiple
2055 * views from one exploded frame share and restore the same (frame)
2056 * position and size.
2058 Rectangle geometry = ap.av.getExplodedGeometry();
2059 if (geometry != null)
2061 newaf.setBounds(geometry);
2064 ap.av.setGatherViewsHere(false);
2066 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2067 AlignFrame.DEFAULT_HEIGHT);
2070 af.alignPanels.clear();
2071 af.closeMenuItem_actionPerformed(true);
2076 * Gather expanded views (separate AlignFrame's) with the same sequence set
2077 * identifier back in to this frame as additional views, and close the
2078 * expanded views. Note the expanded frames may themselves have multiple
2079 * views. We take the lot.
2083 public void gatherViews(AlignFrame source)
2085 source.viewport.setGatherViewsHere(true);
2086 source.viewport.setExplodedGeometry(source.getBounds());
2087 JInternalFrame[] frames = desktop.getAllFrames();
2088 String viewId = source.viewport.getSequenceSetId();
2090 for (int t = 0; t < frames.length; t++)
2092 if (frames[t] instanceof AlignFrame && frames[t] != source)
2094 AlignFrame af = (AlignFrame) frames[t];
2095 boolean gatherThis = false;
2096 for (int a = 0; a < af.alignPanels.size(); a++)
2098 AlignmentPanel ap = af.alignPanels.get(a);
2099 if (viewId.equals(ap.av.getSequenceSetId()))
2102 ap.av.setGatherViewsHere(false);
2103 ap.av.setExplodedGeometry(af.getBounds());
2104 source.addAlignmentPanel(ap, false);
2110 af.alignPanels.clear();
2111 af.closeMenuItem_actionPerformed(true);
2118 jalview.gui.VamsasApplication v_client = null;
2121 public void vamsasImport_actionPerformed(ActionEvent e)
2123 if (v_client == null)
2125 // Load and try to start a session.
2126 JalviewFileChooser chooser = new JalviewFileChooser(
2127 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2129 chooser.setFileView(new JalviewFileView());
2130 chooser.setDialogTitle(
2131 MessageManager.getString("label.open_saved_vamsas_session"));
2132 chooser.setToolTipText(MessageManager.getString(
2133 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2135 int value = chooser.showOpenDialog(this);
2137 if (value == JalviewFileChooser.APPROVE_OPTION)
2139 String fle = chooser.getSelectedFile().toString();
2140 if (!vamsasImport(chooser.getSelectedFile()))
2142 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2143 MessageManager.formatMessage(
2144 "label.couldnt_import_as_vamsas_session",
2148 .getString("label.vamsas_document_import_failed"),
2149 JvOptionPane.ERROR_MESSAGE);
2155 jalview.bin.Cache.log.error(
2156 "Implementation error - load session from a running session is not supported.");
2161 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2164 * @return true if import was a success and a session was started.
2166 public boolean vamsasImport(URL url)
2168 // TODO: create progress bar
2169 if (v_client != null)
2172 jalview.bin.Cache.log.error(
2173 "Implementation error - load session from a running session is not supported.");
2179 // copy the URL content to a temporary local file
2180 // TODO: be a bit cleverer here with nio (?!)
2181 File file = File.createTempFile("vdocfromurl", ".vdj");
2182 FileOutputStream fos = new FileOutputStream(file);
2183 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2184 byte[] buffer = new byte[2048];
2186 while ((ln = bis.read(buffer)) > -1)
2188 fos.write(buffer, 0, ln);
2192 v_client = new jalview.gui.VamsasApplication(this, file,
2193 url.toExternalForm());
2194 } catch (Exception ex)
2196 jalview.bin.Cache.log.error(
2197 "Failed to create new vamsas session from contents of URL "
2202 setupVamsasConnectedGui();
2203 v_client.initial_update(); // TODO: thread ?
2204 return v_client.inSession();
2208 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2211 * @return true if import was a success and a session was started.
2213 public boolean vamsasImport(File file)
2215 if (v_client != null)
2218 jalview.bin.Cache.log.error(
2219 "Implementation error - load session from a running session is not supported.");
2223 setProgressBar(MessageManager.formatMessage(
2224 "status.importing_vamsas_session_from", new Object[]
2225 { file.getName() }), file.hashCode());
2228 v_client = new jalview.gui.VamsasApplication(this, file, null);
2229 } catch (Exception ex)
2231 setProgressBar(MessageManager.formatMessage(
2232 "status.importing_vamsas_session_from", new Object[]
2233 { file.getName() }), file.hashCode());
2234 jalview.bin.Cache.log.error(
2235 "New vamsas session from existing session file failed:", ex);
2238 setupVamsasConnectedGui();
2239 v_client.initial_update(); // TODO: thread ?
2240 setProgressBar(MessageManager.formatMessage(
2241 "status.importing_vamsas_session_from", new Object[]
2242 { file.getName() }), file.hashCode());
2243 return v_client.inSession();
2246 public boolean joinVamsasSession(String mysesid)
2248 if (v_client != null)
2250 throw new Error(MessageManager
2251 .getString("error.try_join_vamsas_session_another"));
2253 if (mysesid == null)
2256 MessageManager.getString("error.invalid_vamsas_session_id"));
2258 v_client = new VamsasApplication(this, mysesid);
2259 setupVamsasConnectedGui();
2260 v_client.initial_update();
2261 return (v_client.inSession());
2265 public void vamsasStart_actionPerformed(ActionEvent e)
2267 if (v_client == null)
2270 // we just start a default session for moment.
2272 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2273 * getProperty("LAST_DIRECTORY"));
2275 * chooser.setFileView(new JalviewFileView());
2276 * chooser.setDialogTitle("Load Vamsas file");
2277 * chooser.setToolTipText("Import");
2279 * int value = chooser.showOpenDialog(this);
2281 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2282 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2284 v_client = new VamsasApplication(this);
2285 setupVamsasConnectedGui();
2286 v_client.initial_update(); // TODO: thread ?
2290 // store current data in session.
2291 v_client.push_update(); // TODO: thread
2295 protected void setupVamsasConnectedGui()
2297 vamsasStart.setText(MessageManager.getString("label.session_update"));
2298 vamsasSave.setVisible(true);
2299 vamsasStop.setVisible(true);
2300 vamsasImport.setVisible(false); // Document import to existing session is
2301 // not possible for vamsas-client-1.0.
2304 protected void setupVamsasDisconnectedGui()
2306 vamsasSave.setVisible(false);
2307 vamsasStop.setVisible(false);
2308 vamsasImport.setVisible(true);
2310 .setText(MessageManager.getString("label.new_vamsas_session"));
2314 public void vamsasStop_actionPerformed(ActionEvent e)
2316 if (v_client != null)
2318 v_client.end_session();
2320 setupVamsasDisconnectedGui();
2324 protected void buildVamsasStMenu()
2326 if (v_client == null)
2328 String[] sess = null;
2331 sess = VamsasApplication.getSessionList();
2332 } catch (Exception e)
2334 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2340 jalview.bin.Cache.log.debug(
2341 "Got current sessions list: " + sess.length + " entries.");
2342 VamsasStMenu.removeAll();
2343 for (int i = 0; i < sess.length; i++)
2345 JMenuItem sessit = new JMenuItem();
2346 sessit.setText(sess[i]);
2347 sessit.setToolTipText(MessageManager
2348 .formatMessage("label.connect_to_session", new Object[]
2350 final Desktop dsktp = this;
2351 final String mysesid = sess[i];
2352 sessit.addActionListener(new ActionListener()
2356 public void actionPerformed(ActionEvent e)
2358 if (dsktp.v_client == null)
2360 Thread rthr = new Thread(new Runnable()
2366 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2367 dsktp.setupVamsasConnectedGui();
2368 dsktp.v_client.initial_update();
2376 VamsasStMenu.add(sessit);
2378 // don't show an empty menu.
2379 VamsasStMenu.setVisible(sess.length > 0);
2384 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2385 VamsasStMenu.removeAll();
2386 VamsasStMenu.setVisible(false);
2391 // Not interested in the content. Just hide ourselves.
2392 VamsasStMenu.setVisible(false);
2397 public void vamsasSave_actionPerformed(ActionEvent e)
2399 if (v_client != null)
2401 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2402 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2405 chooser.setFileView(new JalviewFileView());
2406 chooser.setDialogTitle(MessageManager
2407 .getString("label.save_vamsas_document_archive"));
2409 int value = chooser.showSaveDialog(this);
2411 if (value == JalviewFileChooser.APPROVE_OPTION)
2413 java.io.File choice = chooser.getSelectedFile();
2414 JPanel progpanel = addProgressPanel(MessageManager
2415 .formatMessage("label.saving_vamsas_doc", new Object[]
2416 { choice.getName() }));
2417 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2418 String warnmsg = null;
2419 String warnttl = null;
2422 v_client.vclient.storeDocument(choice);
2425 warnttl = "Serious Problem saving Vamsas Document";
2426 warnmsg = ex.toString();
2427 jalview.bin.Cache.log
2428 .error("Error Whilst saving document to " + choice, ex);
2430 } catch (Exception ex)
2432 warnttl = "Problem saving Vamsas Document.";
2433 warnmsg = ex.toString();
2434 jalview.bin.Cache.log.warn(
2435 "Exception Whilst saving document to " + choice, ex);
2438 removeProgressPanel(progpanel);
2439 if (warnmsg != null)
2441 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2443 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2449 JPanel vamUpdate = null;
2452 * hide vamsas user gui bits when a vamsas document event is being handled.
2455 * true to hide gui, false to reveal gui
2457 public void setVamsasUpdate(boolean b)
2459 Cache.log.debug("Setting gui for Vamsas update "
2460 + (b ? "in progress" : "finished"));
2462 if (vamUpdate != null)
2464 this.removeProgressPanel(vamUpdate);
2468 vamUpdate = this.addProgressPanel(
2469 MessageManager.getString("label.updating_vamsas_session"));
2471 vamsasStart.setVisible(!b);
2472 vamsasStop.setVisible(!b);
2473 vamsasSave.setVisible(!b);
2476 public JInternalFrame[] getAllFrames()
2478 return desktop.getAllFrames();
2482 * Checks the given url to see if it gives a response indicating that the user
2483 * should be informed of a new questionnaire.
2487 public void checkForQuestionnaire(String url)
2489 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2490 // javax.swing.SwingUtilities.invokeLater(jvq);
2491 new Thread(jvq).start();
2494 public void checkURLLinks()
2496 // Thread off the URL link checker
2497 addDialogThread(new Runnable()
2502 if (Cache.getDefault("CHECKURLLINKS", true))
2504 // check what the actual links are - if it's just the default don't
2505 // bother with the warning
2506 List<String> links = Preferences.sequenceUrlLinks
2509 // only need to check links if there is one with a
2510 // SEQUENCE_ID which is not the default EMBL_EBI link
2511 ListIterator<String> li = links.listIterator();
2512 boolean check = false;
2513 List<JLabel> urls = new ArrayList<>();
2514 while (li.hasNext())
2516 String link = li.next();
2517 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2518 && !UrlConstants.isDefaultString(link))
2521 int barPos = link.indexOf("|");
2522 String urlMsg = barPos == -1 ? link
2523 : link.substring(0, barPos) + ": "
2524 + link.substring(barPos + 1);
2525 urls.add(new JLabel(urlMsg));
2533 // ask user to check in case URL links use old style tokens
2534 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2535 JPanel msgPanel = new JPanel();
2536 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2537 msgPanel.add(Box.createVerticalGlue());
2538 JLabel msg = new JLabel(MessageManager
2539 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2540 JLabel msg2 = new JLabel(MessageManager
2541 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2543 for (JLabel url : urls)
2549 final JCheckBox jcb = new JCheckBox(
2550 MessageManager.getString("label.do_not_display_again"));
2551 jcb.addActionListener(new ActionListener()
2554 public void actionPerformed(ActionEvent e)
2556 // update Cache settings for "don't show this again"
2557 boolean showWarningAgain = !jcb.isSelected();
2558 Cache.setProperty("CHECKURLLINKS",
2559 Boolean.valueOf(showWarningAgain).toString());
2564 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2566 .getString("label.SEQUENCE_ID_no_longer_used"),
2567 JvOptionPane.WARNING_MESSAGE);
2574 * Proxy class for JDesktopPane which optionally displays the current memory
2575 * usage and highlights the desktop area with a red bar if free memory runs
2580 public class MyDesktopPane extends JDesktopPane implements Runnable
2583 private static final float ONE_MB = 1048576f;
2585 boolean showMemoryUsage = false;
2589 java.text.NumberFormat df;
2591 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2594 public MyDesktopPane(boolean showMemoryUsage)
2596 showMemoryUsage(showMemoryUsage);
2599 public void showMemoryUsage(boolean showMemory)
2601 this.showMemoryUsage = showMemory;
2604 Thread worker = new Thread(this);
2610 public boolean isShowMemoryUsage()
2612 return showMemoryUsage;
2618 df = java.text.NumberFormat.getNumberInstance();
2619 df.setMaximumFractionDigits(2);
2620 runtime = Runtime.getRuntime();
2622 while (showMemoryUsage)
2626 maxMemory = runtime.maxMemory() / ONE_MB;
2627 allocatedMemory = runtime.totalMemory() / ONE_MB;
2628 freeMemory = runtime.freeMemory() / ONE_MB;
2629 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2631 percentUsage = (totalFreeMemory / maxMemory) * 100;
2633 // if (percentUsage < 20)
2635 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2637 // instance.set.setBorder(border1);
2640 // sleep after showing usage
2642 } catch (Exception ex)
2644 ex.printStackTrace();
2650 public void paintComponent(Graphics g)
2652 if (showMemoryUsage && g != null && df != null)
2654 if (percentUsage < 20)
2656 g.setColor(Color.red);
2658 FontMetrics fm = g.getFontMetrics();
2661 g.drawString(MessageManager.formatMessage("label.memory_stats",
2663 { df.format(totalFreeMemory), df.format(maxMemory),
2664 df.format(percentUsage) }),
2665 10, getHeight() - fm.getHeight());
2672 * Accessor method to quickly get all the AlignmentFrames loaded.
2674 * @return an array of AlignFrame, or null if none found
2676 public static AlignFrame[] getAlignFrames()
2678 if (Jalview.isHeadlessMode())
2680 // Desktop.desktop is null in headless mode
2681 return new AlignFrame[] { Jalview.currentAlignFrame };
2684 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2690 List<AlignFrame> avp = new ArrayList<>();
2692 for (int i = frames.length - 1; i > -1; i--)
2694 if (frames[i] instanceof AlignFrame)
2696 avp.add((AlignFrame) frames[i]);
2698 else if (frames[i] instanceof SplitFrame)
2701 * Also check for a split frame containing an AlignFrame
2703 GSplitFrame sf = (GSplitFrame) frames[i];
2704 if (sf.getTopFrame() instanceof AlignFrame)
2706 avp.add((AlignFrame) sf.getTopFrame());
2708 if (sf.getBottomFrame() instanceof AlignFrame)
2710 avp.add((AlignFrame) sf.getBottomFrame());
2714 if (avp.size() == 0)
2718 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2723 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2727 public GStructureViewer[] getJmols()
2729 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2735 List<GStructureViewer> avp = new ArrayList<>();
2737 for (int i = frames.length - 1; i > -1; i--)
2739 if (frames[i] instanceof AppJmol)
2741 GStructureViewer af = (GStructureViewer) frames[i];
2745 if (avp.size() == 0)
2749 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2754 * Add Groovy Support to Jalview
2757 public void groovyShell_actionPerformed()
2761 openGroovyConsole();
2762 } catch (Exception ex)
2764 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2765 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2767 MessageManager.getString("label.couldnt_create_groovy_shell"),
2768 MessageManager.getString("label.groovy_support_failed"),
2769 JvOptionPane.ERROR_MESSAGE);
2774 * Open the Groovy console
2776 void openGroovyConsole()
2778 if (groovyConsole == null)
2780 groovyConsole = new groovy.ui.Console();
2781 groovyConsole.setVariable("Jalview", this);
2782 groovyConsole.run();
2785 * We allow only one console at a time, so that AlignFrame menu option
2786 * 'Calculate | Run Groovy script' is unambiguous.
2787 * Disable 'Groovy Console', and enable 'Run script', when the console is
2788 * opened, and the reverse when it is closed
2790 Window window = (Window) groovyConsole.getFrame();
2791 window.addWindowListener(new WindowAdapter()
2794 public void windowClosed(WindowEvent e)
2797 * rebind CMD-Q from Groovy Console to Jalview Quit
2800 enableExecuteGroovy(false);
2806 * show Groovy console window (after close and reopen)
2808 ((Window) groovyConsole.getFrame()).setVisible(true);
2811 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2812 * and disable opening a second console
2814 enableExecuteGroovy(true);
2818 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2819 * binding when opened
2821 protected void addQuitHandler()
2823 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2824 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2825 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2827 getRootPane().getActionMap().put("Quit", new AbstractAction()
2830 public void actionPerformed(ActionEvent e)
2838 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2841 * true if Groovy console is open
2843 public void enableExecuteGroovy(boolean enabled)
2846 * disable opening a second Groovy console
2847 * (or re-enable when the console is closed)
2849 groovyShell.setEnabled(!enabled);
2851 AlignFrame[] alignFrames = getAlignFrames();
2852 if (alignFrames != null)
2854 for (AlignFrame af : alignFrames)
2856 af.setGroovyEnabled(enabled);
2862 * Progress bars managed by the IProgressIndicator method.
2864 private Hashtable<Long, JPanel> progressBars;
2866 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2871 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2874 public void setProgressBar(String message, long id)
2876 if (progressBars == null)
2878 progressBars = new Hashtable<>();
2879 progressBarHandlers = new Hashtable<>();
2882 if (progressBars.get(new Long(id)) != null)
2884 JPanel panel = progressBars.remove(new Long(id));
2885 if (progressBarHandlers.contains(new Long(id)))
2887 progressBarHandlers.remove(new Long(id));
2889 removeProgressPanel(panel);
2893 progressBars.put(new Long(id), addProgressPanel(message));
2900 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2901 * jalview.gui.IProgressIndicatorHandler)
2904 public void registerHandler(final long id,
2905 final IProgressIndicatorHandler handler)
2907 if (progressBarHandlers == null
2908 || !progressBars.containsKey(new Long(id)))
2910 throw new Error(MessageManager.getString(
2911 "error.call_setprogressbar_before_registering_handler"));
2913 progressBarHandlers.put(new Long(id), handler);
2914 final JPanel progressPanel = progressBars.get(new Long(id));
2915 if (handler.canCancel())
2917 JButton cancel = new JButton(
2918 MessageManager.getString("action.cancel"));
2919 final IProgressIndicator us = this;
2920 cancel.addActionListener(new ActionListener()
2924 public void actionPerformed(ActionEvent e)
2926 handler.cancelActivity(id);
2927 us.setProgressBar(MessageManager
2928 .formatMessage("label.cancelled_params", new Object[]
2929 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2933 progressPanel.add(cancel, BorderLayout.EAST);
2939 * @return true if any progress bars are still active
2942 public boolean operationInProgress()
2944 if (progressBars != null && progressBars.size() > 0)
2952 * This will return the first AlignFrame holding the given viewport instance.
2953 * It will break if there are more than one AlignFrames viewing a particular
2957 * @return alignFrame for viewport
2959 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2961 if (desktop != null)
2963 AlignmentPanel[] aps = getAlignmentPanels(
2964 viewport.getSequenceSetId());
2965 for (int panel = 0; aps != null && panel < aps.length; panel++)
2967 if (aps[panel] != null && aps[panel].av == viewport)
2969 return aps[panel].alignFrame;
2976 public VamsasApplication getVamsasApplication()
2983 * flag set if jalview GUI is being operated programmatically
2985 private boolean inBatchMode = false;
2988 * check if jalview GUI is being operated programmatically
2990 * @return inBatchMode
2992 public boolean isInBatchMode()
2998 * set flag if jalview GUI is being operated programmatically
3000 * @param inBatchMode
3002 public void setInBatchMode(boolean inBatchMode)
3004 this.inBatchMode = inBatchMode;
3007 public void startServiceDiscovery()
3009 startServiceDiscovery(false);
3012 public void startServiceDiscovery(boolean blocking)
3014 boolean alive = true;
3015 Thread t0 = null, t1 = null, t2 = null;
3016 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3019 // todo: changesupport handlers need to be transferred
3020 if (discoverer == null)
3022 discoverer = new jalview.ws.jws1.Discoverer();
3023 // register PCS handler for desktop.
3024 discoverer.addPropertyChangeListener(changeSupport);
3026 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3027 // until we phase out completely
3028 (t0 = new Thread(discoverer)).start();
3031 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3033 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3034 .startDiscoverer(changeSupport);
3038 // TODO: do rest service discovery
3047 } catch (Exception e)
3050 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3051 || (t3 != null && t3.isAlive())
3052 || (t0 != null && t0.isAlive());
3058 * called to check if the service discovery process completed successfully.
3062 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3064 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3066 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3067 .getErrorMessages();
3070 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3072 if (serviceChangedDialog == null)
3074 // only run if we aren't already displaying one of these.
3075 addDialogThread(serviceChangedDialog = new Runnable()
3082 * JalviewDialog jd =new JalviewDialog() {
3084 * @Override protected void cancelPressed() { // TODO
3085 * Auto-generated method stub
3087 * }@Override protected void okPressed() { // TODO
3088 * Auto-generated method stub
3090 * }@Override protected void raiseClosed() { // TODO
3091 * Auto-generated method stub
3093 * } }; jd.initDialogFrame(new
3094 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3095 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3096 * + " or mis-configured HTTP proxy settings.<br/>" +
3097 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3099 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3100 * ), true, true, "Web Service Configuration Problem", 450,
3103 * jd.waitForInput();
3105 JvOptionPane.showConfirmDialog(Desktop.desktop,
3106 new JLabel("<html><table width=\"450\"><tr><td>"
3107 + ermsg + "</td></tr></table>"
3108 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3109 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3110 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3111 + " Tools->Preferences dialog box to change them.</p></html>"),
3112 "Web Service Configuration Problem",
3113 JvOptionPane.DEFAULT_OPTION,
3114 JvOptionPane.ERROR_MESSAGE);
3115 serviceChangedDialog = null;
3124 "Errors reported by JABA discovery service. Check web services preferences.\n"
3131 private Runnable serviceChangedDialog = null;
3134 * start a thread to open a URL in the configured browser. Pops up a warning
3135 * dialog to the user if there is an exception when calling out to the browser
3140 public static void showUrl(final String url)
3142 showUrl(url, Desktop.instance);
3146 * Like showUrl but allows progress handler to be specified
3150 * (null) or object implementing IProgressIndicator
3152 public static void showUrl(final String url,
3153 final IProgressIndicator progress)
3155 new Thread(new Runnable()
3162 if (progress != null)
3164 progress.setProgressBar(MessageManager
3165 .formatMessage("status.opening_params", new Object[]
3166 { url }), this.hashCode());
3168 jalview.util.BrowserLauncher.openURL(url);
3169 } catch (Exception ex)
3171 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3173 .getString("label.web_browser_not_found_unix"),
3174 MessageManager.getString("label.web_browser_not_found"),
3175 JvOptionPane.WARNING_MESSAGE);
3177 ex.printStackTrace();
3179 if (progress != null)
3181 progress.setProgressBar(null, this.hashCode());
3187 public static WsParamSetManager wsparamManager = null;
3189 public static ParamManager getUserParameterStore()
3191 if (wsparamManager == null)
3193 wsparamManager = new WsParamSetManager();
3195 return wsparamManager;
3199 * static hyperlink handler proxy method for use by Jalview's internal windows
3203 public static void hyperlinkUpdate(HyperlinkEvent e)
3205 if (e.getEventType() == EventType.ACTIVATED)
3210 url = e.getURL().toString();
3211 Desktop.showUrl(url);
3212 } catch (Exception x)
3216 if (Cache.log != null)
3218 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3223 "Couldn't handle string " + url + " as a URL.");
3226 // ignore any exceptions due to dud links.
3233 * single thread that handles display of dialogs to user.
3235 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3238 * flag indicating if dialogExecutor should try to acquire a permit
3240 private volatile boolean dialogPause = true;
3245 private java.util.concurrent.Semaphore block = new Semaphore(0);
3247 private static groovy.ui.Console groovyConsole;
3250 * add another dialog thread to the queue
3254 public void addDialogThread(final Runnable prompter)
3256 dialogExecutor.submit(new Runnable()
3266 } catch (InterruptedException x)
3271 if (instance == null)
3277 SwingUtilities.invokeAndWait(prompter);
3278 } catch (Exception q)
3280 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3286 public void startDialogQueue()
3288 // set the flag so we don't pause waiting for another permit and semaphore
3289 // the current task to begin
3290 dialogPause = false;
3295 protected void snapShotWindow_actionPerformed(ActionEvent e)
3299 ImageMaker im = new jalview.util.ImageMaker(
3300 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3301 getHeight(), of = new File("Jalview_snapshot"
3302 + System.currentTimeMillis() + ".eps"),
3303 "View of desktop", null, 0, false);
3306 paintAll(im.getGraphics());
3308 } catch (Exception q)
3310 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3314 Cache.log.info("Successfully written snapshot to file "
3315 + of.getAbsolutePath());
3319 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3320 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3321 * and location last time the view was expanded (if any). However it does not
3322 * remember the split pane divider location - this is set to match the
3323 * 'exploding' frame.
3327 public void explodeViews(SplitFrame sf)
3329 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3330 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3331 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3333 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3335 int viewCount = topPanels.size();
3342 * Processing in reverse order works, forwards order leaves the first panels
3343 * not visible. I don't know why!
3345 for (int i = viewCount - 1; i >= 0; i--)
3348 * Make new top and bottom frames. These take over the respective
3349 * AlignmentPanel objects, including their AlignmentViewports, so the
3350 * cdna/protein relationships between the viewports is carried over to the
3353 * explodedGeometry holds the (x, y) position of the previously exploded
3354 * SplitFrame, and the (width, height) of the AlignFrame component
3356 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3357 AlignFrame newTopFrame = new AlignFrame(topPanel);
3358 newTopFrame.setSize(oldTopFrame.getSize());
3359 newTopFrame.setVisible(true);
3360 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3361 .getExplodedGeometry();
3362 if (geometry != null)
3364 newTopFrame.setSize(geometry.getSize());
3367 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3368 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3369 newBottomFrame.setSize(oldBottomFrame.getSize());
3370 newBottomFrame.setVisible(true);
3371 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3372 .getExplodedGeometry();
3373 if (geometry != null)
3375 newBottomFrame.setSize(geometry.getSize());
3378 topPanel.av.setGatherViewsHere(false);
3379 bottomPanel.av.setGatherViewsHere(false);
3380 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3382 if (geometry != null)
3384 splitFrame.setLocation(geometry.getLocation());
3386 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3390 * Clear references to the panels (now relocated in the new SplitFrames)
3391 * before closing the old SplitFrame.
3394 bottomPanels.clear();
3399 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3400 * back into the given SplitFrame as additional views. Note that the gathered
3401 * frames may themselves have multiple views.
3405 public void gatherViews(GSplitFrame source)
3408 * special handling of explodedGeometry for a view within a SplitFrame: - it
3409 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3410 * height) of the AlignFrame component
3412 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3413 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3414 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3415 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3416 myBottomFrame.viewport
3417 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3418 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3419 myTopFrame.viewport.setGatherViewsHere(true);
3420 myBottomFrame.viewport.setGatherViewsHere(true);
3421 String topViewId = myTopFrame.viewport.getSequenceSetId();
3422 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3424 JInternalFrame[] frames = desktop.getAllFrames();
3425 for (JInternalFrame frame : frames)
3427 if (frame instanceof SplitFrame && frame != source)
3429 SplitFrame sf = (SplitFrame) frame;
3430 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3431 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3432 boolean gatherThis = false;
3433 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3435 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3436 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3437 if (topViewId.equals(topPanel.av.getSequenceSetId())
3438 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3441 topPanel.av.setGatherViewsHere(false);
3442 bottomPanel.av.setGatherViewsHere(false);
3443 topPanel.av.setExplodedGeometry(
3444 new Rectangle(sf.getLocation(), topFrame.getSize()));
3445 bottomPanel.av.setExplodedGeometry(
3446 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3447 myTopFrame.addAlignmentPanel(topPanel, false);
3448 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3454 topFrame.getAlignPanels().clear();
3455 bottomFrame.getAlignPanels().clear();
3462 * The dust settles...give focus to the tab we did this from.
3464 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3467 public static groovy.ui.Console getGroovyConsole()
3469 return groovyConsole;
3473 * handles the payload of a drag and drop event.
3475 * TODO refactor to desktop utilities class
3478 * - Data source strings extracted from the drop event
3480 * - protocol for each data source extracted from the drop event
3484 * - the payload from the drop event
3487 public static void transferFromDropTarget(List<String> files,
3488 List<DataSourceType> protocols, DropTargetDropEvent evt,
3489 Transferable t) throws Exception
3492 DataFlavor uriListFlavor = new DataFlavor(
3493 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3496 urlFlavour = new DataFlavor(
3497 "application/x-java-url; class=java.net.URL");
3498 } catch (ClassNotFoundException cfe)
3500 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3503 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3508 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3509 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3510 // means url may be null.
3513 protocols.add(DataSourceType.URL);
3514 files.add(url.toString());
3515 Cache.log.debug("Drop handled as URL dataflavor "
3516 + files.get(files.size() - 1));
3521 if (Platform.isAMac())
3524 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3528 } catch (Throwable ex)
3530 Cache.log.debug("URL drop handler failed.", ex);
3533 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3535 // Works on Windows and MacOSX
3536 Cache.log.debug("Drop handled as javaFileListFlavor");
3537 for (Object file : (List) t
3538 .getTransferData(DataFlavor.javaFileListFlavor))
3540 files.add(((File) file).toString());
3541 protocols.add(DataSourceType.FILE);
3546 // Unix like behaviour
3547 boolean added = false;
3549 if (t.isDataFlavorSupported(uriListFlavor))
3551 Cache.log.debug("Drop handled as uriListFlavor");
3552 // This is used by Unix drag system
3553 data = (String) t.getTransferData(uriListFlavor);
3557 // fallback to text: workaround - on OSX where there's a JVM bug
3558 Cache.log.debug("standard URIListFlavor failed. Trying text");
3559 // try text fallback
3560 DataFlavor textDf = new DataFlavor(
3561 "text/plain;class=java.lang.String");
3562 if (t.isDataFlavorSupported(textDf))
3564 data = (String) t.getTransferData(textDf);
3567 Cache.log.debug("Plain text drop content returned "
3568 + (data == null ? "Null - failed" : data));
3573 while (protocols.size() < files.size())
3575 Cache.log.debug("Adding missing FILE protocol for "
3576 + files.get(protocols.size()));
3577 protocols.add(DataSourceType.FILE);
3579 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3580 data, "\r\n"); st.hasMoreTokens();)
3583 String s = st.nextToken();
3584 if (s.startsWith("#"))
3586 // the line is a comment (as per the RFC 2483)
3589 java.net.URI uri = new java.net.URI(s);
3590 if (uri.getScheme().toLowerCase().startsWith("http"))
3592 protocols.add(DataSourceType.URL);
3593 files.add(uri.toString());
3597 // otherwise preserve old behaviour: catch all for file objects
3598 java.io.File file = new java.io.File(uri);
3599 protocols.add(DataSourceType.FILE);
3600 files.add(file.toString());
3605 if (Cache.log.isDebugEnabled())
3607 if (data == null || !added)
3610 if (t.getTransferDataFlavors() != null
3611 && t.getTransferDataFlavors().length > 0)
3614 "Couldn't resolve drop data. Here are the supported flavors:");
3615 for (DataFlavor fl : t.getTransferDataFlavors())
3618 "Supported transfer dataflavor: " + fl.toString());
3619 Object df = t.getTransferData(fl);
3622 Cache.log.debug("Retrieves: " + df);
3626 Cache.log.debug("Retrieved nothing");
3632 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3638 if (Platform.isWindows())
3641 Cache.log.debug("Scanning dropped content for Windows Link Files");
3643 // resolve any .lnk files in the file drop
3644 for (int f = 0; f < files.size(); f++)
3646 String source = files.get(f).toLowerCase();
3647 if (protocols.get(f).equals(DataSourceType.FILE)
3648 && (source.endsWith(".lnk") || source.endsWith(".url")
3649 || source.endsWith(".site")))
3653 File lf = new File(files.get(f));
3654 // process link file to get a URL
3655 Cache.log.debug("Found potential link file: " + lf);
3656 WindowsShortcut wscfile = new WindowsShortcut(lf);
3657 String fullname = wscfile.getRealFilename();
3658 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3659 files.set(f, fullname);
3660 Cache.log.debug("Parsed real filename " + fullname
3661 + " to extract protocol: " + protocols.get(f));
3662 } catch (Exception ex)
3665 "Couldn't parse " + files.get(f) + " as a link file.",
3674 * Sets the Preferences property for experimental features to True or False
3675 * depending on the state of the controlling menu item
3678 protected void showExperimental_actionPerformed(boolean selected)
3680 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3684 * Answers a (possibly empty) list of any structure viewer frames (currently
3685 * for either Jmol or Chimera) which are currently open. This may optionally
3686 * be restricted to viewers of a specified class, or viewers linked to a
3687 * specified alignment panel.
3690 * if not null, only return viewers linked to this panel
3691 * @param structureViewerClass
3692 * if not null, only return viewers of this class
3695 public List<StructureViewerBase> getStructureViewers(
3696 AlignmentPanel apanel,
3697 Class<? extends StructureViewerBase> structureViewerClass)
3699 List<StructureViewerBase> result = new ArrayList<>();
3700 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3702 for (JInternalFrame frame : frames)
3704 if (frame instanceof StructureViewerBase)
3706 if (structureViewerClass == null
3707 || structureViewerClass.isInstance(frame))
3710 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3712 result.add((StructureViewerBase) frame);