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 (desktopClass.getDeclaredMethod("setAboutHandler",
386 { AboutHandler.class }) != null)
389 hdesktop.setAboutHandler(new AboutHandler()
392 public void handleAbout(AboutEvent e)
394 aboutMenuItem_actionPerformed(null);
400 if (desktopClass.getDeclaredMethod("setPreferencesHandler",
402 { PreferencesHandler.class }) != null)
405 hdesktop.setPreferencesHandler(new PreferencesHandler()
408 public void handlePreferences(PreferencesEvent e)
410 preferences_actionPerformed(null);
416 if (desktopClass.getDeclaredMethod("setQuitHandler",
418 { QuitHandler.class }) != null)
421 hdesktop.setQuitHandler(new QuitHandler()
424 public void handleQuitRequestWith(QuitEvent e, QuitResponse r)
426 boolean confirmQuit = jalview.bin.Cache
427 .getDefault(CONFIRM_KEYBOARD_QUIT, true);
431 n = JOptionPane.showConfirmDialog(null,
432 MessageManager.getString("label.quit_jalview"),
433 MessageManager.getString("action.quit"),
434 JOptionPane.OK_CANCEL_OPTION,
435 JOptionPane.PLAIN_MESSAGE, null);
439 n = JOptionPane.OK_OPTION;
441 if (n == JOptionPane.OK_OPTION)
443 System.out.println("Shortcut Quit confirmed by user");
445 r.performQuit(); // probably won't reach this line, but just in
451 System.out.println("Shortcut Quit cancelled by user");
455 hdesktop.setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
459 } catch (NoSuchMethodException e)
462 "NoSuchMethodException when looking for About, Preferences, Quit Handlers");
466 setAPQHandlers = true;
469 addWindowListener(new WindowAdapter()
473 public void windowClosing(WindowEvent ev)
479 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
482 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
484 desktop = new MyDesktopPane(selmemusage);
485 showMemusage.setSelected(selmemusage);
486 desktop.setBackground(Color.white);
488 getContentPane().setLayout(new BorderLayout());
489 // alternate config - have scrollbars - see notes in JAL-153
490 // JScrollPane sp = new JScrollPane();
491 // sp.getViewport().setView(desktop);
492 // getContentPane().add(sp, BorderLayout.CENTER);
493 getContentPane().add(desktop, BorderLayout.CENTER);
494 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
496 // This line prevents Windows Look&Feel resizing all new windows to maximum
497 // if previous window was maximised
498 desktop.setDesktopManager(new MyDesktopManager(
499 (Platform.isWindows() ? new DefaultDesktopManager()
501 ? new AquaInternalFrameManager(
502 desktop.getDesktopManager())
503 : desktop.getDesktopManager())));
505 Rectangle dims = getLastKnownDimensions("");
512 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
513 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
516 jconsole = new Console(this, showjconsole);
517 // add essential build information
519 "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
520 + "\n" + "Jalview Installation: "
521 + jalview.bin.Cache.getDefault("INSTALLATION",
523 + "\n" + "Build Date: "
524 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
525 + "\n" + "Java version: "
526 + System.getProperty("java.version") + "\n"
527 + System.getProperty("os.arch") + " "
528 + System.getProperty("os.name") + " "
529 + System.getProperty("os.version"));
531 showConsole(showjconsole);
533 showNews.setVisible(false);
535 experimentalFeatures.setSelected(showExperimental());
537 getIdentifiersOrgData();
541 this.addWindowListener(new WindowAdapter()
544 public void windowClosing(WindowEvent evt)
551 this.addMouseListener(ma = new MouseAdapter()
554 public void mousePressed(MouseEvent evt)
556 if (evt.isPopupTrigger()) // Mac
558 showPasteMenu(evt.getX(), evt.getY());
563 public void mouseReleased(MouseEvent evt)
565 if (evt.isPopupTrigger()) // Windows
567 showPasteMenu(evt.getX(), evt.getY());
571 desktop.addMouseListener(ma);
573 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
574 // Spawn a thread that shows the splashscreen
575 SwingUtilities.invokeLater(new Runnable()
584 // Thread off a new instance of the file chooser - this reduces the time it
585 // takes to open it later on.
586 new Thread(new Runnable()
591 Cache.log.debug("Filechooser init thread started.");
592 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
593 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
595 Cache.log.debug("Filechooser init thread finished.");
598 // Add the service change listener
599 changeSupport.addJalviewPropertyChangeListener("services",
600 new PropertyChangeListener()
604 public void propertyChange(PropertyChangeEvent evt)
606 Cache.log.debug("Firing service changed event for "
607 + evt.getNewValue());
608 JalviewServicesChanged(evt);
615 * Answers true if user preferences to enable experimental features is True
620 public boolean showExperimental()
622 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
623 Boolean.FALSE.toString());
624 return Boolean.valueOf(experimental).booleanValue();
627 public void doConfigureStructurePrefs()
629 // configure services
630 StructureSelectionManager ssm = StructureSelectionManager
631 .getStructureSelectionManager(this);
632 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
634 ssm.setAddTempFacAnnot(jalview.bin.Cache
635 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
636 ssm.setProcessSecondaryStructure(jalview.bin.Cache
637 .getDefault(Preferences.STRUCT_FROM_PDB, true));
638 ssm.setSecStructServices(
639 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
643 ssm.setAddTempFacAnnot(false);
644 ssm.setProcessSecondaryStructure(false);
645 ssm.setSecStructServices(false);
649 public void checkForNews()
651 final Desktop me = this;
652 // Thread off the news reader, in case there are connection problems.
653 new Thread(new Runnable()
658 Cache.log.debug("Starting news thread.");
660 jvnews = new BlogReader(me);
661 showNews.setVisible(true);
662 Cache.log.debug("Completed news thread.");
667 public void getIdentifiersOrgData()
669 // Thread off the identifiers fetcher
670 new Thread(new Runnable()
675 Cache.log.debug("Downloading data from identifiers.org");
676 UrlDownloadClient client = new UrlDownloadClient();
679 client.download(IdOrgSettings.getUrl(),
680 IdOrgSettings.getDownloadLocation());
681 } catch (IOException e)
683 Cache.log.debug("Exception downloading identifiers.org data"
692 protected void showNews_actionPerformed(ActionEvent e)
694 showNews(showNews.isSelected());
697 void showNews(boolean visible)
700 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
701 showNews.setSelected(visible);
702 if (visible && !jvnews.isVisible())
704 new Thread(new Runnable()
709 long now = System.currentTimeMillis();
710 Desktop.instance.setProgressBar(
711 MessageManager.getString("status.refreshing_news"),
713 jvnews.refreshNews();
714 Desktop.instance.setProgressBar(null, now);
723 * recover the last known dimensions for a jalview window
726 * - empty string is desktop, all other windows have unique prefix
727 * @return null or last known dimensions scaled to current geometry (if last
728 * window geom was known)
730 Rectangle getLastKnownDimensions(String windowName)
732 // TODO: lock aspect ratio for scaling desktop Bug #0058199
733 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
734 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
735 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
736 String width = jalview.bin.Cache
737 .getProperty(windowName + "SCREEN_WIDTH");
738 String height = jalview.bin.Cache
739 .getProperty(windowName + "SCREEN_HEIGHT");
740 if ((x != null) && (y != null) && (width != null) && (height != null))
742 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
743 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
744 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
746 // attempt #1 - try to cope with change in screen geometry - this
747 // version doesn't preserve original jv aspect ratio.
748 // take ratio of current screen size vs original screen size.
749 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
750 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
751 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
752 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
753 // rescale the bounds depending upon the current screen geometry.
754 ix = (int) (ix * sw);
755 iw = (int) (iw * sw);
756 iy = (int) (iy * sh);
757 ih = (int) (ih * sh);
758 while (ix >= screenSize.width)
760 jalview.bin.Cache.log.debug(
761 "Window geometry location recall error: shifting horizontal to within screenbounds.");
762 ix -= screenSize.width;
764 while (iy >= screenSize.height)
766 jalview.bin.Cache.log.debug(
767 "Window geometry location recall error: shifting vertical to within screenbounds.");
768 iy -= screenSize.height;
770 jalview.bin.Cache.log.debug(
771 "Got last known dimensions for " + windowName + ": x:" + ix
772 + " y:" + iy + " width:" + iw + " height:" + ih);
774 // return dimensions for new instance
775 return new Rectangle(ix, iy, iw, ih);
780 private void doVamsasClientCheck()
782 if (jalview.bin.Cache.vamsasJarsPresent())
784 setupVamsasDisconnectedGui();
785 VamsasMenu.setVisible(true);
786 final Desktop us = this;
787 VamsasMenu.addMenuListener(new MenuListener()
789 // this listener remembers when the menu was first selected, and
790 // doesn't rebuild the session list until it has been cleared and
792 boolean refresh = true;
795 public void menuCanceled(MenuEvent e)
801 public void menuDeselected(MenuEvent e)
807 public void menuSelected(MenuEvent e)
811 us.buildVamsasStMenu();
816 vamsasStart.setVisible(true);
820 void showPasteMenu(int x, int y)
822 JPopupMenu popup = new JPopupMenu();
823 JMenuItem item = new JMenuItem(
824 MessageManager.getString("label.paste_new_window"));
825 item.addActionListener(new ActionListener()
828 public void actionPerformed(ActionEvent evt)
835 popup.show(this, x, y);
842 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
843 Transferable contents = c.getContents(this);
845 if (contents != null)
847 String file = (String) contents
848 .getTransferData(DataFlavor.stringFlavor);
850 FileFormatI format = new IdentifyFile().identify(file,
851 DataSourceType.PASTE);
853 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
856 } catch (Exception ex)
859 "Unable to paste alignment from system clipboard:\n" + ex);
864 * Adds and opens the given frame to the desktop
875 public static synchronized void addInternalFrame(
876 final JInternalFrame frame, String title, int w, int h)
878 addInternalFrame(frame, title, true, w, h, true, false);
882 * Add an internal frame to the Jalview desktop
889 * When true, display frame immediately, otherwise, caller must call
890 * setVisible themselves.
896 public static synchronized void addInternalFrame(
897 final JInternalFrame frame, String title, boolean makeVisible,
900 addInternalFrame(frame, title, makeVisible, w, h, true, false);
904 * Add an internal frame to the Jalview desktop and make it visible
917 public static synchronized void addInternalFrame(
918 final JInternalFrame frame, String title, int w, int h,
921 addInternalFrame(frame, title, true, w, h, resizable, false);
925 * Add an internal frame to the Jalview desktop
932 * When true, display frame immediately, otherwise, caller must call
933 * setVisible themselves.
940 * @param ignoreMinSize
941 * Do not set the default minimum size for frame
943 public static synchronized void addInternalFrame(
944 final JInternalFrame frame, String title, boolean makeVisible,
945 int w, int h, boolean resizable, boolean ignoreMinSize)
948 // TODO: allow callers to determine X and Y position of frame (eg. via
950 // TODO: consider fixing method to update entries in the window submenu with
951 // the current window title
953 frame.setTitle(title);
954 if (frame.getWidth() < 1 || frame.getHeight() < 1)
958 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
959 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
960 // IF JALVIEW IS RUNNING HEADLESS
961 // ///////////////////////////////////////////////
962 if (instance == null || (System.getProperty("java.awt.headless") != null
963 && System.getProperty("java.awt.headless").equals("true")))
972 frame.setMinimumSize(
973 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
975 // Set default dimension for Alignment Frame window.
976 // The Alignment Frame window could be added from a number of places,
978 // I did this here in order not to miss out on any Alignment frame.
979 if (frame instanceof AlignFrame)
981 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
982 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
986 frame.setVisible(makeVisible);
987 frame.setClosable(true);
988 frame.setResizable(resizable);
989 frame.setMaximizable(resizable);
990 frame.setIconifiable(resizable);
991 frame.setOpaque(false);
993 if (frame.getX() < 1 && frame.getY() < 1)
995 frame.setLocation(xOffset * openFrameCount,
996 yOffset * ((openFrameCount - 1) % 10) + yOffset);
1000 * add an entry for the new frame in the Window menu
1001 * (and remove it when the frame is closed)
1003 final JMenuItem menuItem = new JMenuItem(title);
1004 frame.addInternalFrameListener(new InternalFrameAdapter()
1007 public void internalFrameActivated(InternalFrameEvent evt)
1009 JInternalFrame itf = desktop.getSelectedFrame();
1012 if (itf instanceof AlignFrame)
1014 Jalview.setCurrentAlignFrame((AlignFrame) itf);
1021 public void internalFrameClosed(InternalFrameEvent evt)
1023 PaintRefresher.RemoveComponent(frame);
1026 * defensive check to prevent frames being
1027 * added half off the window
1029 if (openFrameCount > 0)
1035 * ensure no reference to alignFrame retained by menu item listener
1037 if (menuItem.getActionListeners().length > 0)
1039 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
1041 windowMenu.remove(menuItem);
1045 menuItem.addActionListener(new ActionListener()
1048 public void actionPerformed(ActionEvent e)
1052 frame.setSelected(true);
1053 frame.setIcon(false);
1054 } catch (java.beans.PropertyVetoException ex)
1061 setKeyBindings(frame);
1065 windowMenu.add(menuItem);
1070 frame.setSelected(true);
1071 frame.requestFocus();
1072 } catch (java.beans.PropertyVetoException ve)
1074 } catch (java.lang.ClassCastException cex)
1077 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
1083 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
1088 private static void setKeyBindings(JInternalFrame frame)
1090 @SuppressWarnings("serial")
1091 final Action closeAction = new AbstractAction()
1094 public void actionPerformed(ActionEvent e)
1101 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1103 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1104 InputEvent.CTRL_DOWN_MASK);
1105 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1106 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1108 InputMap inputMap = frame
1109 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1110 String ctrlW = ctrlWKey.toString();
1111 inputMap.put(ctrlWKey, ctrlW);
1112 inputMap.put(cmdWKey, ctrlW);
1114 ActionMap actionMap = frame.getActionMap();
1115 actionMap.put(ctrlW, closeAction);
1119 public void lostOwnership(Clipboard clipboard, Transferable contents)
1123 Desktop.jalviewClipboard = null;
1126 internalCopy = false;
1130 public void dragEnter(DropTargetDragEvent evt)
1135 public void dragExit(DropTargetEvent evt)
1140 public void dragOver(DropTargetDragEvent evt)
1145 public void dropActionChanged(DropTargetDragEvent evt)
1156 public void drop(DropTargetDropEvent evt)
1158 boolean success = true;
1159 // JAL-1552 - acceptDrop required before getTransferable call for
1160 // Java's Transferable for native dnd
1161 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1162 Transferable t = evt.getTransferable();
1163 List<String> files = new ArrayList<>();
1164 List<DataSourceType> protocols = new ArrayList<>();
1168 Desktop.transferFromDropTarget(files, protocols, evt, t);
1169 } catch (Exception e)
1171 e.printStackTrace();
1179 for (int i = 0; i < files.size(); i++)
1181 String file = files.get(i).toString();
1182 DataSourceType protocol = (protocols == null)
1183 ? DataSourceType.FILE
1185 FileFormatI format = null;
1187 if (file.endsWith(".jar"))
1189 format = FileFormat.Jalview;
1194 format = new IdentifyFile().identify(file, protocol);
1197 new FileLoader().LoadFile(file, protocol, format);
1200 } catch (Exception ex)
1205 evt.dropComplete(success); // need this to ensure input focus is properly
1206 // transfered to any new windows created
1216 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1218 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1219 JalviewFileChooser chooser = JalviewFileChooser
1220 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1222 chooser.setFileView(new JalviewFileView());
1223 chooser.setDialogTitle(
1224 MessageManager.getString("label.open_local_file"));
1225 chooser.setToolTipText(MessageManager.getString("action.open"));
1227 int value = chooser.showOpenDialog(this);
1229 if (value == JalviewFileChooser.APPROVE_OPTION)
1231 String choice = chooser.getSelectedFile().getPath();
1232 Cache.setProperty("LAST_DIRECTORY",
1233 chooser.getSelectedFile().getParent());
1235 FileFormatI format = chooser.getSelectedFormat();
1238 * Call IdentifyFile to verify the file contains what its extension implies.
1239 * Skip this step for dynamically added file formats, because
1240 * IdentifyFile does not know how to recognise them.
1242 if (FileFormats.getInstance().isIdentifiable(format))
1246 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1247 } catch (FileFormatException e)
1249 // format = null; //??
1253 if (viewport != null)
1255 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1260 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1272 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1274 // This construct allows us to have a wider textfield
1276 JLabel label = new JLabel(
1277 MessageManager.getString("label.input_file_url"));
1278 final JComboBox history = new JComboBox();
1280 JPanel panel = new JPanel(new GridLayout(2, 1));
1283 history.setPreferredSize(new Dimension(400, 20));
1284 history.setEditable(true);
1285 history.addItem("http://www.");
1287 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1291 if (historyItems != null)
1293 st = new StringTokenizer(historyItems, "\t");
1295 while (st.hasMoreTokens())
1297 history.addItem(st.nextElement());
1301 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1302 MessageManager.getString("label.input_alignment_from_url"),
1303 JvOptionPane.OK_CANCEL_OPTION);
1305 if (reply != JvOptionPane.OK_OPTION)
1310 String url = history.getSelectedItem().toString();
1312 if (url.toLowerCase().endsWith(".jar"))
1314 if (viewport != null)
1316 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1317 FileFormat.Jalview);
1321 new FileLoader().LoadFile(url, DataSourceType.URL,
1322 FileFormat.Jalview);
1327 FileFormatI format = null;
1330 format = new IdentifyFile().identify(url, DataSourceType.URL);
1331 } catch (FileFormatException e)
1333 // TODO revise error handling, distinguish between
1334 // URL not found and response not valid
1339 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1340 MessageManager.formatMessage("label.couldnt_locate",
1343 MessageManager.getString("label.url_not_found"),
1344 JvOptionPane.WARNING_MESSAGE);
1349 if (viewport != null)
1351 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1356 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1362 * Opens the CutAndPaste window for the user to paste an alignment in to
1365 * - if not null, the pasted alignment is added to the current
1366 * alignment; if null, to a new alignment window
1369 public void inputTextboxMenuItem_actionPerformed(
1370 AlignmentViewPanel viewPanel)
1372 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1373 cap.setForInput(viewPanel);
1374 Desktop.addInternalFrame(cap,
1375 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1385 System.out.println("********** Desktop.quit()");
1386 System.out.println(savingFiles.toString());
1387 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1388 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1390 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1391 screen.height + "");
1392 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1393 getWidth(), getHeight()));
1395 if (jconsole != null)
1397 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1398 jconsole.stopConsole();
1402 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1405 if (dialogExecutor != null)
1407 dialogExecutor.shutdownNow();
1409 closeAll_actionPerformed(null);
1411 if (groovyConsole != null)
1413 // suppress a possible repeat prompt to save script
1414 groovyConsole.setDirty(false);
1415 groovyConsole.exit();
1420 private void storeLastKnownDimensions(String string, Rectangle jc)
1422 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1423 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1424 + " height:" + jc.height);
1426 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1427 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1428 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1429 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1439 public void aboutMenuItem_actionPerformed(ActionEvent e)
1441 // StringBuffer message = getAboutMessage(false);
1442 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1444 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1445 new Thread(new Runnable()
1450 new SplashScreen(true);
1455 public StringBuffer getAboutMessage(boolean shortv)
1457 StringBuffer message = new StringBuffer();
1458 message.append("<html>");
1461 message.append("<h1><strong>Version: "
1462 + jalview.bin.Cache.getProperty("VERSION")
1463 + "</strong></h1>");
1464 message.append("<strong>Last Updated: <em>"
1465 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1466 + "</em></strong>");
1472 message.append("<strong>Version "
1473 + jalview.bin.Cache.getProperty("VERSION")
1474 + "; last updated: "
1475 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1478 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1479 .equals("Checking"))
1481 message.append("<br>...Checking latest version...</br>");
1483 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1484 .equals(jalview.bin.Cache.getProperty("VERSION")))
1486 boolean red = false;
1487 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1488 .indexOf("automated build") == -1)
1491 // Displayed when code version and jnlp version do not match and code
1492 // version is not a development build
1493 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1496 message.append("<br>!! Version "
1497 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1499 + " is available for download from "
1500 + jalview.bin.Cache.getDefault("www.jalview.org",
1501 "http://www.jalview.org")
1505 message.append("</div>");
1508 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1510 "The Jalview Authors (See AUTHORS file for current list)")
1511 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1512 + "<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"
1513 + "<br><br>If you use Jalview, please cite:"
1514 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1515 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1516 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1528 public void documentationMenuItem_actionPerformed(ActionEvent e)
1532 Help.showHelpWindow();
1533 } catch (Exception ex)
1539 public void closeAll_actionPerformed(ActionEvent e)
1541 // TODO show a progress bar while closing?
1542 JInternalFrame[] frames = desktop.getAllFrames();
1543 for (int i = 0; i < frames.length; i++)
1547 frames[i].setClosed(true);
1548 } catch (java.beans.PropertyVetoException ex)
1552 Jalview.setCurrentAlignFrame(null);
1553 System.out.println("ALL CLOSED");
1554 if (v_client != null)
1556 // TODO clear binding to vamsas document objects on close_all
1560 * reset state of singleton objects as appropriate (clear down session state
1561 * when all windows are closed)
1563 StructureSelectionManager ssm = StructureSelectionManager
1564 .getStructureSelectionManager(this);
1572 public void raiseRelated_actionPerformed(ActionEvent e)
1574 reorderAssociatedWindows(false, false);
1578 public void minimizeAssociated_actionPerformed(ActionEvent e)
1580 reorderAssociatedWindows(true, false);
1583 void closeAssociatedWindows()
1585 reorderAssociatedWindows(false, true);
1591 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1595 protected void garbageCollect_actionPerformed(ActionEvent e)
1597 // We simply collect the garbage
1598 jalview.bin.Cache.log.debug("Collecting garbage...");
1600 jalview.bin.Cache.log.debug("Finished garbage collection.");
1607 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1611 protected void showMemusage_actionPerformed(ActionEvent e)
1613 desktop.showMemoryUsage(showMemusage.isSelected());
1620 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1624 protected void showConsole_actionPerformed(ActionEvent e)
1626 showConsole(showConsole.isSelected());
1629 Console jconsole = null;
1632 * control whether the java console is visible or not
1636 void showConsole(boolean selected)
1638 showConsole.setSelected(selected);
1639 // TODO: decide if we should update properties file
1640 Cache.setProperty("SHOW_JAVA_CONSOLE",
1641 Boolean.valueOf(selected).toString());
1642 jconsole.setVisible(selected);
1645 void reorderAssociatedWindows(boolean minimize, boolean close)
1647 JInternalFrame[] frames = desktop.getAllFrames();
1648 if (frames == null || frames.length < 1)
1653 AlignmentViewport source = null, target = null;
1654 if (frames[0] instanceof AlignFrame)
1656 source = ((AlignFrame) frames[0]).getCurrentView();
1658 else if (frames[0] instanceof TreePanel)
1660 source = ((TreePanel) frames[0]).getViewPort();
1662 else if (frames[0] instanceof PCAPanel)
1664 source = ((PCAPanel) frames[0]).av;
1666 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1668 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1673 for (int i = 0; i < frames.length; i++)
1676 if (frames[i] == null)
1680 if (frames[i] instanceof AlignFrame)
1682 target = ((AlignFrame) frames[i]).getCurrentView();
1684 else if (frames[i] instanceof TreePanel)
1686 target = ((TreePanel) frames[i]).getViewPort();
1688 else if (frames[i] instanceof PCAPanel)
1690 target = ((PCAPanel) frames[i]).av;
1692 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1694 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1697 if (source == target)
1703 frames[i].setClosed(true);
1707 frames[i].setIcon(minimize);
1710 frames[i].toFront();
1714 } catch (java.beans.PropertyVetoException ex)
1729 protected void preferences_actionPerformed(ActionEvent e)
1735 * Shows a file chooser dialog and writes out the current session as a Jalview
1739 public void saveState_actionPerformed()
1741 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1744 chooser.setFileView(new JalviewFileView());
1745 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1747 int value = chooser.showSaveDialog(this);
1749 if (value == JalviewFileChooser.APPROVE_OPTION)
1751 final Desktop me = this;
1752 final java.io.File choice = chooser.getSelectedFile();
1753 setProjectFile(choice);
1755 new Thread(new Runnable()
1760 // TODO: refactor to Jalview desktop session controller action.
1761 setProgressBar(MessageManager.formatMessage(
1762 "label.saving_jalview_project", new Object[]
1763 { choice.getName() }), choice.hashCode());
1764 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1765 choice.getParent());
1766 // TODO catch and handle errors for savestate
1767 // TODO prevent user from messing with the Desktop whilst we're saving
1770 new Jalview2XML().saveState(choice);
1771 } catch (OutOfMemoryError oom)
1774 "Whilst saving current state to " + choice.getName(),
1776 } catch (Exception ex)
1779 "Problems whilst trying to save to " + choice.getName(),
1781 JvOptionPane.showMessageDialog(me,
1782 MessageManager.formatMessage(
1783 "label.error_whilst_saving_current_state_to",
1785 { choice.getName() }),
1786 MessageManager.getString("label.couldnt_save_project"),
1787 JvOptionPane.WARNING_MESSAGE);
1789 setProgressBar(null, choice.hashCode());
1795 private void setProjectFile(File choice)
1797 this.projectFile = choice;
1800 public File getProjectFile()
1802 return this.projectFile;
1806 * Shows a file chooser dialog and tries to read in the selected file as a
1810 public void loadState_actionPerformed()
1812 final String[] suffix = new String[] { "jvp", "jar" };
1813 final String[] desc = new String[] { "Jalview Project",
1814 "Jalview Project (old)" };
1815 JalviewFileChooser chooser = new JalviewFileChooser(
1816 Cache.getProperty("LAST_DIRECTORY"), suffix,
1819 chooser.setFileView(new JalviewFileView());
1820 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1822 int value = chooser.showOpenDialog(this);
1824 if (value == JalviewFileChooser.APPROVE_OPTION)
1826 final File selectedFile = chooser.getSelectedFile();
1827 setProjectFile(selectedFile);
1828 final String choice = selectedFile.getAbsolutePath();
1829 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1830 new Thread(new Runnable()
1835 setProgressBar(MessageManager.formatMessage(
1836 "label.loading_jalview_project", new Object[]
1837 { choice }), choice.hashCode());
1840 new Jalview2XML().loadJalviewAlign(choice);
1841 } catch (OutOfMemoryError oom)
1843 new OOMWarning("Whilst loading project from " + choice, oom);
1844 } catch (Exception ex)
1847 "Problems whilst loading project from " + choice, ex);
1848 JvOptionPane.showMessageDialog(Desktop.desktop,
1849 MessageManager.formatMessage(
1850 "label.error_whilst_loading_project_from",
1853 MessageManager.getString("label.couldnt_load_project"),
1854 JvOptionPane.WARNING_MESSAGE);
1856 setProgressBar(null, choice.hashCode());
1863 public void inputSequence_actionPerformed(ActionEvent e)
1865 new SequenceFetcher(this);
1868 JPanel progressPanel;
1870 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1872 public void startLoading(final String fileName)
1874 if (fileLoadingCount == 0)
1876 fileLoadingPanels.add(addProgressPanel(MessageManager
1877 .formatMessage("label.loading_file", new Object[]
1883 private JPanel addProgressPanel(String string)
1885 if (progressPanel == null)
1887 progressPanel = new JPanel(new GridLayout(1, 1));
1888 totalProgressCount = 0;
1889 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1891 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1892 JProgressBar progressBar = new JProgressBar();
1893 progressBar.setIndeterminate(true);
1895 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1897 thisprogress.add(progressBar, BorderLayout.CENTER);
1898 progressPanel.add(thisprogress);
1899 ((GridLayout) progressPanel.getLayout()).setRows(
1900 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1901 ++totalProgressCount;
1902 instance.validate();
1903 return thisprogress;
1906 int totalProgressCount = 0;
1908 private void removeProgressPanel(JPanel progbar)
1910 if (progressPanel != null)
1912 synchronized (progressPanel)
1914 progressPanel.remove(progbar);
1915 GridLayout gl = (GridLayout) progressPanel.getLayout();
1916 gl.setRows(gl.getRows() - 1);
1917 if (--totalProgressCount < 1)
1919 this.getContentPane().remove(progressPanel);
1920 progressPanel = null;
1927 public void stopLoading()
1930 if (fileLoadingCount < 1)
1932 while (fileLoadingPanels.size() > 0)
1934 removeProgressPanel(fileLoadingPanels.remove(0));
1936 fileLoadingPanels.clear();
1937 fileLoadingCount = 0;
1942 public static int getViewCount(String alignmentId)
1944 AlignmentViewport[] aps = getViewports(alignmentId);
1945 return (aps == null) ? 0 : aps.length;
1950 * @param alignmentId
1951 * - if null, all sets are returned
1952 * @return all AlignmentPanels concerning the alignmentId sequence set
1954 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1956 if (Desktop.desktop == null)
1958 // no frames created and in headless mode
1959 // TODO: verify that frames are recoverable when in headless mode
1962 List<AlignmentPanel> aps = new ArrayList<>();
1963 AlignFrame[] frames = getAlignFrames();
1968 for (AlignFrame af : frames)
1970 for (AlignmentPanel ap : af.alignPanels)
1972 if (alignmentId == null
1973 || alignmentId.equals(ap.av.getSequenceSetId()))
1979 if (aps.size() == 0)
1983 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1988 * get all the viewports on an alignment.
1990 * @param sequenceSetId
1991 * unique alignment id (may be null - all viewports returned in that
1993 * @return all viewports on the alignment bound to sequenceSetId
1995 public static AlignmentViewport[] getViewports(String sequenceSetId)
1997 List<AlignmentViewport> viewp = new ArrayList<>();
1998 if (desktop != null)
2000 AlignFrame[] frames = Desktop.getAlignFrames();
2002 for (AlignFrame afr : frames)
2004 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
2005 .equals(sequenceSetId))
2007 if (afr.alignPanels != null)
2009 for (AlignmentPanel ap : afr.alignPanels)
2011 if (sequenceSetId == null
2012 || sequenceSetId.equals(ap.av.getSequenceSetId()))
2020 viewp.add(afr.getViewport());
2024 if (viewp.size() > 0)
2026 return viewp.toArray(new AlignmentViewport[viewp.size()]);
2033 * Explode the views in the given frame into separate AlignFrame
2037 public static void explodeViews(AlignFrame af)
2039 int size = af.alignPanels.size();
2045 for (int i = 0; i < size; i++)
2047 AlignmentPanel ap = af.alignPanels.get(i);
2048 AlignFrame newaf = new AlignFrame(ap);
2051 * Restore the view's last exploded frame geometry if known. Multiple
2052 * views from one exploded frame share and restore the same (frame)
2053 * position and size.
2055 Rectangle geometry = ap.av.getExplodedGeometry();
2056 if (geometry != null)
2058 newaf.setBounds(geometry);
2061 ap.av.setGatherViewsHere(false);
2063 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2064 AlignFrame.DEFAULT_HEIGHT);
2067 af.alignPanels.clear();
2068 af.closeMenuItem_actionPerformed(true);
2073 * Gather expanded views (separate AlignFrame's) with the same sequence set
2074 * identifier back in to this frame as additional views, and close the
2075 * expanded views. Note the expanded frames may themselves have multiple
2076 * views. We take the lot.
2080 public void gatherViews(AlignFrame source)
2082 source.viewport.setGatherViewsHere(true);
2083 source.viewport.setExplodedGeometry(source.getBounds());
2084 JInternalFrame[] frames = desktop.getAllFrames();
2085 String viewId = source.viewport.getSequenceSetId();
2087 for (int t = 0; t < frames.length; t++)
2089 if (frames[t] instanceof AlignFrame && frames[t] != source)
2091 AlignFrame af = (AlignFrame) frames[t];
2092 boolean gatherThis = false;
2093 for (int a = 0; a < af.alignPanels.size(); a++)
2095 AlignmentPanel ap = af.alignPanels.get(a);
2096 if (viewId.equals(ap.av.getSequenceSetId()))
2099 ap.av.setGatherViewsHere(false);
2100 ap.av.setExplodedGeometry(af.getBounds());
2101 source.addAlignmentPanel(ap, false);
2107 af.alignPanels.clear();
2108 af.closeMenuItem_actionPerformed(true);
2115 jalview.gui.VamsasApplication v_client = null;
2118 public void vamsasImport_actionPerformed(ActionEvent e)
2120 if (v_client == null)
2122 // Load and try to start a session.
2123 JalviewFileChooser chooser = new JalviewFileChooser(
2124 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2126 chooser.setFileView(new JalviewFileView());
2127 chooser.setDialogTitle(
2128 MessageManager.getString("label.open_saved_vamsas_session"));
2129 chooser.setToolTipText(MessageManager.getString(
2130 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2132 int value = chooser.showOpenDialog(this);
2134 if (value == JalviewFileChooser.APPROVE_OPTION)
2136 String fle = chooser.getSelectedFile().toString();
2137 if (!vamsasImport(chooser.getSelectedFile()))
2139 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2140 MessageManager.formatMessage(
2141 "label.couldnt_import_as_vamsas_session",
2145 .getString("label.vamsas_document_import_failed"),
2146 JvOptionPane.ERROR_MESSAGE);
2152 jalview.bin.Cache.log.error(
2153 "Implementation error - load session from a running session is not supported.");
2158 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2161 * @return true if import was a success and a session was started.
2163 public boolean vamsasImport(URL url)
2165 // TODO: create progress bar
2166 if (v_client != null)
2169 jalview.bin.Cache.log.error(
2170 "Implementation error - load session from a running session is not supported.");
2176 // copy the URL content to a temporary local file
2177 // TODO: be a bit cleverer here with nio (?!)
2178 File file = File.createTempFile("vdocfromurl", ".vdj");
2179 FileOutputStream fos = new FileOutputStream(file);
2180 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2181 byte[] buffer = new byte[2048];
2183 while ((ln = bis.read(buffer)) > -1)
2185 fos.write(buffer, 0, ln);
2189 v_client = new jalview.gui.VamsasApplication(this, file,
2190 url.toExternalForm());
2191 } catch (Exception ex)
2193 jalview.bin.Cache.log.error(
2194 "Failed to create new vamsas session from contents of URL "
2199 setupVamsasConnectedGui();
2200 v_client.initial_update(); // TODO: thread ?
2201 return v_client.inSession();
2205 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2208 * @return true if import was a success and a session was started.
2210 public boolean vamsasImport(File file)
2212 if (v_client != null)
2215 jalview.bin.Cache.log.error(
2216 "Implementation error - load session from a running session is not supported.");
2220 setProgressBar(MessageManager.formatMessage(
2221 "status.importing_vamsas_session_from", new Object[]
2222 { file.getName() }), file.hashCode());
2225 v_client = new jalview.gui.VamsasApplication(this, file, null);
2226 } catch (Exception ex)
2228 setProgressBar(MessageManager.formatMessage(
2229 "status.importing_vamsas_session_from", new Object[]
2230 { file.getName() }), file.hashCode());
2231 jalview.bin.Cache.log.error(
2232 "New vamsas session from existing session file failed:", ex);
2235 setupVamsasConnectedGui();
2236 v_client.initial_update(); // TODO: thread ?
2237 setProgressBar(MessageManager.formatMessage(
2238 "status.importing_vamsas_session_from", new Object[]
2239 { file.getName() }), file.hashCode());
2240 return v_client.inSession();
2243 public boolean joinVamsasSession(String mysesid)
2245 if (v_client != null)
2247 throw new Error(MessageManager
2248 .getString("error.try_join_vamsas_session_another"));
2250 if (mysesid == null)
2253 MessageManager.getString("error.invalid_vamsas_session_id"));
2255 v_client = new VamsasApplication(this, mysesid);
2256 setupVamsasConnectedGui();
2257 v_client.initial_update();
2258 return (v_client.inSession());
2262 public void vamsasStart_actionPerformed(ActionEvent e)
2264 if (v_client == null)
2267 // we just start a default session for moment.
2269 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2270 * getProperty("LAST_DIRECTORY"));
2272 * chooser.setFileView(new JalviewFileView());
2273 * chooser.setDialogTitle("Load Vamsas file");
2274 * chooser.setToolTipText("Import");
2276 * int value = chooser.showOpenDialog(this);
2278 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2279 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2281 v_client = new VamsasApplication(this);
2282 setupVamsasConnectedGui();
2283 v_client.initial_update(); // TODO: thread ?
2287 // store current data in session.
2288 v_client.push_update(); // TODO: thread
2292 protected void setupVamsasConnectedGui()
2294 vamsasStart.setText(MessageManager.getString("label.session_update"));
2295 vamsasSave.setVisible(true);
2296 vamsasStop.setVisible(true);
2297 vamsasImport.setVisible(false); // Document import to existing session is
2298 // not possible for vamsas-client-1.0.
2301 protected void setupVamsasDisconnectedGui()
2303 vamsasSave.setVisible(false);
2304 vamsasStop.setVisible(false);
2305 vamsasImport.setVisible(true);
2307 .setText(MessageManager.getString("label.new_vamsas_session"));
2311 public void vamsasStop_actionPerformed(ActionEvent e)
2313 if (v_client != null)
2315 v_client.end_session();
2317 setupVamsasDisconnectedGui();
2321 protected void buildVamsasStMenu()
2323 if (v_client == null)
2325 String[] sess = null;
2328 sess = VamsasApplication.getSessionList();
2329 } catch (Exception e)
2331 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2337 jalview.bin.Cache.log.debug(
2338 "Got current sessions list: " + sess.length + " entries.");
2339 VamsasStMenu.removeAll();
2340 for (int i = 0; i < sess.length; i++)
2342 JMenuItem sessit = new JMenuItem();
2343 sessit.setText(sess[i]);
2344 sessit.setToolTipText(MessageManager
2345 .formatMessage("label.connect_to_session", new Object[]
2347 final Desktop dsktp = this;
2348 final String mysesid = sess[i];
2349 sessit.addActionListener(new ActionListener()
2353 public void actionPerformed(ActionEvent e)
2355 if (dsktp.v_client == null)
2357 Thread rthr = new Thread(new Runnable()
2363 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2364 dsktp.setupVamsasConnectedGui();
2365 dsktp.v_client.initial_update();
2373 VamsasStMenu.add(sessit);
2375 // don't show an empty menu.
2376 VamsasStMenu.setVisible(sess.length > 0);
2381 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2382 VamsasStMenu.removeAll();
2383 VamsasStMenu.setVisible(false);
2388 // Not interested in the content. Just hide ourselves.
2389 VamsasStMenu.setVisible(false);
2394 public void vamsasSave_actionPerformed(ActionEvent e)
2396 if (v_client != null)
2398 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2399 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2402 chooser.setFileView(new JalviewFileView());
2403 chooser.setDialogTitle(MessageManager
2404 .getString("label.save_vamsas_document_archive"));
2406 int value = chooser.showSaveDialog(this);
2408 if (value == JalviewFileChooser.APPROVE_OPTION)
2410 java.io.File choice = chooser.getSelectedFile();
2411 JPanel progpanel = addProgressPanel(MessageManager
2412 .formatMessage("label.saving_vamsas_doc", new Object[]
2413 { choice.getName() }));
2414 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2415 String warnmsg = null;
2416 String warnttl = null;
2419 v_client.vclient.storeDocument(choice);
2422 warnttl = "Serious Problem saving Vamsas Document";
2423 warnmsg = ex.toString();
2424 jalview.bin.Cache.log
2425 .error("Error Whilst saving document to " + choice, ex);
2427 } catch (Exception ex)
2429 warnttl = "Problem saving Vamsas Document.";
2430 warnmsg = ex.toString();
2431 jalview.bin.Cache.log.warn(
2432 "Exception Whilst saving document to " + choice, ex);
2435 removeProgressPanel(progpanel);
2436 if (warnmsg != null)
2438 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2440 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2446 JPanel vamUpdate = null;
2449 * hide vamsas user gui bits when a vamsas document event is being handled.
2452 * true to hide gui, false to reveal gui
2454 public void setVamsasUpdate(boolean b)
2456 Cache.log.debug("Setting gui for Vamsas update "
2457 + (b ? "in progress" : "finished"));
2459 if (vamUpdate != null)
2461 this.removeProgressPanel(vamUpdate);
2465 vamUpdate = this.addProgressPanel(
2466 MessageManager.getString("label.updating_vamsas_session"));
2468 vamsasStart.setVisible(!b);
2469 vamsasStop.setVisible(!b);
2470 vamsasSave.setVisible(!b);
2473 public JInternalFrame[] getAllFrames()
2475 return desktop.getAllFrames();
2479 * Checks the given url to see if it gives a response indicating that the user
2480 * should be informed of a new questionnaire.
2484 public void checkForQuestionnaire(String url)
2486 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2487 // javax.swing.SwingUtilities.invokeLater(jvq);
2488 new Thread(jvq).start();
2491 public void checkURLLinks()
2493 // Thread off the URL link checker
2494 addDialogThread(new Runnable()
2499 if (Cache.getDefault("CHECKURLLINKS", true))
2501 // check what the actual links are - if it's just the default don't
2502 // bother with the warning
2503 List<String> links = Preferences.sequenceUrlLinks
2506 // only need to check links if there is one with a
2507 // SEQUENCE_ID which is not the default EMBL_EBI link
2508 ListIterator<String> li = links.listIterator();
2509 boolean check = false;
2510 List<JLabel> urls = new ArrayList<>();
2511 while (li.hasNext())
2513 String link = li.next();
2514 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2515 && !UrlConstants.isDefaultString(link))
2518 int barPos = link.indexOf("|");
2519 String urlMsg = barPos == -1 ? link
2520 : link.substring(0, barPos) + ": "
2521 + link.substring(barPos + 1);
2522 urls.add(new JLabel(urlMsg));
2530 // ask user to check in case URL links use old style tokens
2531 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2532 JPanel msgPanel = new JPanel();
2533 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2534 msgPanel.add(Box.createVerticalGlue());
2535 JLabel msg = new JLabel(MessageManager
2536 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2537 JLabel msg2 = new JLabel(MessageManager
2538 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2540 for (JLabel url : urls)
2546 final JCheckBox jcb = new JCheckBox(
2547 MessageManager.getString("label.do_not_display_again"));
2548 jcb.addActionListener(new ActionListener()
2551 public void actionPerformed(ActionEvent e)
2553 // update Cache settings for "don't show this again"
2554 boolean showWarningAgain = !jcb.isSelected();
2555 Cache.setProperty("CHECKURLLINKS",
2556 Boolean.valueOf(showWarningAgain).toString());
2561 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2563 .getString("label.SEQUENCE_ID_no_longer_used"),
2564 JvOptionPane.WARNING_MESSAGE);
2571 * Proxy class for JDesktopPane which optionally displays the current memory
2572 * usage and highlights the desktop area with a red bar if free memory runs
2577 public class MyDesktopPane extends JDesktopPane implements Runnable
2580 private static final float ONE_MB = 1048576f;
2582 boolean showMemoryUsage = false;
2586 java.text.NumberFormat df;
2588 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2591 public MyDesktopPane(boolean showMemoryUsage)
2593 showMemoryUsage(showMemoryUsage);
2596 public void showMemoryUsage(boolean showMemory)
2598 this.showMemoryUsage = showMemory;
2601 Thread worker = new Thread(this);
2607 public boolean isShowMemoryUsage()
2609 return showMemoryUsage;
2615 df = java.text.NumberFormat.getNumberInstance();
2616 df.setMaximumFractionDigits(2);
2617 runtime = Runtime.getRuntime();
2619 while (showMemoryUsage)
2623 maxMemory = runtime.maxMemory() / ONE_MB;
2624 allocatedMemory = runtime.totalMemory() / ONE_MB;
2625 freeMemory = runtime.freeMemory() / ONE_MB;
2626 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2628 percentUsage = (totalFreeMemory / maxMemory) * 100;
2630 // if (percentUsage < 20)
2632 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2634 // instance.set.setBorder(border1);
2637 // sleep after showing usage
2639 } catch (Exception ex)
2641 ex.printStackTrace();
2647 public void paintComponent(Graphics g)
2649 if (showMemoryUsage && g != null && df != null)
2651 if (percentUsage < 20)
2653 g.setColor(Color.red);
2655 FontMetrics fm = g.getFontMetrics();
2658 g.drawString(MessageManager.formatMessage("label.memory_stats",
2660 { df.format(totalFreeMemory), df.format(maxMemory),
2661 df.format(percentUsage) }),
2662 10, getHeight() - fm.getHeight());
2669 * Accessor method to quickly get all the AlignmentFrames loaded.
2671 * @return an array of AlignFrame, or null if none found
2673 public static AlignFrame[] getAlignFrames()
2675 if (Jalview.isHeadlessMode())
2677 // Desktop.desktop is null in headless mode
2678 return new AlignFrame[] { Jalview.currentAlignFrame };
2681 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2687 List<AlignFrame> avp = new ArrayList<>();
2689 for (int i = frames.length - 1; i > -1; i--)
2691 if (frames[i] instanceof AlignFrame)
2693 avp.add((AlignFrame) frames[i]);
2695 else if (frames[i] instanceof SplitFrame)
2698 * Also check for a split frame containing an AlignFrame
2700 GSplitFrame sf = (GSplitFrame) frames[i];
2701 if (sf.getTopFrame() instanceof AlignFrame)
2703 avp.add((AlignFrame) sf.getTopFrame());
2705 if (sf.getBottomFrame() instanceof AlignFrame)
2707 avp.add((AlignFrame) sf.getBottomFrame());
2711 if (avp.size() == 0)
2715 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2720 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2724 public GStructureViewer[] getJmols()
2726 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2732 List<GStructureViewer> avp = new ArrayList<>();
2734 for (int i = frames.length - 1; i > -1; i--)
2736 if (frames[i] instanceof AppJmol)
2738 GStructureViewer af = (GStructureViewer) frames[i];
2742 if (avp.size() == 0)
2746 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2751 * Add Groovy Support to Jalview
2754 public void groovyShell_actionPerformed()
2758 openGroovyConsole();
2759 } catch (Exception ex)
2761 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2762 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2764 MessageManager.getString("label.couldnt_create_groovy_shell"),
2765 MessageManager.getString("label.groovy_support_failed"),
2766 JvOptionPane.ERROR_MESSAGE);
2771 * Open the Groovy console
2773 void openGroovyConsole()
2775 if (groovyConsole == null)
2777 groovyConsole = new groovy.ui.Console();
2778 groovyConsole.setVariable("Jalview", this);
2779 groovyConsole.run();
2782 * We allow only one console at a time, so that AlignFrame menu option
2783 * 'Calculate | Run Groovy script' is unambiguous.
2784 * Disable 'Groovy Console', and enable 'Run script', when the console is
2785 * opened, and the reverse when it is closed
2787 Window window = (Window) groovyConsole.getFrame();
2788 window.addWindowListener(new WindowAdapter()
2791 public void windowClosed(WindowEvent e)
2794 * rebind CMD-Q from Groovy Console to Jalview Quit
2797 enableExecuteGroovy(false);
2803 * show Groovy console window (after close and reopen)
2805 ((Window) groovyConsole.getFrame()).setVisible(true);
2808 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2809 * and disable opening a second console
2811 enableExecuteGroovy(true);
2815 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2816 * binding when opened
2818 protected void addQuitHandler()
2820 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2821 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2822 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2824 getRootPane().getActionMap().put("Quit", new AbstractAction()
2827 public void actionPerformed(ActionEvent e)
2835 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2838 * true if Groovy console is open
2840 public void enableExecuteGroovy(boolean enabled)
2843 * disable opening a second Groovy console
2844 * (or re-enable when the console is closed)
2846 groovyShell.setEnabled(!enabled);
2848 AlignFrame[] alignFrames = getAlignFrames();
2849 if (alignFrames != null)
2851 for (AlignFrame af : alignFrames)
2853 af.setGroovyEnabled(enabled);
2859 * Progress bars managed by the IProgressIndicator method.
2861 private Hashtable<Long, JPanel> progressBars;
2863 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2868 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2871 public void setProgressBar(String message, long id)
2873 if (progressBars == null)
2875 progressBars = new Hashtable<>();
2876 progressBarHandlers = new Hashtable<>();
2879 if (progressBars.get(new Long(id)) != null)
2881 JPanel panel = progressBars.remove(new Long(id));
2882 if (progressBarHandlers.contains(new Long(id)))
2884 progressBarHandlers.remove(new Long(id));
2886 removeProgressPanel(panel);
2890 progressBars.put(new Long(id), addProgressPanel(message));
2897 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2898 * jalview.gui.IProgressIndicatorHandler)
2901 public void registerHandler(final long id,
2902 final IProgressIndicatorHandler handler)
2904 if (progressBarHandlers == null
2905 || !progressBars.containsKey(new Long(id)))
2907 throw new Error(MessageManager.getString(
2908 "error.call_setprogressbar_before_registering_handler"));
2910 progressBarHandlers.put(new Long(id), handler);
2911 final JPanel progressPanel = progressBars.get(new Long(id));
2912 if (handler.canCancel())
2914 JButton cancel = new JButton(
2915 MessageManager.getString("action.cancel"));
2916 final IProgressIndicator us = this;
2917 cancel.addActionListener(new ActionListener()
2921 public void actionPerformed(ActionEvent e)
2923 handler.cancelActivity(id);
2924 us.setProgressBar(MessageManager
2925 .formatMessage("label.cancelled_params", new Object[]
2926 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2930 progressPanel.add(cancel, BorderLayout.EAST);
2936 * @return true if any progress bars are still active
2939 public boolean operationInProgress()
2941 if (progressBars != null && progressBars.size() > 0)
2949 * This will return the first AlignFrame holding the given viewport instance.
2950 * It will break if there are more than one AlignFrames viewing a particular
2954 * @return alignFrame for viewport
2956 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2958 if (desktop != null)
2960 AlignmentPanel[] aps = getAlignmentPanels(
2961 viewport.getSequenceSetId());
2962 for (int panel = 0; aps != null && panel < aps.length; panel++)
2964 if (aps[panel] != null && aps[panel].av == viewport)
2966 return aps[panel].alignFrame;
2973 public VamsasApplication getVamsasApplication()
2980 * flag set if jalview GUI is being operated programmatically
2982 private boolean inBatchMode = false;
2985 * check if jalview GUI is being operated programmatically
2987 * @return inBatchMode
2989 public boolean isInBatchMode()
2995 * set flag if jalview GUI is being operated programmatically
2997 * @param inBatchMode
2999 public void setInBatchMode(boolean inBatchMode)
3001 this.inBatchMode = inBatchMode;
3004 public void startServiceDiscovery()
3006 startServiceDiscovery(false);
3009 public void startServiceDiscovery(boolean blocking)
3011 boolean alive = true;
3012 Thread t0 = null, t1 = null, t2 = null;
3013 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3016 // todo: changesupport handlers need to be transferred
3017 if (discoverer == null)
3019 discoverer = new jalview.ws.jws1.Discoverer();
3020 // register PCS handler for desktop.
3021 discoverer.addPropertyChangeListener(changeSupport);
3023 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3024 // until we phase out completely
3025 (t0 = new Thread(discoverer)).start();
3028 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3030 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3031 .startDiscoverer(changeSupport);
3035 // TODO: do rest service discovery
3044 } catch (Exception e)
3047 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3048 || (t3 != null && t3.isAlive())
3049 || (t0 != null && t0.isAlive());
3055 * called to check if the service discovery process completed successfully.
3059 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3061 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3063 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3064 .getErrorMessages();
3067 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3069 if (serviceChangedDialog == null)
3071 // only run if we aren't already displaying one of these.
3072 addDialogThread(serviceChangedDialog = new Runnable()
3079 * JalviewDialog jd =new JalviewDialog() {
3081 * @Override protected void cancelPressed() { // TODO
3082 * Auto-generated method stub
3084 * }@Override protected void okPressed() { // TODO
3085 * Auto-generated method stub
3087 * }@Override protected void raiseClosed() { // TODO
3088 * Auto-generated method stub
3090 * } }; jd.initDialogFrame(new
3091 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3092 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3093 * + " or mis-configured HTTP proxy settings.<br/>" +
3094 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3096 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3097 * ), true, true, "Web Service Configuration Problem", 450,
3100 * jd.waitForInput();
3102 JvOptionPane.showConfirmDialog(Desktop.desktop,
3103 new JLabel("<html><table width=\"450\"><tr><td>"
3104 + ermsg + "</td></tr></table>"
3105 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3106 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3107 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3108 + " Tools->Preferences dialog box to change them.</p></html>"),
3109 "Web Service Configuration Problem",
3110 JvOptionPane.DEFAULT_OPTION,
3111 JvOptionPane.ERROR_MESSAGE);
3112 serviceChangedDialog = null;
3121 "Errors reported by JABA discovery service. Check web services preferences.\n"
3128 private Runnable serviceChangedDialog = null;
3131 * start a thread to open a URL in the configured browser. Pops up a warning
3132 * dialog to the user if there is an exception when calling out to the browser
3137 public static void showUrl(final String url)
3139 showUrl(url, Desktop.instance);
3143 * Like showUrl but allows progress handler to be specified
3147 * (null) or object implementing IProgressIndicator
3149 public static void showUrl(final String url,
3150 final IProgressIndicator progress)
3152 new Thread(new Runnable()
3159 if (progress != null)
3161 progress.setProgressBar(MessageManager
3162 .formatMessage("status.opening_params", new Object[]
3163 { url }), this.hashCode());
3165 jalview.util.BrowserLauncher.openURL(url);
3166 } catch (Exception ex)
3168 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3170 .getString("label.web_browser_not_found_unix"),
3171 MessageManager.getString("label.web_browser_not_found"),
3172 JvOptionPane.WARNING_MESSAGE);
3174 ex.printStackTrace();
3176 if (progress != null)
3178 progress.setProgressBar(null, this.hashCode());
3184 public static WsParamSetManager wsparamManager = null;
3186 public static ParamManager getUserParameterStore()
3188 if (wsparamManager == null)
3190 wsparamManager = new WsParamSetManager();
3192 return wsparamManager;
3196 * static hyperlink handler proxy method for use by Jalview's internal windows
3200 public static void hyperlinkUpdate(HyperlinkEvent e)
3202 if (e.getEventType() == EventType.ACTIVATED)
3207 url = e.getURL().toString();
3208 Desktop.showUrl(url);
3209 } catch (Exception x)
3213 if (Cache.log != null)
3215 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3220 "Couldn't handle string " + url + " as a URL.");
3223 // ignore any exceptions due to dud links.
3230 * single thread that handles display of dialogs to user.
3232 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3235 * flag indicating if dialogExecutor should try to acquire a permit
3237 private volatile boolean dialogPause = true;
3242 private java.util.concurrent.Semaphore block = new Semaphore(0);
3244 private static groovy.ui.Console groovyConsole;
3247 * add another dialog thread to the queue
3251 public void addDialogThread(final Runnable prompter)
3253 dialogExecutor.submit(new Runnable()
3263 } catch (InterruptedException x)
3268 if (instance == null)
3274 SwingUtilities.invokeAndWait(prompter);
3275 } catch (Exception q)
3277 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3283 public void startDialogQueue()
3285 // set the flag so we don't pause waiting for another permit and semaphore
3286 // the current task to begin
3287 dialogPause = false;
3292 protected void snapShotWindow_actionPerformed(ActionEvent e)
3296 ImageMaker im = new jalview.util.ImageMaker(
3297 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3298 getHeight(), of = new File("Jalview_snapshot"
3299 + System.currentTimeMillis() + ".eps"),
3300 "View of desktop", null, 0, false);
3303 paintAll(im.getGraphics());
3305 } catch (Exception q)
3307 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3311 Cache.log.info("Successfully written snapshot to file "
3312 + of.getAbsolutePath());
3316 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3317 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3318 * and location last time the view was expanded (if any). However it does not
3319 * remember the split pane divider location - this is set to match the
3320 * 'exploding' frame.
3324 public void explodeViews(SplitFrame sf)
3326 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3327 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3328 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3330 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3332 int viewCount = topPanels.size();
3339 * Processing in reverse order works, forwards order leaves the first panels
3340 * not visible. I don't know why!
3342 for (int i = viewCount - 1; i >= 0; i--)
3345 * Make new top and bottom frames. These take over the respective
3346 * AlignmentPanel objects, including their AlignmentViewports, so the
3347 * cdna/protein relationships between the viewports is carried over to the
3350 * explodedGeometry holds the (x, y) position of the previously exploded
3351 * SplitFrame, and the (width, height) of the AlignFrame component
3353 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3354 AlignFrame newTopFrame = new AlignFrame(topPanel);
3355 newTopFrame.setSize(oldTopFrame.getSize());
3356 newTopFrame.setVisible(true);
3357 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3358 .getExplodedGeometry();
3359 if (geometry != null)
3361 newTopFrame.setSize(geometry.getSize());
3364 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3365 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3366 newBottomFrame.setSize(oldBottomFrame.getSize());
3367 newBottomFrame.setVisible(true);
3368 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3369 .getExplodedGeometry();
3370 if (geometry != null)
3372 newBottomFrame.setSize(geometry.getSize());
3375 topPanel.av.setGatherViewsHere(false);
3376 bottomPanel.av.setGatherViewsHere(false);
3377 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3379 if (geometry != null)
3381 splitFrame.setLocation(geometry.getLocation());
3383 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3387 * Clear references to the panels (now relocated in the new SplitFrames)
3388 * before closing the old SplitFrame.
3391 bottomPanels.clear();
3396 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3397 * back into the given SplitFrame as additional views. Note that the gathered
3398 * frames may themselves have multiple views.
3402 public void gatherViews(GSplitFrame source)
3405 * special handling of explodedGeometry for a view within a SplitFrame: - it
3406 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3407 * height) of the AlignFrame component
3409 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3410 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3411 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3412 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3413 myBottomFrame.viewport
3414 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3415 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3416 myTopFrame.viewport.setGatherViewsHere(true);
3417 myBottomFrame.viewport.setGatherViewsHere(true);
3418 String topViewId = myTopFrame.viewport.getSequenceSetId();
3419 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3421 JInternalFrame[] frames = desktop.getAllFrames();
3422 for (JInternalFrame frame : frames)
3424 if (frame instanceof SplitFrame && frame != source)
3426 SplitFrame sf = (SplitFrame) frame;
3427 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3428 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3429 boolean gatherThis = false;
3430 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3432 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3433 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3434 if (topViewId.equals(topPanel.av.getSequenceSetId())
3435 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3438 topPanel.av.setGatherViewsHere(false);
3439 bottomPanel.av.setGatherViewsHere(false);
3440 topPanel.av.setExplodedGeometry(
3441 new Rectangle(sf.getLocation(), topFrame.getSize()));
3442 bottomPanel.av.setExplodedGeometry(
3443 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3444 myTopFrame.addAlignmentPanel(topPanel, false);
3445 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3451 topFrame.getAlignPanels().clear();
3452 bottomFrame.getAlignPanels().clear();
3459 * The dust settles...give focus to the tab we did this from.
3461 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3464 public static groovy.ui.Console getGroovyConsole()
3466 return groovyConsole;
3470 * handles the payload of a drag and drop event.
3472 * TODO refactor to desktop utilities class
3475 * - Data source strings extracted from the drop event
3477 * - protocol for each data source extracted from the drop event
3481 * - the payload from the drop event
3484 public static void transferFromDropTarget(List<String> files,
3485 List<DataSourceType> protocols, DropTargetDropEvent evt,
3486 Transferable t) throws Exception
3489 DataFlavor uriListFlavor = new DataFlavor(
3490 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3493 urlFlavour = new DataFlavor(
3494 "application/x-java-url; class=java.net.URL");
3495 } catch (ClassNotFoundException cfe)
3497 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3500 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3505 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3506 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3507 // means url may be null.
3510 protocols.add(DataSourceType.URL);
3511 files.add(url.toString());
3512 Cache.log.debug("Drop handled as URL dataflavor "
3513 + files.get(files.size() - 1));
3518 if (Platform.isAMac())
3521 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3525 } catch (Throwable ex)
3527 Cache.log.debug("URL drop handler failed.", ex);
3530 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3532 // Works on Windows and MacOSX
3533 Cache.log.debug("Drop handled as javaFileListFlavor");
3534 for (Object file : (List) t
3535 .getTransferData(DataFlavor.javaFileListFlavor))
3537 files.add(((File) file).toString());
3538 protocols.add(DataSourceType.FILE);
3543 // Unix like behaviour
3544 boolean added = false;
3546 if (t.isDataFlavorSupported(uriListFlavor))
3548 Cache.log.debug("Drop handled as uriListFlavor");
3549 // This is used by Unix drag system
3550 data = (String) t.getTransferData(uriListFlavor);
3554 // fallback to text: workaround - on OSX where there's a JVM bug
3555 Cache.log.debug("standard URIListFlavor failed. Trying text");
3556 // try text fallback
3557 DataFlavor textDf = new DataFlavor(
3558 "text/plain;class=java.lang.String");
3559 if (t.isDataFlavorSupported(textDf))
3561 data = (String) t.getTransferData(textDf);
3564 Cache.log.debug("Plain text drop content returned "
3565 + (data == null ? "Null - failed" : data));
3570 while (protocols.size() < files.size())
3572 Cache.log.debug("Adding missing FILE protocol for "
3573 + files.get(protocols.size()));
3574 protocols.add(DataSourceType.FILE);
3576 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3577 data, "\r\n"); st.hasMoreTokens();)
3580 String s = st.nextToken();
3581 if (s.startsWith("#"))
3583 // the line is a comment (as per the RFC 2483)
3586 java.net.URI uri = new java.net.URI(s);
3587 if (uri.getScheme().toLowerCase().startsWith("http"))
3589 protocols.add(DataSourceType.URL);
3590 files.add(uri.toString());
3594 // otherwise preserve old behaviour: catch all for file objects
3595 java.io.File file = new java.io.File(uri);
3596 protocols.add(DataSourceType.FILE);
3597 files.add(file.toString());
3602 if (Cache.log.isDebugEnabled())
3604 if (data == null || !added)
3607 if (t.getTransferDataFlavors() != null
3608 && t.getTransferDataFlavors().length > 0)
3611 "Couldn't resolve drop data. Here are the supported flavors:");
3612 for (DataFlavor fl : t.getTransferDataFlavors())
3615 "Supported transfer dataflavor: " + fl.toString());
3616 Object df = t.getTransferData(fl);
3619 Cache.log.debug("Retrieves: " + df);
3623 Cache.log.debug("Retrieved nothing");
3629 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3635 if (Platform.isWindows())
3638 Cache.log.debug("Scanning dropped content for Windows Link Files");
3640 // resolve any .lnk files in the file drop
3641 for (int f = 0; f < files.size(); f++)
3643 String source = files.get(f).toLowerCase();
3644 if (protocols.get(f).equals(DataSourceType.FILE)
3645 && (source.endsWith(".lnk") || source.endsWith(".url")
3646 || source.endsWith(".site")))
3650 File lf = new File(files.get(f));
3651 // process link file to get a URL
3652 Cache.log.debug("Found potential link file: " + lf);
3653 WindowsShortcut wscfile = new WindowsShortcut(lf);
3654 String fullname = wscfile.getRealFilename();
3655 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3656 files.set(f, fullname);
3657 Cache.log.debug("Parsed real filename " + fullname
3658 + " to extract protocol: " + protocols.get(f));
3659 } catch (Exception ex)
3662 "Couldn't parse " + files.get(f) + " as a link file.",
3671 * Sets the Preferences property for experimental features to True or False
3672 * depending on the state of the controlling menu item
3675 protected void showExperimental_actionPerformed(boolean selected)
3677 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3681 * Answers a (possibly empty) list of any structure viewer frames (currently
3682 * for either Jmol or Chimera) which are currently open. This may optionally
3683 * be restricted to viewers of a specified class, or viewers linked to a
3684 * specified alignment panel.
3687 * if not null, only return viewers linked to this panel
3688 * @param structureViewerClass
3689 * if not null, only return viewers of this class
3692 public List<StructureViewerBase> getStructureViewers(
3693 AlignmentPanel apanel,
3694 Class<? extends StructureViewerBase> structureViewerClass)
3696 List<StructureViewerBase> result = new ArrayList<>();
3697 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3699 for (JInternalFrame frame : frames)
3701 if (frame instanceof StructureViewerBase)
3703 if (structureViewerClass == null
3704 || structureViewerClass.isInstance(frame))
3707 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3709 result.add((StructureViewerBase) frame);