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
454 System.out.println("Shortcut Quit cancelled by user");
458 hdesktop.setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
463 } catch (NoSuchMethodException e)
466 "NoSuchMethodException when looking for About, Preferences, Quit Handlers");
470 setAPQHandlers = true;
473 addWindowListener(new WindowAdapter()
477 public void windowClosing(WindowEvent ev)
483 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
486 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
488 desktop = new MyDesktopPane(selmemusage);
489 showMemusage.setSelected(selmemusage);
490 desktop.setBackground(Color.white);
492 getContentPane().setLayout(new BorderLayout());
493 // alternate config - have scrollbars - see notes in JAL-153
494 // JScrollPane sp = new JScrollPane();
495 // sp.getViewport().setView(desktop);
496 // getContentPane().add(sp, BorderLayout.CENTER);
497 getContentPane().add(desktop, BorderLayout.CENTER);
498 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
500 // This line prevents Windows Look&Feel resizing all new windows to maximum
501 // if previous window was maximised
502 desktop.setDesktopManager(new MyDesktopManager(
503 (Platform.isWindows() ? new DefaultDesktopManager()
505 ? new AquaInternalFrameManager(
506 desktop.getDesktopManager())
507 : desktop.getDesktopManager())));
509 Rectangle dims = getLastKnownDimensions("");
516 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
517 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
520 jconsole = new Console(this, showjconsole);
521 // add essential build information
523 "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
524 + "\n" + "Jalview Installation: "
525 + jalview.bin.Cache.getDefault("INSTALLATION",
527 + "\n" + "Build Date: "
528 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
529 + "\n" + "Java version: "
530 + System.getProperty("java.version") + "\n"
531 + System.getProperty("os.arch") + " "
532 + System.getProperty("os.name") + " "
533 + System.getProperty("os.version"));
535 showConsole(showjconsole);
537 showNews.setVisible(false);
539 experimentalFeatures.setSelected(showExperimental());
541 getIdentifiersOrgData();
545 this.addWindowListener(new WindowAdapter()
548 public void windowClosing(WindowEvent evt)
555 this.addMouseListener(ma = new MouseAdapter()
558 public void mousePressed(MouseEvent evt)
560 if (evt.isPopupTrigger()) // Mac
562 showPasteMenu(evt.getX(), evt.getY());
567 public void mouseReleased(MouseEvent evt)
569 if (evt.isPopupTrigger()) // Windows
571 showPasteMenu(evt.getX(), evt.getY());
575 desktop.addMouseListener(ma);
577 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
578 // Spawn a thread that shows the splashscreen
579 SwingUtilities.invokeLater(new Runnable()
588 // Thread off a new instance of the file chooser - this reduces the time it
589 // takes to open it later on.
590 new Thread(new Runnable()
595 Cache.log.debug("Filechooser init thread started.");
596 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
597 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
599 Cache.log.debug("Filechooser init thread finished.");
602 // Add the service change listener
603 changeSupport.addJalviewPropertyChangeListener("services",
604 new PropertyChangeListener()
608 public void propertyChange(PropertyChangeEvent evt)
610 Cache.log.debug("Firing service changed event for "
611 + evt.getNewValue());
612 JalviewServicesChanged(evt);
619 * Answers true if user preferences to enable experimental features is True
624 public boolean showExperimental()
626 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
627 Boolean.FALSE.toString());
628 return Boolean.valueOf(experimental).booleanValue();
631 public void doConfigureStructurePrefs()
633 // configure services
634 StructureSelectionManager ssm = StructureSelectionManager
635 .getStructureSelectionManager(this);
636 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
638 ssm.setAddTempFacAnnot(jalview.bin.Cache
639 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
640 ssm.setProcessSecondaryStructure(jalview.bin.Cache
641 .getDefault(Preferences.STRUCT_FROM_PDB, true));
642 ssm.setSecStructServices(
643 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
647 ssm.setAddTempFacAnnot(false);
648 ssm.setProcessSecondaryStructure(false);
649 ssm.setSecStructServices(false);
653 public void checkForNews()
655 final Desktop me = this;
656 // Thread off the news reader, in case there are connection problems.
657 new Thread(new Runnable()
662 Cache.log.debug("Starting news thread.");
664 jvnews = new BlogReader(me);
665 showNews.setVisible(true);
666 Cache.log.debug("Completed news thread.");
671 public void getIdentifiersOrgData()
673 // Thread off the identifiers fetcher
674 new Thread(new Runnable()
679 Cache.log.debug("Downloading data from identifiers.org");
680 UrlDownloadClient client = new UrlDownloadClient();
683 client.download(IdOrgSettings.getUrl(),
684 IdOrgSettings.getDownloadLocation());
685 } catch (IOException e)
687 Cache.log.debug("Exception downloading identifiers.org data"
696 protected void showNews_actionPerformed(ActionEvent e)
698 showNews(showNews.isSelected());
701 void showNews(boolean visible)
704 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
705 showNews.setSelected(visible);
706 if (visible && !jvnews.isVisible())
708 new Thread(new Runnable()
713 long now = System.currentTimeMillis();
714 Desktop.instance.setProgressBar(
715 MessageManager.getString("status.refreshing_news"),
717 jvnews.refreshNews();
718 Desktop.instance.setProgressBar(null, now);
727 * recover the last known dimensions for a jalview window
730 * - empty string is desktop, all other windows have unique prefix
731 * @return null or last known dimensions scaled to current geometry (if last
732 * window geom was known)
734 Rectangle getLastKnownDimensions(String windowName)
736 // TODO: lock aspect ratio for scaling desktop Bug #0058199
737 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
738 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
739 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
740 String width = jalview.bin.Cache
741 .getProperty(windowName + "SCREEN_WIDTH");
742 String height = jalview.bin.Cache
743 .getProperty(windowName + "SCREEN_HEIGHT");
744 if ((x != null) && (y != null) && (width != null) && (height != null))
746 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
747 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
748 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
750 // attempt #1 - try to cope with change in screen geometry - this
751 // version doesn't preserve original jv aspect ratio.
752 // take ratio of current screen size vs original screen size.
753 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
754 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
755 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
756 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
757 // rescale the bounds depending upon the current screen geometry.
758 ix = (int) (ix * sw);
759 iw = (int) (iw * sw);
760 iy = (int) (iy * sh);
761 ih = (int) (ih * sh);
762 while (ix >= screenSize.width)
764 jalview.bin.Cache.log.debug(
765 "Window geometry location recall error: shifting horizontal to within screenbounds.");
766 ix -= screenSize.width;
768 while (iy >= screenSize.height)
770 jalview.bin.Cache.log.debug(
771 "Window geometry location recall error: shifting vertical to within screenbounds.");
772 iy -= screenSize.height;
774 jalview.bin.Cache.log.debug(
775 "Got last known dimensions for " + windowName + ": x:" + ix
776 + " y:" + iy + " width:" + iw + " height:" + ih);
778 // return dimensions for new instance
779 return new Rectangle(ix, iy, iw, ih);
784 private void doVamsasClientCheck()
786 if (jalview.bin.Cache.vamsasJarsPresent())
788 setupVamsasDisconnectedGui();
789 VamsasMenu.setVisible(true);
790 final Desktop us = this;
791 VamsasMenu.addMenuListener(new MenuListener()
793 // this listener remembers when the menu was first selected, and
794 // doesn't rebuild the session list until it has been cleared and
796 boolean refresh = true;
799 public void menuCanceled(MenuEvent e)
805 public void menuDeselected(MenuEvent e)
811 public void menuSelected(MenuEvent e)
815 us.buildVamsasStMenu();
820 vamsasStart.setVisible(true);
824 void showPasteMenu(int x, int y)
826 JPopupMenu popup = new JPopupMenu();
827 JMenuItem item = new JMenuItem(
828 MessageManager.getString("label.paste_new_window"));
829 item.addActionListener(new ActionListener()
832 public void actionPerformed(ActionEvent evt)
839 popup.show(this, x, y);
846 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
847 Transferable contents = c.getContents(this);
849 if (contents != null)
851 String file = (String) contents
852 .getTransferData(DataFlavor.stringFlavor);
854 FileFormatI format = new IdentifyFile().identify(file,
855 DataSourceType.PASTE);
857 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
860 } catch (Exception ex)
863 "Unable to paste alignment from system clipboard:\n" + ex);
868 * Adds and opens the given frame to the desktop
879 public static synchronized void addInternalFrame(
880 final JInternalFrame frame, String title, int w, int h)
882 addInternalFrame(frame, title, true, w, h, true, false);
886 * Add an internal frame to the Jalview desktop
893 * When true, display frame immediately, otherwise, caller must call
894 * setVisible themselves.
900 public static synchronized void addInternalFrame(
901 final JInternalFrame frame, String title, boolean makeVisible,
904 addInternalFrame(frame, title, makeVisible, w, h, true, false);
908 * Add an internal frame to the Jalview desktop and make it visible
921 public static synchronized void addInternalFrame(
922 final JInternalFrame frame, String title, int w, int h,
925 addInternalFrame(frame, title, true, w, h, resizable, false);
929 * Add an internal frame to the Jalview desktop
936 * When true, display frame immediately, otherwise, caller must call
937 * setVisible themselves.
944 * @param ignoreMinSize
945 * Do not set the default minimum size for frame
947 public static synchronized void addInternalFrame(
948 final JInternalFrame frame, String title, boolean makeVisible,
949 int w, int h, boolean resizable, boolean ignoreMinSize)
952 // TODO: allow callers to determine X and Y position of frame (eg. via
954 // TODO: consider fixing method to update entries in the window submenu with
955 // the current window title
957 frame.setTitle(title);
958 if (frame.getWidth() < 1 || frame.getHeight() < 1)
962 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
963 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
964 // IF JALVIEW IS RUNNING HEADLESS
965 // ///////////////////////////////////////////////
966 if (instance == null || (System.getProperty("java.awt.headless") != null
967 && System.getProperty("java.awt.headless").equals("true")))
976 frame.setMinimumSize(
977 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
979 // Set default dimension for Alignment Frame window.
980 // The Alignment Frame window could be added from a number of places,
982 // I did this here in order not to miss out on any Alignment frame.
983 if (frame instanceof AlignFrame)
985 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
986 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
990 frame.setVisible(makeVisible);
991 frame.setClosable(true);
992 frame.setResizable(resizable);
993 frame.setMaximizable(resizable);
994 frame.setIconifiable(resizable);
995 frame.setOpaque(false);
997 if (frame.getX() < 1 && frame.getY() < 1)
999 frame.setLocation(xOffset * openFrameCount,
1000 yOffset * ((openFrameCount - 1) % 10) + yOffset);
1004 * add an entry for the new frame in the Window menu
1005 * (and remove it when the frame is closed)
1007 final JMenuItem menuItem = new JMenuItem(title);
1008 frame.addInternalFrameListener(new InternalFrameAdapter()
1011 public void internalFrameActivated(InternalFrameEvent evt)
1013 JInternalFrame itf = desktop.getSelectedFrame();
1016 if (itf instanceof AlignFrame)
1018 Jalview.setCurrentAlignFrame((AlignFrame) itf);
1025 public void internalFrameClosed(InternalFrameEvent evt)
1027 PaintRefresher.RemoveComponent(frame);
1030 * defensive check to prevent frames being
1031 * added half off the window
1033 if (openFrameCount > 0)
1039 * ensure no reference to alignFrame retained by menu item listener
1041 if (menuItem.getActionListeners().length > 0)
1043 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
1045 windowMenu.remove(menuItem);
1049 menuItem.addActionListener(new ActionListener()
1052 public void actionPerformed(ActionEvent e)
1056 frame.setSelected(true);
1057 frame.setIcon(false);
1058 } catch (java.beans.PropertyVetoException ex)
1065 setKeyBindings(frame);
1069 windowMenu.add(menuItem);
1074 frame.setSelected(true);
1075 frame.requestFocus();
1076 } catch (java.beans.PropertyVetoException ve)
1078 } catch (java.lang.ClassCastException cex)
1081 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
1087 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
1092 private static void setKeyBindings(JInternalFrame frame)
1094 @SuppressWarnings("serial")
1095 final Action closeAction = new AbstractAction()
1098 public void actionPerformed(ActionEvent e)
1105 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1107 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1108 InputEvent.CTRL_DOWN_MASK);
1109 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1110 Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx());
1112 InputMap inputMap = frame
1113 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1114 String ctrlW = ctrlWKey.toString();
1115 inputMap.put(ctrlWKey, ctrlW);
1116 inputMap.put(cmdWKey, ctrlW);
1118 ActionMap actionMap = frame.getActionMap();
1119 actionMap.put(ctrlW, closeAction);
1123 public void lostOwnership(Clipboard clipboard, Transferable contents)
1127 Desktop.jalviewClipboard = null;
1130 internalCopy = false;
1134 public void dragEnter(DropTargetDragEvent evt)
1139 public void dragExit(DropTargetEvent evt)
1144 public void dragOver(DropTargetDragEvent evt)
1149 public void dropActionChanged(DropTargetDragEvent evt)
1160 public void drop(DropTargetDropEvent evt)
1162 boolean success = true;
1163 // JAL-1552 - acceptDrop required before getTransferable call for
1164 // Java's Transferable for native dnd
1165 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1166 Transferable t = evt.getTransferable();
1167 List<String> files = new ArrayList<>();
1168 List<DataSourceType> protocols = new ArrayList<>();
1172 Desktop.transferFromDropTarget(files, protocols, evt, t);
1173 } catch (Exception e)
1175 e.printStackTrace();
1183 for (int i = 0; i < files.size(); i++)
1185 String file = files.get(i).toString();
1186 DataSourceType protocol = (protocols == null)
1187 ? DataSourceType.FILE
1189 FileFormatI format = null;
1191 if (file.endsWith(".jar"))
1193 format = FileFormat.Jalview;
1198 format = new IdentifyFile().identify(file, protocol);
1201 new FileLoader().LoadFile(file, protocol, format);
1204 } catch (Exception ex)
1209 evt.dropComplete(success); // need this to ensure input focus is properly
1210 // transfered to any new windows created
1220 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1222 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1223 JalviewFileChooser chooser = JalviewFileChooser
1224 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1226 chooser.setFileView(new JalviewFileView());
1227 chooser.setDialogTitle(
1228 MessageManager.getString("label.open_local_file"));
1229 chooser.setToolTipText(MessageManager.getString("action.open"));
1231 int value = chooser.showOpenDialog(this);
1233 if (value == JalviewFileChooser.APPROVE_OPTION)
1235 String choice = chooser.getSelectedFile().getPath();
1236 Cache.setProperty("LAST_DIRECTORY",
1237 chooser.getSelectedFile().getParent());
1239 FileFormatI format = chooser.getSelectedFormat();
1242 * Call IdentifyFile to verify the file contains what its extension implies.
1243 * Skip this step for dynamically added file formats, because
1244 * IdentifyFile does not know how to recognise them.
1246 if (FileFormats.getInstance().isIdentifiable(format))
1250 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1251 } catch (FileFormatException e)
1253 // format = null; //??
1257 if (viewport != null)
1259 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1264 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1276 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1278 // This construct allows us to have a wider textfield
1280 JLabel label = new JLabel(
1281 MessageManager.getString("label.input_file_url"));
1282 final JComboBox history = new JComboBox();
1284 JPanel panel = new JPanel(new GridLayout(2, 1));
1287 history.setPreferredSize(new Dimension(400, 20));
1288 history.setEditable(true);
1289 history.addItem("http://www.");
1291 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1295 if (historyItems != null)
1297 st = new StringTokenizer(historyItems, "\t");
1299 while (st.hasMoreTokens())
1301 history.addItem(st.nextElement());
1305 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1306 MessageManager.getString("label.input_alignment_from_url"),
1307 JvOptionPane.OK_CANCEL_OPTION);
1309 if (reply != JvOptionPane.OK_OPTION)
1314 String url = history.getSelectedItem().toString();
1316 if (url.toLowerCase().endsWith(".jar"))
1318 if (viewport != null)
1320 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1321 FileFormat.Jalview);
1325 new FileLoader().LoadFile(url, DataSourceType.URL,
1326 FileFormat.Jalview);
1331 FileFormatI format = null;
1334 format = new IdentifyFile().identify(url, DataSourceType.URL);
1335 } catch (FileFormatException e)
1337 // TODO revise error handling, distinguish between
1338 // URL not found and response not valid
1343 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1344 MessageManager.formatMessage("label.couldnt_locate",
1347 MessageManager.getString("label.url_not_found"),
1348 JvOptionPane.WARNING_MESSAGE);
1353 if (viewport != null)
1355 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1360 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1366 * Opens the CutAndPaste window for the user to paste an alignment in to
1369 * - if not null, the pasted alignment is added to the current
1370 * alignment; if null, to a new alignment window
1373 public void inputTextboxMenuItem_actionPerformed(
1374 AlignmentViewPanel viewPanel)
1376 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1377 cap.setForInput(viewPanel);
1378 Desktop.addInternalFrame(cap,
1379 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1389 System.out.println("********** Desktop.quit()");
1390 System.out.println(savingFiles.toString());
1391 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1392 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1394 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1395 screen.height + "");
1396 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1397 getWidth(), getHeight()));
1399 if (jconsole != null)
1401 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1402 jconsole.stopConsole();
1406 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1409 if (dialogExecutor != null)
1411 dialogExecutor.shutdownNow();
1413 closeAll_actionPerformed(null);
1415 if (groovyConsole != null)
1417 // suppress a possible repeat prompt to save script
1418 groovyConsole.setDirty(false);
1419 groovyConsole.exit();
1424 private void storeLastKnownDimensions(String string, Rectangle jc)
1426 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1427 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1428 + " height:" + jc.height);
1430 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1431 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1432 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1433 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1443 public void aboutMenuItem_actionPerformed(ActionEvent e)
1445 // StringBuffer message = getAboutMessage(false);
1446 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1448 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1449 new Thread(new Runnable()
1454 new SplashScreen(true);
1459 public StringBuffer getAboutMessage(boolean shortv)
1461 StringBuffer message = new StringBuffer();
1462 message.append("<html>");
1465 message.append("<h1><strong>Version: "
1466 + jalview.bin.Cache.getProperty("VERSION")
1467 + "</strong></h1>");
1468 message.append("<strong>Last Updated: <em>"
1469 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1470 + "</em></strong>");
1476 message.append("<strong>Version "
1477 + jalview.bin.Cache.getProperty("VERSION")
1478 + "; last updated: "
1479 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1482 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1483 .equals("Checking"))
1485 message.append("<br>...Checking latest version...</br>");
1487 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1488 .equals(jalview.bin.Cache.getProperty("VERSION")))
1490 boolean red = false;
1491 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1492 .indexOf("automated build") == -1)
1495 // Displayed when code version and jnlp version do not match and code
1496 // version is not a development build
1497 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1500 message.append("<br>!! Version "
1501 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1503 + " is available for download from "
1504 + jalview.bin.Cache.getDefault("www.jalview.org",
1505 "http://www.jalview.org")
1509 message.append("</div>");
1512 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1514 "The Jalview Authors (See AUTHORS file for current list)")
1515 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1516 + "<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"
1517 + "<br><br>If you use Jalview, please cite:"
1518 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1519 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1520 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1532 public void documentationMenuItem_actionPerformed(ActionEvent e)
1536 Help.showHelpWindow();
1537 } catch (Exception ex)
1543 public void closeAll_actionPerformed(ActionEvent e)
1545 // TODO show a progress bar while closing?
1546 JInternalFrame[] frames = desktop.getAllFrames();
1547 for (int i = 0; i < frames.length; i++)
1551 frames[i].setClosed(true);
1552 } catch (java.beans.PropertyVetoException ex)
1556 Jalview.setCurrentAlignFrame(null);
1557 System.out.println("ALL CLOSED");
1558 if (v_client != null)
1560 // TODO clear binding to vamsas document objects on close_all
1564 * reset state of singleton objects as appropriate (clear down session state
1565 * when all windows are closed)
1567 StructureSelectionManager ssm = StructureSelectionManager
1568 .getStructureSelectionManager(this);
1576 public void raiseRelated_actionPerformed(ActionEvent e)
1578 reorderAssociatedWindows(false, false);
1582 public void minimizeAssociated_actionPerformed(ActionEvent e)
1584 reorderAssociatedWindows(true, false);
1587 void closeAssociatedWindows()
1589 reorderAssociatedWindows(false, true);
1595 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1599 protected void garbageCollect_actionPerformed(ActionEvent e)
1601 // We simply collect the garbage
1602 jalview.bin.Cache.log.debug("Collecting garbage...");
1604 jalview.bin.Cache.log.debug("Finished garbage collection.");
1611 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1615 protected void showMemusage_actionPerformed(ActionEvent e)
1617 desktop.showMemoryUsage(showMemusage.isSelected());
1624 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1628 protected void showConsole_actionPerformed(ActionEvent e)
1630 showConsole(showConsole.isSelected());
1633 Console jconsole = null;
1636 * control whether the java console is visible or not
1640 void showConsole(boolean selected)
1642 showConsole.setSelected(selected);
1643 // TODO: decide if we should update properties file
1644 Cache.setProperty("SHOW_JAVA_CONSOLE",
1645 Boolean.valueOf(selected).toString());
1646 jconsole.setVisible(selected);
1649 void reorderAssociatedWindows(boolean minimize, boolean close)
1651 JInternalFrame[] frames = desktop.getAllFrames();
1652 if (frames == null || frames.length < 1)
1657 AlignmentViewport source = null, target = null;
1658 if (frames[0] instanceof AlignFrame)
1660 source = ((AlignFrame) frames[0]).getCurrentView();
1662 else if (frames[0] instanceof TreePanel)
1664 source = ((TreePanel) frames[0]).getViewPort();
1666 else if (frames[0] instanceof PCAPanel)
1668 source = ((PCAPanel) frames[0]).av;
1670 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1672 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1677 for (int i = 0; i < frames.length; i++)
1680 if (frames[i] == null)
1684 if (frames[i] instanceof AlignFrame)
1686 target = ((AlignFrame) frames[i]).getCurrentView();
1688 else if (frames[i] instanceof TreePanel)
1690 target = ((TreePanel) frames[i]).getViewPort();
1692 else if (frames[i] instanceof PCAPanel)
1694 target = ((PCAPanel) frames[i]).av;
1696 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1698 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1701 if (source == target)
1707 frames[i].setClosed(true);
1711 frames[i].setIcon(minimize);
1714 frames[i].toFront();
1718 } catch (java.beans.PropertyVetoException ex)
1733 protected void preferences_actionPerformed(ActionEvent e)
1739 * Shows a file chooser dialog and writes out the current session as a Jalview
1743 public void saveState_actionPerformed()
1745 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1748 chooser.setFileView(new JalviewFileView());
1749 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1751 int value = chooser.showSaveDialog(this);
1753 if (value == JalviewFileChooser.APPROVE_OPTION)
1755 final Desktop me = this;
1756 final java.io.File choice = chooser.getSelectedFile();
1757 setProjectFile(choice);
1759 new Thread(new Runnable()
1764 // TODO: refactor to Jalview desktop session controller action.
1765 setProgressBar(MessageManager.formatMessage(
1766 "label.saving_jalview_project", new Object[]
1767 { choice.getName() }), choice.hashCode());
1768 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1769 choice.getParent());
1770 // TODO catch and handle errors for savestate
1771 // TODO prevent user from messing with the Desktop whilst we're saving
1774 new Jalview2XML().saveState(choice);
1775 } catch (OutOfMemoryError oom)
1778 "Whilst saving current state to " + choice.getName(),
1780 } catch (Exception ex)
1783 "Problems whilst trying to save to " + choice.getName(),
1785 JvOptionPane.showMessageDialog(me,
1786 MessageManager.formatMessage(
1787 "label.error_whilst_saving_current_state_to",
1789 { choice.getName() }),
1790 MessageManager.getString("label.couldnt_save_project"),
1791 JvOptionPane.WARNING_MESSAGE);
1793 setProgressBar(null, choice.hashCode());
1799 private void setProjectFile(File choice)
1801 this.projectFile = choice;
1804 public File getProjectFile()
1806 return this.projectFile;
1810 * Shows a file chooser dialog and tries to read in the selected file as a
1814 public void loadState_actionPerformed()
1816 final String[] suffix = new String[] { "jvp", "jar" };
1817 final String[] desc = new String[] { "Jalview Project",
1818 "Jalview Project (old)" };
1819 JalviewFileChooser chooser = new JalviewFileChooser(
1820 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
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().getMenuShortcutKeyMaskEx()),
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(Long.valueOf(id)) != null)
2884 JPanel panel = progressBars.remove(Long.valueOf(id));
2885 if (progressBarHandlers.contains(Long.valueOf(id)))
2887 progressBarHandlers.remove(Long.valueOf(id));
2889 removeProgressPanel(panel);
2893 progressBars.put(Long.valueOf(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(Long.valueOf(id)))
2910 throw new Error(MessageManager.getString(
2911 "error.call_setprogressbar_before_registering_handler"));
2913 progressBarHandlers.put(Long.valueOf(id), handler);
2914 final JPanel progressPanel = progressBars.get(Long.valueOf(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);