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 static jalview.util.UrlConstants.SEQUENCE_ID;
25 import jalview.api.AlignViewportI;
26 import jalview.api.AlignmentViewPanel;
27 import jalview.bin.Cache;
28 import jalview.bin.Jalview;
29 import jalview.io.DataSourceType;
30 import jalview.io.FileFormat;
31 import jalview.io.FileFormatException;
32 import jalview.io.FileFormatI;
33 import jalview.io.FileFormats;
34 import jalview.io.FileLoader;
35 import jalview.io.FormatAdapter;
36 import jalview.io.IdentifyFile;
37 import jalview.io.JalviewFileChooser;
38 import jalview.io.JalviewFileView;
39 import jalview.jbgui.GSplitFrame;
40 import jalview.jbgui.GStructureViewer;
41 import jalview.structure.StructureSelectionManager;
42 import jalview.urls.IdOrgSettings;
43 import jalview.util.ImageMaker;
44 import jalview.util.MessageManager;
45 import jalview.util.Platform;
46 import jalview.util.UrlConstants;
47 import jalview.viewmodel.AlignmentViewport;
48 import jalview.ws.params.ParamManager;
49 import jalview.ws.utils.UrlDownloadClient;
51 import java.awt.BorderLayout;
52 import java.awt.Color;
53 import java.awt.Dimension;
54 import java.awt.FontMetrics;
55 import java.awt.Graphics;
56 import java.awt.GridLayout;
57 import java.awt.Point;
58 import java.awt.Rectangle;
59 import java.awt.Toolkit;
60 import java.awt.Window;
61 import java.awt.datatransfer.Clipboard;
62 import java.awt.datatransfer.ClipboardOwner;
63 import java.awt.datatransfer.DataFlavor;
64 import java.awt.datatransfer.Transferable;
65 import java.awt.dnd.DnDConstants;
66 import java.awt.dnd.DropTargetDragEvent;
67 import java.awt.dnd.DropTargetDropEvent;
68 import java.awt.dnd.DropTargetEvent;
69 import java.awt.dnd.DropTargetListener;
70 import java.awt.event.ActionEvent;
71 import java.awt.event.ActionListener;
72 import java.awt.event.InputEvent;
73 import java.awt.event.KeyEvent;
74 import java.awt.event.MouseAdapter;
75 import java.awt.event.MouseEvent;
76 import java.awt.event.WindowAdapter;
77 import java.awt.event.WindowEvent;
78 import java.beans.PropertyChangeEvent;
79 import java.beans.PropertyChangeListener;
80 import java.io.BufferedInputStream;
82 import java.io.FileOutputStream;
83 import java.io.FileWriter;
84 import java.io.IOException;
86 import java.util.ArrayList;
87 import java.util.HashMap;
88 import java.util.Hashtable;
89 import java.util.List;
90 import java.util.ListIterator;
91 import java.util.StringTokenizer;
92 import java.util.Vector;
93 import java.util.concurrent.ExecutorService;
94 import java.util.concurrent.Executors;
95 import java.util.concurrent.Semaphore;
97 import javax.swing.AbstractAction;
98 import javax.swing.Action;
99 import javax.swing.ActionMap;
100 import javax.swing.Box;
101 import javax.swing.BoxLayout;
102 import javax.swing.DefaultDesktopManager;
103 import javax.swing.DesktopManager;
104 import javax.swing.InputMap;
105 import javax.swing.JButton;
106 import javax.swing.JCheckBox;
107 import javax.swing.JComboBox;
108 import javax.swing.JComponent;
109 import javax.swing.JDesktopPane;
110 import javax.swing.JInternalFrame;
111 import javax.swing.JLabel;
112 import javax.swing.JMenuItem;
113 import javax.swing.JPanel;
114 import javax.swing.JPopupMenu;
115 import javax.swing.JProgressBar;
116 import javax.swing.KeyStroke;
117 import javax.swing.SwingUtilities;
118 import javax.swing.WindowConstants;
119 import javax.swing.event.HyperlinkEvent;
120 import javax.swing.event.HyperlinkEvent.EventType;
121 import javax.swing.event.InternalFrameAdapter;
122 import javax.swing.event.InternalFrameEvent;
123 import javax.swing.event.MenuEvent;
124 import javax.swing.event.MenuListener;
126 import org.stackoverflowusers.file.WindowsShortcut;
132 * @version $Revision: 1.155 $
134 public class Desktop extends jalview.jbgui.GDesktop
135 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
136 jalview.api.StructureSelectionManagerProvider
138 private static int DEFAULT_MIN_WIDTH = 300;
140 private static int DEFAULT_MIN_HEIGHT = 250;
142 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
144 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
146 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
148 public static HashMap<String, FileWriter> savingFiles = new HashMap<>();
150 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
153 * news reader - null if it was never started.
155 private BlogReader jvnews = null;
157 private File projectFile;
161 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
163 public void addJalviewPropertyChangeListener(
164 PropertyChangeListener listener)
166 changeSupport.addJalviewPropertyChangeListener(listener);
170 * @param propertyName
172 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
173 * java.beans.PropertyChangeListener)
175 public void addJalviewPropertyChangeListener(String propertyName,
176 PropertyChangeListener listener)
178 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
182 * @param propertyName
184 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
185 * java.beans.PropertyChangeListener)
187 public void removeJalviewPropertyChangeListener(String propertyName,
188 PropertyChangeListener listener)
190 changeSupport.removeJalviewPropertyChangeListener(propertyName,
194 /** Singleton Desktop instance */
195 public static Desktop instance;
197 public static MyDesktopPane desktop;
199 static int openFrameCount = 0;
201 static final int xOffset = 30;
203 static final int yOffset = 30;
205 public static jalview.ws.jws1.Discoverer discoverer;
207 public static Object[] jalviewClipboard;
209 public static boolean internalCopy = false;
211 static int fileLoadingCount = 0;
213 class MyDesktopManager implements DesktopManager
216 private DesktopManager delegate;
218 public MyDesktopManager(DesktopManager delegate)
220 this.delegate = delegate;
224 public void activateFrame(JInternalFrame f)
228 delegate.activateFrame(f);
229 } catch (NullPointerException npe)
231 Point p = getMousePosition();
232 instance.showPasteMenu(p.x, p.y);
237 public void beginDraggingFrame(JComponent f)
239 delegate.beginDraggingFrame(f);
243 public void beginResizingFrame(JComponent f, int direction)
245 delegate.beginResizingFrame(f, direction);
249 public void closeFrame(JInternalFrame f)
251 delegate.closeFrame(f);
255 public void deactivateFrame(JInternalFrame f)
257 delegate.deactivateFrame(f);
261 public void deiconifyFrame(JInternalFrame f)
263 delegate.deiconifyFrame(f);
267 public void dragFrame(JComponent f, int newX, int newY)
273 delegate.dragFrame(f, newX, newY);
277 public void endDraggingFrame(JComponent f)
279 delegate.endDraggingFrame(f);
284 public void endResizingFrame(JComponent f)
286 delegate.endResizingFrame(f);
291 public void iconifyFrame(JInternalFrame f)
293 delegate.iconifyFrame(f);
297 public void maximizeFrame(JInternalFrame f)
299 delegate.maximizeFrame(f);
303 public void minimizeFrame(JInternalFrame f)
305 delegate.minimizeFrame(f);
309 public void openFrame(JInternalFrame f)
311 delegate.openFrame(f);
315 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
322 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
326 public void setBoundsForFrame(JComponent f, int newX, int newY,
327 int newWidth, int newHeight)
329 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
332 // All other methods, simply delegate
337 * Creates a new Desktop object.
342 * A note to implementors. It is ESSENTIAL that any activities that might
343 * block are spawned off as threads rather than waited for during this
347 doVamsasClientCheck();
349 doConfigureStructurePrefs();
350 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
351 // setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
352 if (!Platform.isAMac())
354 this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
358 this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
359 this.addQuitHandler();
362 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
364 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
366 desktop = new MyDesktopPane(selmemusage);
367 showMemusage.setSelected(selmemusage);
368 desktop.setBackground(Color.white);
369 getContentPane().setLayout(new BorderLayout());
370 // alternate config - have scrollbars - see notes in JAL-153
371 // JScrollPane sp = new JScrollPane();
372 // sp.getViewport().setView(desktop);
373 // getContentPane().add(sp, BorderLayout.CENTER);
374 getContentPane().add(desktop, BorderLayout.CENTER);
375 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
377 // This line prevents Windows Look&Feel resizing all new windows to maximum
378 // if previous window was maximised
379 desktop.setDesktopManager(
380 new MyDesktopManager(
381 (Platform.isWindows() ? new DefaultDesktopManager()
383 ? new AquaInternalFrameManager(
384 desktop.getDesktopManager())
385 : desktop.getDesktopManager())));
387 Rectangle dims = getLastKnownDimensions("");
394 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
395 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
398 jconsole = new Console(this, showjconsole);
399 // add essential build information
401 "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
402 + "\n" + "Jalview Installation: "
403 + jalview.bin.Cache.getDefault("INSTALLATION",
405 + "\n" + "Build Date: "
406 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
407 + "\n" + "Java version: "
408 + System.getProperty("java.version") + "\n"
409 + System.getProperty("os.arch") + " "
410 + System.getProperty("os.name") + " "
411 + System.getProperty("os.version"));
413 showConsole(showjconsole);
415 showNews.setVisible(false);
417 experimentalFeatures.setSelected(showExperimental());
419 getIdentifiersOrgData();
423 this.addWindowListener(new WindowAdapter()
426 public void windowClosing(WindowEvent evt)
433 this.addMouseListener(ma = new MouseAdapter()
436 public void mousePressed(MouseEvent evt)
438 if (evt.isPopupTrigger()) // Mac
440 showPasteMenu(evt.getX(), evt.getY());
445 public void mouseReleased(MouseEvent evt)
447 if (evt.isPopupTrigger()) // Windows
449 showPasteMenu(evt.getX(), evt.getY());
453 desktop.addMouseListener(ma);
455 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
456 // Spawn a thread that shows the splashscreen
457 SwingUtilities.invokeLater(new Runnable()
466 // Thread off a new instance of the file chooser - this reduces the time it
467 // takes to open it later on.
468 new Thread(new Runnable()
473 Cache.log.debug("Filechooser init thread started.");
474 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
475 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
477 Cache.log.debug("Filechooser init thread finished.");
480 // Add the service change listener
481 changeSupport.addJalviewPropertyChangeListener("services",
482 new PropertyChangeListener()
486 public void propertyChange(PropertyChangeEvent evt)
488 Cache.log.debug("Firing service changed event for "
489 + evt.getNewValue());
490 JalviewServicesChanged(evt);
497 * Answers true if user preferences to enable experimental features is True
502 public boolean showExperimental()
504 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
505 Boolean.FALSE.toString());
506 return Boolean.valueOf(experimental).booleanValue();
509 public void doConfigureStructurePrefs()
511 // configure services
512 StructureSelectionManager ssm = StructureSelectionManager
513 .getStructureSelectionManager(this);
514 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
516 ssm.setAddTempFacAnnot(jalview.bin.Cache
517 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
518 ssm.setProcessSecondaryStructure(jalview.bin.Cache
519 .getDefault(Preferences.STRUCT_FROM_PDB, true));
520 ssm.setSecStructServices(
521 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
525 ssm.setAddTempFacAnnot(false);
526 ssm.setProcessSecondaryStructure(false);
527 ssm.setSecStructServices(false);
531 public void checkForNews()
533 final Desktop me = this;
534 // Thread off the news reader, in case there are connection problems.
535 new Thread(new Runnable()
540 Cache.log.debug("Starting news thread.");
542 jvnews = new BlogReader(me);
543 showNews.setVisible(true);
544 Cache.log.debug("Completed news thread.");
549 public void getIdentifiersOrgData()
551 // Thread off the identifiers fetcher
552 new Thread(new Runnable()
557 Cache.log.debug("Downloading data from identifiers.org");
558 UrlDownloadClient client = new UrlDownloadClient();
561 client.download(IdOrgSettings.getUrl(),
562 IdOrgSettings.getDownloadLocation());
563 } catch (IOException e)
565 Cache.log.debug("Exception downloading identifiers.org data"
574 protected void showNews_actionPerformed(ActionEvent e)
576 showNews(showNews.isSelected());
579 void showNews(boolean visible)
582 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
583 showNews.setSelected(visible);
584 if (visible && !jvnews.isVisible())
586 new Thread(new Runnable()
591 long now = System.currentTimeMillis();
592 Desktop.instance.setProgressBar(
593 MessageManager.getString("status.refreshing_news"),
595 jvnews.refreshNews();
596 Desktop.instance.setProgressBar(null, now);
605 * recover the last known dimensions for a jalview window
608 * - empty string is desktop, all other windows have unique prefix
609 * @return null or last known dimensions scaled to current geometry (if last
610 * window geom was known)
612 Rectangle getLastKnownDimensions(String windowName)
614 // TODO: lock aspect ratio for scaling desktop Bug #0058199
615 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
616 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
617 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
618 String width = jalview.bin.Cache
619 .getProperty(windowName + "SCREEN_WIDTH");
620 String height = jalview.bin.Cache
621 .getProperty(windowName + "SCREEN_HEIGHT");
622 if ((x != null) && (y != null) && (width != null) && (height != null))
624 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
625 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
626 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
628 // attempt #1 - try to cope with change in screen geometry - this
629 // version doesn't preserve original jv aspect ratio.
630 // take ratio of current screen size vs original screen size.
631 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
632 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
633 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
634 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
635 // rescale the bounds depending upon the current screen geometry.
636 ix = (int) (ix * sw);
637 iw = (int) (iw * sw);
638 iy = (int) (iy * sh);
639 ih = (int) (ih * sh);
640 while (ix >= screenSize.width)
642 jalview.bin.Cache.log.debug(
643 "Window geometry location recall error: shifting horizontal to within screenbounds.");
644 ix -= screenSize.width;
646 while (iy >= screenSize.height)
648 jalview.bin.Cache.log.debug(
649 "Window geometry location recall error: shifting vertical to within screenbounds.");
650 iy -= screenSize.height;
652 jalview.bin.Cache.log.debug(
653 "Got last known dimensions for " + windowName + ": x:" + ix
654 + " y:" + iy + " width:" + iw + " height:" + ih);
656 // return dimensions for new instance
657 return new Rectangle(ix, iy, iw, ih);
662 private void doVamsasClientCheck()
664 if (jalview.bin.Cache.vamsasJarsPresent())
666 setupVamsasDisconnectedGui();
667 VamsasMenu.setVisible(true);
668 final Desktop us = this;
669 VamsasMenu.addMenuListener(new MenuListener()
671 // this listener remembers when the menu was first selected, and
672 // doesn't rebuild the session list until it has been cleared and
674 boolean refresh = true;
677 public void menuCanceled(MenuEvent e)
683 public void menuDeselected(MenuEvent e)
689 public void menuSelected(MenuEvent e)
693 us.buildVamsasStMenu();
698 vamsasStart.setVisible(true);
702 void showPasteMenu(int x, int y)
704 JPopupMenu popup = new JPopupMenu();
705 JMenuItem item = new JMenuItem(
706 MessageManager.getString("label.paste_new_window"));
707 item.addActionListener(new ActionListener()
710 public void actionPerformed(ActionEvent evt)
717 popup.show(this, x, y);
724 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
725 Transferable contents = c.getContents(this);
727 if (contents != null)
729 String file = (String) contents
730 .getTransferData(DataFlavor.stringFlavor);
732 FileFormatI format = new IdentifyFile().identify(file,
733 DataSourceType.PASTE);
735 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
738 } catch (Exception ex)
741 "Unable to paste alignment from system clipboard:\n" + ex);
746 * Adds and opens the given frame to the desktop
757 public static synchronized void addInternalFrame(
758 final JInternalFrame frame, String title, int w, int h)
760 addInternalFrame(frame, title, true, w, h, true, false);
764 * Add an internal frame to the Jalview desktop
771 * When true, display frame immediately, otherwise, caller must call
772 * setVisible themselves.
778 public static synchronized void addInternalFrame(
779 final JInternalFrame frame, String title, boolean makeVisible,
782 addInternalFrame(frame, title, makeVisible, w, h, true, false);
786 * Add an internal frame to the Jalview desktop and make it visible
799 public static synchronized void addInternalFrame(
800 final JInternalFrame frame, String title, int w, int h,
803 addInternalFrame(frame, title, true, w, h, resizable, false);
807 * Add an internal frame to the Jalview desktop
814 * When true, display frame immediately, otherwise, caller must call
815 * setVisible themselves.
822 * @param ignoreMinSize
823 * Do not set the default minimum size for frame
825 public static synchronized void addInternalFrame(
826 final JInternalFrame frame, String title, boolean makeVisible,
827 int w, int h, boolean resizable, boolean ignoreMinSize)
830 // TODO: allow callers to determine X and Y position of frame (eg. via
832 // TODO: consider fixing method to update entries in the window submenu with
833 // the current window title
835 frame.setTitle(title);
836 if (frame.getWidth() < 1 || frame.getHeight() < 1)
840 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
841 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
842 // IF JALVIEW IS RUNNING HEADLESS
843 // ///////////////////////////////////////////////
844 if (instance == null || (System.getProperty("java.awt.headless") != null
845 && System.getProperty("java.awt.headless").equals("true")))
854 frame.setMinimumSize(
855 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
857 // Set default dimension for Alignment Frame window.
858 // The Alignment Frame window could be added from a number of places,
860 // I did this here in order not to miss out on any Alignment frame.
861 if (frame instanceof AlignFrame)
863 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
864 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
868 frame.setVisible(makeVisible);
869 frame.setClosable(true);
870 frame.setResizable(resizable);
871 frame.setMaximizable(resizable);
872 frame.setIconifiable(resizable);
873 frame.setOpaque(false);
875 if (frame.getX() < 1 && frame.getY() < 1)
877 frame.setLocation(xOffset * openFrameCount,
878 yOffset * ((openFrameCount - 1) % 10) + yOffset);
882 * add an entry for the new frame in the Window menu
883 * (and remove it when the frame is closed)
885 final JMenuItem menuItem = new JMenuItem(title);
886 frame.addInternalFrameListener(new InternalFrameAdapter()
889 public void internalFrameActivated(InternalFrameEvent evt)
891 JInternalFrame itf = desktop.getSelectedFrame();
894 if (itf instanceof AlignFrame)
896 Jalview.setCurrentAlignFrame((AlignFrame) itf);
903 public void internalFrameClosed(InternalFrameEvent evt)
905 PaintRefresher.RemoveComponent(frame);
908 * defensive check to prevent frames being
909 * added half off the window
911 if (openFrameCount > 0)
917 * ensure no reference to alignFrame retained by menu item listener
919 if (menuItem.getActionListeners().length > 0)
921 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
923 windowMenu.remove(menuItem);
927 menuItem.addActionListener(new ActionListener()
930 public void actionPerformed(ActionEvent e)
934 frame.setSelected(true);
935 frame.setIcon(false);
936 } catch (java.beans.PropertyVetoException ex)
943 setKeyBindings(frame);
947 windowMenu.add(menuItem);
952 frame.setSelected(true);
953 frame.requestFocus();
954 } catch (java.beans.PropertyVetoException ve)
956 } catch (java.lang.ClassCastException cex)
959 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
965 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
970 private static void setKeyBindings(JInternalFrame frame)
972 @SuppressWarnings("serial")
973 final Action closeAction = new AbstractAction()
976 public void actionPerformed(ActionEvent e)
983 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
985 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
986 InputEvent.CTRL_DOWN_MASK);
987 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
988 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
990 InputMap inputMap = frame
991 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
992 String ctrlW = ctrlWKey.toString();
993 inputMap.put(ctrlWKey, ctrlW);
994 inputMap.put(cmdWKey, ctrlW);
996 ActionMap actionMap = frame.getActionMap();
997 actionMap.put(ctrlW, closeAction);
1001 public void lostOwnership(Clipboard clipboard, Transferable contents)
1005 Desktop.jalviewClipboard = null;
1008 internalCopy = false;
1012 public void dragEnter(DropTargetDragEvent evt)
1017 public void dragExit(DropTargetEvent evt)
1022 public void dragOver(DropTargetDragEvent evt)
1027 public void dropActionChanged(DropTargetDragEvent evt)
1038 public void drop(DropTargetDropEvent evt)
1040 boolean success = true;
1041 // JAL-1552 - acceptDrop required before getTransferable call for
1042 // Java's Transferable for native dnd
1043 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1044 Transferable t = evt.getTransferable();
1045 List<String> files = new ArrayList<>();
1046 List<DataSourceType> protocols = new ArrayList<>();
1050 Desktop.transferFromDropTarget(files, protocols, evt, t);
1051 } catch (Exception e)
1053 e.printStackTrace();
1061 for (int i = 0; i < files.size(); i++)
1063 String file = files.get(i).toString();
1064 DataSourceType protocol = (protocols == null)
1065 ? DataSourceType.FILE
1067 FileFormatI format = null;
1069 if (file.endsWith(".jar"))
1071 format = FileFormat.Jalview;
1076 format = new IdentifyFile().identify(file, protocol);
1079 new FileLoader().LoadFile(file, protocol, format);
1082 } catch (Exception ex)
1087 evt.dropComplete(success); // need this to ensure input focus is properly
1088 // transfered to any new windows created
1098 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1100 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1101 JalviewFileChooser chooser = JalviewFileChooser
1102 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1104 chooser.setFileView(new JalviewFileView());
1105 chooser.setDialogTitle(
1106 MessageManager.getString("label.open_local_file"));
1107 chooser.setToolTipText(MessageManager.getString("action.open"));
1109 int value = chooser.showOpenDialog(this);
1111 if (value == JalviewFileChooser.APPROVE_OPTION)
1113 String choice = chooser.getSelectedFile().getPath();
1114 Cache.setProperty("LAST_DIRECTORY",
1115 chooser.getSelectedFile().getParent());
1117 FileFormatI format = chooser.getSelectedFormat();
1120 * Call IdentifyFile to verify the file contains what its extension implies.
1121 * Skip this step for dynamically added file formats, because
1122 * IdentifyFile does not know how to recognise them.
1124 if (FileFormats.getInstance().isIdentifiable(format))
1128 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1129 } catch (FileFormatException e)
1131 // format = null; //??
1135 if (viewport != null)
1137 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1142 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1154 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1156 // This construct allows us to have a wider textfield
1158 JLabel label = new JLabel(
1159 MessageManager.getString("label.input_file_url"));
1160 final JComboBox history = new JComboBox();
1162 JPanel panel = new JPanel(new GridLayout(2, 1));
1165 history.setPreferredSize(new Dimension(400, 20));
1166 history.setEditable(true);
1167 history.addItem("http://www.");
1169 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1173 if (historyItems != null)
1175 st = new StringTokenizer(historyItems, "\t");
1177 while (st.hasMoreTokens())
1179 history.addItem(st.nextElement());
1183 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1184 MessageManager.getString("label.input_alignment_from_url"),
1185 JvOptionPane.OK_CANCEL_OPTION);
1187 if (reply != JvOptionPane.OK_OPTION)
1192 String url = history.getSelectedItem().toString();
1194 if (url.toLowerCase().endsWith(".jar"))
1196 if (viewport != null)
1198 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1199 FileFormat.Jalview);
1203 new FileLoader().LoadFile(url, DataSourceType.URL,
1204 FileFormat.Jalview);
1209 FileFormatI format = null;
1212 format = new IdentifyFile().identify(url, DataSourceType.URL);
1213 } catch (FileFormatException e)
1215 // TODO revise error handling, distinguish between
1216 // URL not found and response not valid
1221 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1222 MessageManager.formatMessage("label.couldnt_locate",
1225 MessageManager.getString("label.url_not_found"),
1226 JvOptionPane.WARNING_MESSAGE);
1231 if (viewport != null)
1233 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1238 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1244 * Opens the CutAndPaste window for the user to paste an alignment in to
1247 * - if not null, the pasted alignment is added to the current
1248 * alignment; if null, to a new alignment window
1251 public void inputTextboxMenuItem_actionPerformed(
1252 AlignmentViewPanel viewPanel)
1254 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1255 cap.setForInput(viewPanel);
1256 Desktop.addInternalFrame(cap,
1257 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1267 System.out.println("********** Desktop.quit()");
1268 System.out.println(savingFiles.toString());
1269 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1270 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1272 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1273 screen.height + "");
1274 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1275 getWidth(), getHeight()));
1277 if (jconsole != null)
1279 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1280 jconsole.stopConsole();
1284 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1287 if (dialogExecutor != null)
1289 dialogExecutor.shutdownNow();
1291 closeAll_actionPerformed(null);
1293 if (groovyConsole != null)
1295 // suppress a possible repeat prompt to save script
1296 groovyConsole.setDirty(false);
1297 groovyConsole.exit();
1302 private void storeLastKnownDimensions(String string, Rectangle jc)
1304 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1305 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1306 + " height:" + jc.height);
1308 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1309 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1310 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1311 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1321 public void aboutMenuItem_actionPerformed(ActionEvent e)
1323 // StringBuffer message = getAboutMessage(false);
1324 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1326 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1327 new Thread(new Runnable()
1332 new SplashScreen(true);
1337 public StringBuffer getAboutMessage(boolean shortv)
1339 StringBuffer message = new StringBuffer();
1340 message.append("<html>");
1343 message.append("<h1><strong>Version: "
1344 + jalview.bin.Cache.getProperty("VERSION")
1345 + "</strong></h1>");
1346 message.append("<strong>Last Updated: <em>"
1347 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1348 + "</em></strong>");
1354 message.append("<strong>Version "
1355 + jalview.bin.Cache.getProperty("VERSION")
1356 + "; last updated: "
1357 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1360 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1361 .equals("Checking"))
1363 message.append("<br>...Checking latest version...</br>");
1365 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1366 .equals(jalview.bin.Cache.getProperty("VERSION")))
1368 boolean red = false;
1369 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1370 .indexOf("automated build") == -1)
1373 // Displayed when code version and jnlp version do not match and code
1374 // version is not a development build
1375 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1378 message.append("<br>!! Version "
1379 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1381 + " is available for download from "
1382 + jalview.bin.Cache.getDefault("www.jalview.org",
1383 "http://www.jalview.org")
1387 message.append("</div>");
1390 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1392 "The Jalview Authors (See AUTHORS file for current list)")
1393 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1394 + "<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"
1395 + "<br><br>If you use Jalview, please cite:"
1396 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1397 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1398 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1410 public void documentationMenuItem_actionPerformed(ActionEvent e)
1414 Help.showHelpWindow();
1415 } catch (Exception ex)
1421 public void closeAll_actionPerformed(ActionEvent e)
1423 // TODO show a progress bar while closing?
1424 JInternalFrame[] frames = desktop.getAllFrames();
1425 for (int i = 0; i < frames.length; i++)
1429 frames[i].setClosed(true);
1430 } catch (java.beans.PropertyVetoException ex)
1434 Jalview.setCurrentAlignFrame(null);
1435 System.out.println("ALL CLOSED");
1436 if (v_client != null)
1438 // TODO clear binding to vamsas document objects on close_all
1442 * reset state of singleton objects as appropriate (clear down session state
1443 * when all windows are closed)
1445 StructureSelectionManager ssm = StructureSelectionManager
1446 .getStructureSelectionManager(this);
1454 public void raiseRelated_actionPerformed(ActionEvent e)
1456 reorderAssociatedWindows(false, false);
1460 public void minimizeAssociated_actionPerformed(ActionEvent e)
1462 reorderAssociatedWindows(true, false);
1465 void closeAssociatedWindows()
1467 reorderAssociatedWindows(false, true);
1473 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1477 protected void garbageCollect_actionPerformed(ActionEvent e)
1479 // We simply collect the garbage
1480 jalview.bin.Cache.log.debug("Collecting garbage...");
1482 jalview.bin.Cache.log.debug("Finished garbage collection.");
1489 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1493 protected void showMemusage_actionPerformed(ActionEvent e)
1495 desktop.showMemoryUsage(showMemusage.isSelected());
1502 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1506 protected void showConsole_actionPerformed(ActionEvent e)
1508 showConsole(showConsole.isSelected());
1511 Console jconsole = null;
1514 * control whether the java console is visible or not
1518 void showConsole(boolean selected)
1520 showConsole.setSelected(selected);
1521 // TODO: decide if we should update properties file
1522 Cache.setProperty("SHOW_JAVA_CONSOLE",
1523 Boolean.valueOf(selected).toString());
1524 jconsole.setVisible(selected);
1527 void reorderAssociatedWindows(boolean minimize, boolean close)
1529 JInternalFrame[] frames = desktop.getAllFrames();
1530 if (frames == null || frames.length < 1)
1535 AlignmentViewport source = null, target = null;
1536 if (frames[0] instanceof AlignFrame)
1538 source = ((AlignFrame) frames[0]).getCurrentView();
1540 else if (frames[0] instanceof TreePanel)
1542 source = ((TreePanel) frames[0]).getViewPort();
1544 else if (frames[0] instanceof PCAPanel)
1546 source = ((PCAPanel) frames[0]).av;
1548 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1550 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1555 for (int i = 0; i < frames.length; i++)
1558 if (frames[i] == null)
1562 if (frames[i] instanceof AlignFrame)
1564 target = ((AlignFrame) frames[i]).getCurrentView();
1566 else if (frames[i] instanceof TreePanel)
1568 target = ((TreePanel) frames[i]).getViewPort();
1570 else if (frames[i] instanceof PCAPanel)
1572 target = ((PCAPanel) frames[i]).av;
1574 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1576 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1579 if (source == target)
1585 frames[i].setClosed(true);
1589 frames[i].setIcon(minimize);
1592 frames[i].toFront();
1596 } catch (java.beans.PropertyVetoException ex)
1611 protected void preferences_actionPerformed(ActionEvent e)
1623 public void saveState_actionPerformed(ActionEvent e)
1625 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1628 chooser.setFileView(new JalviewFileView());
1629 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1631 int value = chooser.showSaveDialog(this);
1633 if (value == JalviewFileChooser.APPROVE_OPTION)
1635 final Desktop me = this;
1636 final java.io.File choice = chooser.getSelectedFile();
1637 setProjectFile(choice);
1639 new Thread(new Runnable()
1644 // TODO: refactor to Jalview desktop session controller action.
1645 setProgressBar(MessageManager.formatMessage(
1646 "label.saving_jalview_project", new Object[]
1647 { choice.getName() }), choice.hashCode());
1648 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1649 choice.getParent());
1650 // TODO catch and handle errors for savestate
1651 // TODO prevent user from messing with the Desktop whilst we're saving
1654 new Jalview2XML().saveState(choice);
1655 } catch (OutOfMemoryError oom)
1658 "Whilst saving current state to " + choice.getName(),
1660 } catch (Exception ex)
1663 "Problems whilst trying to save to " + choice.getName(),
1665 JvOptionPane.showMessageDialog(me,
1666 MessageManager.formatMessage(
1667 "label.error_whilst_saving_current_state_to",
1669 { choice.getName() }),
1670 MessageManager.getString("label.couldnt_save_project"),
1671 JvOptionPane.WARNING_MESSAGE);
1673 setProgressBar(null, choice.hashCode());
1679 private void setProjectFile(File choice)
1681 this.projectFile = choice;
1684 public File getProjectFile()
1686 return this.projectFile;
1696 public void loadState_actionPerformed(ActionEvent e)
1698 JalviewFileChooser chooser = new JalviewFileChooser(
1699 Cache.getProperty("LAST_DIRECTORY"), new String[]
1702 { "Jalview Project", "Jalview Project (old)" },
1704 chooser.setFileView(new JalviewFileView());
1705 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1707 int value = chooser.showOpenDialog(this);
1709 if (value == JalviewFileChooser.APPROVE_OPTION)
1711 final File selectedFile = chooser.getSelectedFile();
1712 setProjectFile(selectedFile);
1713 final String choice = selectedFile.getAbsolutePath();
1714 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1715 new Thread(new Runnable()
1720 setProgressBar(MessageManager.formatMessage(
1721 "label.loading_jalview_project", new Object[]
1722 { choice }), choice.hashCode());
1725 new Jalview2XML().loadJalviewAlign(choice);
1726 } catch (OutOfMemoryError oom)
1728 new OOMWarning("Whilst loading project from " + choice, oom);
1729 } catch (Exception ex)
1732 "Problems whilst loading project from " + choice, ex);
1733 JvOptionPane.showMessageDialog(Desktop.desktop,
1734 MessageManager.formatMessage(
1735 "label.error_whilst_loading_project_from",
1738 MessageManager.getString("label.couldnt_load_project"),
1739 JvOptionPane.WARNING_MESSAGE);
1741 setProgressBar(null, choice.hashCode());
1748 public void inputSequence_actionPerformed(ActionEvent e)
1750 new SequenceFetcher(this);
1753 JPanel progressPanel;
1755 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1757 public void startLoading(final String fileName)
1759 if (fileLoadingCount == 0)
1761 fileLoadingPanels.add(addProgressPanel(MessageManager
1762 .formatMessage("label.loading_file", new Object[]
1768 private JPanel addProgressPanel(String string)
1770 if (progressPanel == null)
1772 progressPanel = new JPanel(new GridLayout(1, 1));
1773 totalProgressCount = 0;
1774 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1776 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1777 JProgressBar progressBar = new JProgressBar();
1778 progressBar.setIndeterminate(true);
1780 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1782 thisprogress.add(progressBar, BorderLayout.CENTER);
1783 progressPanel.add(thisprogress);
1784 ((GridLayout) progressPanel.getLayout()).setRows(
1785 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1786 ++totalProgressCount;
1787 instance.validate();
1788 return thisprogress;
1791 int totalProgressCount = 0;
1793 private void removeProgressPanel(JPanel progbar)
1795 if (progressPanel != null)
1797 synchronized (progressPanel)
1799 progressPanel.remove(progbar);
1800 GridLayout gl = (GridLayout) progressPanel.getLayout();
1801 gl.setRows(gl.getRows() - 1);
1802 if (--totalProgressCount < 1)
1804 this.getContentPane().remove(progressPanel);
1805 progressPanel = null;
1812 public void stopLoading()
1815 if (fileLoadingCount < 1)
1817 while (fileLoadingPanels.size() > 0)
1819 removeProgressPanel(fileLoadingPanels.remove(0));
1821 fileLoadingPanels.clear();
1822 fileLoadingCount = 0;
1827 public static int getViewCount(String alignmentId)
1829 AlignmentViewport[] aps = getViewports(alignmentId);
1830 return (aps == null) ? 0 : aps.length;
1835 * @param alignmentId
1836 * - if null, all sets are returned
1837 * @return all AlignmentPanels concerning the alignmentId sequence set
1839 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1841 if (Desktop.desktop == null)
1843 // no frames created and in headless mode
1844 // TODO: verify that frames are recoverable when in headless mode
1847 List<AlignmentPanel> aps = new ArrayList<>();
1848 AlignFrame[] frames = getAlignFrames();
1853 for (AlignFrame af : frames)
1855 for (AlignmentPanel ap : af.alignPanels)
1857 if (alignmentId == null
1858 || alignmentId.equals(ap.av.getSequenceSetId()))
1864 if (aps.size() == 0)
1868 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1873 * get all the viewports on an alignment.
1875 * @param sequenceSetId
1876 * unique alignment id (may be null - all viewports returned in that
1878 * @return all viewports on the alignment bound to sequenceSetId
1880 public static AlignmentViewport[] getViewports(String sequenceSetId)
1882 List<AlignmentViewport> viewp = new ArrayList<>();
1883 if (desktop != null)
1885 AlignFrame[] frames = Desktop.getAlignFrames();
1887 for (AlignFrame afr : frames)
1889 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1890 .equals(sequenceSetId))
1892 if (afr.alignPanels != null)
1894 for (AlignmentPanel ap : afr.alignPanels)
1896 if (sequenceSetId == null
1897 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1905 viewp.add(afr.getViewport());
1909 if (viewp.size() > 0)
1911 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1918 * Explode the views in the given frame into separate AlignFrame
1922 public static void explodeViews(AlignFrame af)
1924 int size = af.alignPanels.size();
1930 for (int i = 0; i < size; i++)
1932 AlignmentPanel ap = af.alignPanels.get(i);
1933 AlignFrame newaf = new AlignFrame(ap);
1936 * Restore the view's last exploded frame geometry if known. Multiple
1937 * views from one exploded frame share and restore the same (frame)
1938 * position and size.
1940 Rectangle geometry = ap.av.getExplodedGeometry();
1941 if (geometry != null)
1943 newaf.setBounds(geometry);
1946 ap.av.setGatherViewsHere(false);
1948 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1949 AlignFrame.DEFAULT_HEIGHT);
1952 af.alignPanels.clear();
1953 af.closeMenuItem_actionPerformed(true);
1958 * Gather expanded views (separate AlignFrame's) with the same sequence set
1959 * identifier back in to this frame as additional views, and close the
1960 * expanded views. Note the expanded frames may themselves have multiple
1961 * views. We take the lot.
1965 public void gatherViews(AlignFrame source)
1967 source.viewport.setGatherViewsHere(true);
1968 source.viewport.setExplodedGeometry(source.getBounds());
1969 JInternalFrame[] frames = desktop.getAllFrames();
1970 String viewId = source.viewport.getSequenceSetId();
1972 for (int t = 0; t < frames.length; t++)
1974 if (frames[t] instanceof AlignFrame && frames[t] != source)
1976 AlignFrame af = (AlignFrame) frames[t];
1977 boolean gatherThis = false;
1978 for (int a = 0; a < af.alignPanels.size(); a++)
1980 AlignmentPanel ap = af.alignPanels.get(a);
1981 if (viewId.equals(ap.av.getSequenceSetId()))
1984 ap.av.setGatherViewsHere(false);
1985 ap.av.setExplodedGeometry(af.getBounds());
1986 source.addAlignmentPanel(ap, false);
1992 af.alignPanels.clear();
1993 af.closeMenuItem_actionPerformed(true);
2000 jalview.gui.VamsasApplication v_client = null;
2003 public void vamsasImport_actionPerformed(ActionEvent e)
2005 if (v_client == null)
2007 // Load and try to start a session.
2008 JalviewFileChooser chooser = new JalviewFileChooser(
2009 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2011 chooser.setFileView(new JalviewFileView());
2012 chooser.setDialogTitle(
2013 MessageManager.getString("label.open_saved_vamsas_session"));
2014 chooser.setToolTipText(MessageManager.getString(
2015 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2017 int value = chooser.showOpenDialog(this);
2019 if (value == JalviewFileChooser.APPROVE_OPTION)
2021 String fle = chooser.getSelectedFile().toString();
2022 if (!vamsasImport(chooser.getSelectedFile()))
2024 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2025 MessageManager.formatMessage(
2026 "label.couldnt_import_as_vamsas_session",
2030 .getString("label.vamsas_document_import_failed"),
2031 JvOptionPane.ERROR_MESSAGE);
2037 jalview.bin.Cache.log.error(
2038 "Implementation error - load session from a running session is not supported.");
2043 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2046 * @return true if import was a success and a session was started.
2048 public boolean vamsasImport(URL url)
2050 // TODO: create progress bar
2051 if (v_client != null)
2054 jalview.bin.Cache.log.error(
2055 "Implementation error - load session from a running session is not supported.");
2061 // copy the URL content to a temporary local file
2062 // TODO: be a bit cleverer here with nio (?!)
2063 File file = File.createTempFile("vdocfromurl", ".vdj");
2064 FileOutputStream fos = new FileOutputStream(file);
2065 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2066 byte[] buffer = new byte[2048];
2068 while ((ln = bis.read(buffer)) > -1)
2070 fos.write(buffer, 0, ln);
2074 v_client = new jalview.gui.VamsasApplication(this, file,
2075 url.toExternalForm());
2076 } catch (Exception ex)
2078 jalview.bin.Cache.log.error(
2079 "Failed to create new vamsas session from contents of URL "
2084 setupVamsasConnectedGui();
2085 v_client.initial_update(); // TODO: thread ?
2086 return v_client.inSession();
2090 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2093 * @return true if import was a success and a session was started.
2095 public boolean vamsasImport(File file)
2097 if (v_client != null)
2100 jalview.bin.Cache.log.error(
2101 "Implementation error - load session from a running session is not supported.");
2105 setProgressBar(MessageManager.formatMessage(
2106 "status.importing_vamsas_session_from", new Object[]
2107 { file.getName() }), file.hashCode());
2110 v_client = new jalview.gui.VamsasApplication(this, file, null);
2111 } catch (Exception ex)
2113 setProgressBar(MessageManager.formatMessage(
2114 "status.importing_vamsas_session_from", new Object[]
2115 { file.getName() }), file.hashCode());
2116 jalview.bin.Cache.log.error(
2117 "New vamsas session from existing session file failed:", ex);
2120 setupVamsasConnectedGui();
2121 v_client.initial_update(); // TODO: thread ?
2122 setProgressBar(MessageManager.formatMessage(
2123 "status.importing_vamsas_session_from", new Object[]
2124 { file.getName() }), file.hashCode());
2125 return v_client.inSession();
2128 public boolean joinVamsasSession(String mysesid)
2130 if (v_client != null)
2132 throw new Error(MessageManager
2133 .getString("error.try_join_vamsas_session_another"));
2135 if (mysesid == null)
2138 MessageManager.getString("error.invalid_vamsas_session_id"));
2140 v_client = new VamsasApplication(this, mysesid);
2141 setupVamsasConnectedGui();
2142 v_client.initial_update();
2143 return (v_client.inSession());
2147 public void vamsasStart_actionPerformed(ActionEvent e)
2149 if (v_client == null)
2152 // we just start a default session for moment.
2154 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2155 * getProperty("LAST_DIRECTORY"));
2157 * chooser.setFileView(new JalviewFileView());
2158 * chooser.setDialogTitle("Load Vamsas file");
2159 * chooser.setToolTipText("Import");
2161 * int value = chooser.showOpenDialog(this);
2163 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2164 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2166 v_client = new VamsasApplication(this);
2167 setupVamsasConnectedGui();
2168 v_client.initial_update(); // TODO: thread ?
2172 // store current data in session.
2173 v_client.push_update(); // TODO: thread
2177 protected void setupVamsasConnectedGui()
2179 vamsasStart.setText(MessageManager.getString("label.session_update"));
2180 vamsasSave.setVisible(true);
2181 vamsasStop.setVisible(true);
2182 vamsasImport.setVisible(false); // Document import to existing session is
2183 // not possible for vamsas-client-1.0.
2186 protected void setupVamsasDisconnectedGui()
2188 vamsasSave.setVisible(false);
2189 vamsasStop.setVisible(false);
2190 vamsasImport.setVisible(true);
2192 .setText(MessageManager.getString("label.new_vamsas_session"));
2196 public void vamsasStop_actionPerformed(ActionEvent e)
2198 if (v_client != null)
2200 v_client.end_session();
2202 setupVamsasDisconnectedGui();
2206 protected void buildVamsasStMenu()
2208 if (v_client == null)
2210 String[] sess = null;
2213 sess = VamsasApplication.getSessionList();
2214 } catch (Exception e)
2216 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2222 jalview.bin.Cache.log.debug(
2223 "Got current sessions list: " + sess.length + " entries.");
2224 VamsasStMenu.removeAll();
2225 for (int i = 0; i < sess.length; i++)
2227 JMenuItem sessit = new JMenuItem();
2228 sessit.setText(sess[i]);
2229 sessit.setToolTipText(MessageManager
2230 .formatMessage("label.connect_to_session", new Object[]
2232 final Desktop dsktp = this;
2233 final String mysesid = sess[i];
2234 sessit.addActionListener(new ActionListener()
2238 public void actionPerformed(ActionEvent e)
2240 if (dsktp.v_client == null)
2242 Thread rthr = new Thread(new Runnable()
2248 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2249 dsktp.setupVamsasConnectedGui();
2250 dsktp.v_client.initial_update();
2258 VamsasStMenu.add(sessit);
2260 // don't show an empty menu.
2261 VamsasStMenu.setVisible(sess.length > 0);
2266 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2267 VamsasStMenu.removeAll();
2268 VamsasStMenu.setVisible(false);
2273 // Not interested in the content. Just hide ourselves.
2274 VamsasStMenu.setVisible(false);
2279 public void vamsasSave_actionPerformed(ActionEvent e)
2281 if (v_client != null)
2283 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2284 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2287 chooser.setFileView(new JalviewFileView());
2288 chooser.setDialogTitle(MessageManager
2289 .getString("label.save_vamsas_document_archive"));
2291 int value = chooser.showSaveDialog(this);
2293 if (value == JalviewFileChooser.APPROVE_OPTION)
2295 java.io.File choice = chooser.getSelectedFile();
2296 JPanel progpanel = addProgressPanel(MessageManager
2297 .formatMessage("label.saving_vamsas_doc", new Object[]
2298 { choice.getName() }));
2299 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2300 String warnmsg = null;
2301 String warnttl = null;
2304 v_client.vclient.storeDocument(choice);
2307 warnttl = "Serious Problem saving Vamsas Document";
2308 warnmsg = ex.toString();
2309 jalview.bin.Cache.log
2310 .error("Error Whilst saving document to " + choice, ex);
2312 } catch (Exception ex)
2314 warnttl = "Problem saving Vamsas Document.";
2315 warnmsg = ex.toString();
2316 jalview.bin.Cache.log.warn(
2317 "Exception Whilst saving document to " + choice, ex);
2320 removeProgressPanel(progpanel);
2321 if (warnmsg != null)
2323 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2325 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2331 JPanel vamUpdate = null;
2334 * hide vamsas user gui bits when a vamsas document event is being handled.
2337 * true to hide gui, false to reveal gui
2339 public void setVamsasUpdate(boolean b)
2341 Cache.log.debug("Setting gui for Vamsas update "
2342 + (b ? "in progress" : "finished"));
2344 if (vamUpdate != null)
2346 this.removeProgressPanel(vamUpdate);
2350 vamUpdate = this.addProgressPanel(
2351 MessageManager.getString("label.updating_vamsas_session"));
2353 vamsasStart.setVisible(!b);
2354 vamsasStop.setVisible(!b);
2355 vamsasSave.setVisible(!b);
2358 public JInternalFrame[] getAllFrames()
2360 return desktop.getAllFrames();
2364 * Checks the given url to see if it gives a response indicating that the user
2365 * should be informed of a new questionnaire.
2369 public void checkForQuestionnaire(String url)
2371 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2372 // javax.swing.SwingUtilities.invokeLater(jvq);
2373 new Thread(jvq).start();
2376 public void checkURLLinks()
2378 // Thread off the URL link checker
2379 addDialogThread(new Runnable()
2384 if (Cache.getDefault("CHECKURLLINKS", true))
2386 // check what the actual links are - if it's just the default don't
2387 // bother with the warning
2388 List<String> links = Preferences.sequenceUrlLinks
2391 // only need to check links if there is one with a
2392 // SEQUENCE_ID which is not the default EMBL_EBI link
2393 ListIterator<String> li = links.listIterator();
2394 boolean check = false;
2395 List<JLabel> urls = new ArrayList<>();
2396 while (li.hasNext())
2398 String link = li.next();
2399 if (link.contains(SEQUENCE_ID)
2400 && !UrlConstants.isDefaultString(link))
2403 int barPos = link.indexOf("|");
2404 String urlMsg = barPos == -1 ? link
2405 : link.substring(0, barPos) + ": "
2406 + link.substring(barPos + 1);
2407 urls.add(new JLabel(urlMsg));
2415 // ask user to check in case URL links use old style tokens
2416 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2417 JPanel msgPanel = new JPanel();
2418 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2419 msgPanel.add(Box.createVerticalGlue());
2420 JLabel msg = new JLabel(MessageManager
2421 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2422 JLabel msg2 = new JLabel(MessageManager
2423 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2425 for (JLabel url : urls)
2431 final JCheckBox jcb = new JCheckBox(
2432 MessageManager.getString("label.do_not_display_again"));
2433 jcb.addActionListener(new ActionListener()
2436 public void actionPerformed(ActionEvent e)
2438 // update Cache settings for "don't show this again"
2439 boolean showWarningAgain = !jcb.isSelected();
2440 Cache.setProperty("CHECKURLLINKS",
2441 Boolean.valueOf(showWarningAgain).toString());
2446 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2448 .getString("label.SEQUENCE_ID_no_longer_used"),
2449 JvOptionPane.WARNING_MESSAGE);
2456 * Proxy class for JDesktopPane which optionally displays the current memory
2457 * usage and highlights the desktop area with a red bar if free memory runs
2462 public class MyDesktopPane extends JDesktopPane implements Runnable
2465 private static final float ONE_MB = 1048576f;
2467 boolean showMemoryUsage = false;
2471 java.text.NumberFormat df;
2473 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2476 public MyDesktopPane(boolean showMemoryUsage)
2478 showMemoryUsage(showMemoryUsage);
2481 public void showMemoryUsage(boolean showMemory)
2483 this.showMemoryUsage = showMemory;
2486 Thread worker = new Thread(this);
2492 public boolean isShowMemoryUsage()
2494 return showMemoryUsage;
2500 df = java.text.NumberFormat.getNumberInstance();
2501 df.setMaximumFractionDigits(2);
2502 runtime = Runtime.getRuntime();
2504 while (showMemoryUsage)
2508 maxMemory = runtime.maxMemory() / ONE_MB;
2509 allocatedMemory = runtime.totalMemory() / ONE_MB;
2510 freeMemory = runtime.freeMemory() / ONE_MB;
2511 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2513 percentUsage = (totalFreeMemory / maxMemory) * 100;
2515 // if (percentUsage < 20)
2517 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2519 // instance.set.setBorder(border1);
2522 // sleep after showing usage
2524 } catch (Exception ex)
2526 ex.printStackTrace();
2532 public void paintComponent(Graphics g)
2534 if (showMemoryUsage && g != null && df != null)
2536 if (percentUsage < 20)
2538 g.setColor(Color.red);
2540 FontMetrics fm = g.getFontMetrics();
2543 g.drawString(MessageManager.formatMessage("label.memory_stats",
2545 { df.format(totalFreeMemory), df.format(maxMemory),
2546 df.format(percentUsage) }),
2547 10, getHeight() - fm.getHeight());
2555 * Accessor method to quickly get all the AlignmentFrames loaded.
2557 * @return an array of AlignFrame, or null if none found
2559 public static AlignFrame[] getAlignFrames()
2561 if (Jalview.isHeadlessMode())
2563 // Desktop.desktop is null in headless mode
2564 return new AlignFrame[] { Jalview.currentAlignFrame };
2567 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2573 List<AlignFrame> avp = new ArrayList<>();
2575 for (int i = frames.length - 1; i > -1; i--)
2577 if (frames[i] instanceof AlignFrame)
2579 avp.add((AlignFrame) frames[i]);
2581 else if (frames[i] instanceof SplitFrame)
2584 * Also check for a split frame containing an AlignFrame
2586 GSplitFrame sf = (GSplitFrame) frames[i];
2587 if (sf.getTopFrame() instanceof AlignFrame)
2589 avp.add((AlignFrame) sf.getTopFrame());
2591 if (sf.getBottomFrame() instanceof AlignFrame)
2593 avp.add((AlignFrame) sf.getBottomFrame());
2597 if (avp.size() == 0)
2601 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2606 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2610 public GStructureViewer[] getJmols()
2612 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2618 List<GStructureViewer> avp = new ArrayList<>();
2620 for (int i = frames.length - 1; i > -1; i--)
2622 if (frames[i] instanceof AppJmol)
2624 GStructureViewer af = (GStructureViewer) frames[i];
2628 if (avp.size() == 0)
2632 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2637 * Add Groovy Support to Jalview
2640 public void groovyShell_actionPerformed()
2644 openGroovyConsole();
2645 } catch (Exception ex)
2647 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2648 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2650 MessageManager.getString("label.couldnt_create_groovy_shell"),
2651 MessageManager.getString("label.groovy_support_failed"),
2652 JvOptionPane.ERROR_MESSAGE);
2657 * Open the Groovy console
2659 void openGroovyConsole()
2661 if (groovyConsole == null)
2663 groovyConsole = new groovy.ui.Console();
2664 groovyConsole.setVariable("Jalview", this);
2665 groovyConsole.run();
2668 * We allow only one console at a time, so that AlignFrame menu option
2669 * 'Calculate | Run Groovy script' is unambiguous.
2670 * Disable 'Groovy Console', and enable 'Run script', when the console is
2671 * opened, and the reverse when it is closed
2673 Window window = (Window) groovyConsole.getFrame();
2674 window.addWindowListener(new WindowAdapter()
2677 public void windowClosed(WindowEvent e)
2680 * rebind CMD-Q from Groovy Console to Jalview Quit
2683 enableExecuteGroovy(false);
2689 * show Groovy console window (after close and reopen)
2691 ((Window) groovyConsole.getFrame()).setVisible(true);
2694 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2695 * and disable opening a second console
2697 enableExecuteGroovy(true);
2701 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2702 * binding when opened
2704 protected void addQuitHandler()
2706 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2707 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2708 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2710 getRootPane().getActionMap().put("Quit", new AbstractAction()
2713 public void actionPerformed(ActionEvent e)
2721 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2724 * true if Groovy console is open
2726 public void enableExecuteGroovy(boolean enabled)
2729 * disable opening a second Groovy console
2730 * (or re-enable when the console is closed)
2732 groovyShell.setEnabled(!enabled);
2734 AlignFrame[] alignFrames = getAlignFrames();
2735 if (alignFrames != null)
2737 for (AlignFrame af : alignFrames)
2739 af.setGroovyEnabled(enabled);
2745 * Progress bars managed by the IProgressIndicator method.
2747 private Hashtable<Long, JPanel> progressBars;
2749 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2754 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2757 public void setProgressBar(String message, long id)
2759 if (progressBars == null)
2761 progressBars = new Hashtable<>();
2762 progressBarHandlers = new Hashtable<>();
2765 if (progressBars.get(new Long(id)) != null)
2767 JPanel panel = progressBars.remove(new Long(id));
2768 if (progressBarHandlers.contains(new Long(id)))
2770 progressBarHandlers.remove(new Long(id));
2772 removeProgressPanel(panel);
2776 progressBars.put(new Long(id), addProgressPanel(message));
2783 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2784 * jalview.gui.IProgressIndicatorHandler)
2787 public void registerHandler(final long id,
2788 final IProgressIndicatorHandler handler)
2790 if (progressBarHandlers == null
2791 || !progressBars.containsKey(new Long(id)))
2793 throw new Error(MessageManager.getString(
2794 "error.call_setprogressbar_before_registering_handler"));
2796 progressBarHandlers.put(new Long(id), handler);
2797 final JPanel progressPanel = progressBars.get(new Long(id));
2798 if (handler.canCancel())
2800 JButton cancel = new JButton(
2801 MessageManager.getString("action.cancel"));
2802 final IProgressIndicator us = this;
2803 cancel.addActionListener(new ActionListener()
2807 public void actionPerformed(ActionEvent e)
2809 handler.cancelActivity(id);
2810 us.setProgressBar(MessageManager
2811 .formatMessage("label.cancelled_params", new Object[]
2812 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2816 progressPanel.add(cancel, BorderLayout.EAST);
2822 * @return true if any progress bars are still active
2825 public boolean operationInProgress()
2827 if (progressBars != null && progressBars.size() > 0)
2835 * This will return the first AlignFrame holding the given viewport instance.
2836 * It will break if there are more than one AlignFrames viewing a particular
2840 * @return alignFrame for viewport
2842 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2844 if (desktop != null)
2846 AlignmentPanel[] aps = getAlignmentPanels(
2847 viewport.getSequenceSetId());
2848 for (int panel = 0; aps != null && panel < aps.length; panel++)
2850 if (aps[panel] != null && aps[panel].av == viewport)
2852 return aps[panel].alignFrame;
2859 public VamsasApplication getVamsasApplication()
2866 * flag set if jalview GUI is being operated programmatically
2868 private boolean inBatchMode = false;
2871 * check if jalview GUI is being operated programmatically
2873 * @return inBatchMode
2875 public boolean isInBatchMode()
2881 * set flag if jalview GUI is being operated programmatically
2883 * @param inBatchMode
2885 public void setInBatchMode(boolean inBatchMode)
2887 this.inBatchMode = inBatchMode;
2890 public void startServiceDiscovery()
2892 startServiceDiscovery(false);
2895 public void startServiceDiscovery(boolean blocking)
2897 boolean alive = true;
2898 Thread t0 = null, t1 = null, t2 = null;
2899 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2902 // todo: changesupport handlers need to be transferred
2903 if (discoverer == null)
2905 discoverer = new jalview.ws.jws1.Discoverer();
2906 // register PCS handler for desktop.
2907 discoverer.addPropertyChangeListener(changeSupport);
2909 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2910 // until we phase out completely
2911 (t0 = new Thread(discoverer)).start();
2914 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2916 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2917 .startDiscoverer(changeSupport);
2921 // TODO: do rest service discovery
2930 } catch (Exception e)
2933 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2934 || (t3 != null && t3.isAlive())
2935 || (t0 != null && t0.isAlive());
2941 * called to check if the service discovery process completed successfully.
2945 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2947 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2949 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2950 .getErrorMessages();
2953 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
2955 if (serviceChangedDialog == null)
2957 // only run if we aren't already displaying one of these.
2958 addDialogThread(serviceChangedDialog = new Runnable()
2965 * JalviewDialog jd =new JalviewDialog() {
2967 * @Override protected void cancelPressed() { // TODO
2968 * Auto-generated method stub
2970 * }@Override protected void okPressed() { // TODO
2971 * Auto-generated method stub
2973 * }@Override protected void raiseClosed() { // TODO
2974 * Auto-generated method stub
2976 * } }; jd.initDialogFrame(new
2977 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
2978 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
2979 * + " or mis-configured HTTP proxy settings.<br/>" +
2980 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
2982 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
2983 * ), true, true, "Web Service Configuration Problem", 450,
2986 * jd.waitForInput();
2988 JvOptionPane.showConfirmDialog(Desktop.desktop,
2989 new JLabel("<html><table width=\"450\"><tr><td>"
2990 + ermsg + "</td></tr></table>"
2991 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
2992 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
2993 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
2994 + " Tools->Preferences dialog box to change them.</p></html>"),
2995 "Web Service Configuration Problem",
2996 JvOptionPane.DEFAULT_OPTION,
2997 JvOptionPane.ERROR_MESSAGE);
2998 serviceChangedDialog = null;
3007 "Errors reported by JABA discovery service. Check web services preferences.\n"
3014 private Runnable serviceChangedDialog = null;
3017 * start a thread to open a URL in the configured browser. Pops up a warning
3018 * dialog to the user if there is an exception when calling out to the browser
3023 public static void showUrl(final String url)
3025 showUrl(url, Desktop.instance);
3029 * Like showUrl but allows progress handler to be specified
3033 * (null) or object implementing IProgressIndicator
3035 public static void showUrl(final String url,
3036 final IProgressIndicator progress)
3038 new Thread(new Runnable()
3045 if (progress != null)
3047 progress.setProgressBar(MessageManager
3048 .formatMessage("status.opening_params", new Object[]
3049 { url }), this.hashCode());
3051 jalview.util.BrowserLauncher.openURL(url);
3052 } catch (Exception ex)
3054 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3056 .getString("label.web_browser_not_found_unix"),
3057 MessageManager.getString("label.web_browser_not_found"),
3058 JvOptionPane.WARNING_MESSAGE);
3060 ex.printStackTrace();
3062 if (progress != null)
3064 progress.setProgressBar(null, this.hashCode());
3070 public static WsParamSetManager wsparamManager = null;
3072 public static ParamManager getUserParameterStore()
3074 if (wsparamManager == null)
3076 wsparamManager = new WsParamSetManager();
3078 return wsparamManager;
3082 * static hyperlink handler proxy method for use by Jalview's internal windows
3086 public static void hyperlinkUpdate(HyperlinkEvent e)
3088 if (e.getEventType() == EventType.ACTIVATED)
3093 url = e.getURL().toString();
3094 Desktop.showUrl(url);
3095 } catch (Exception x)
3099 if (Cache.log != null)
3101 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3106 "Couldn't handle string " + url + " as a URL.");
3109 // ignore any exceptions due to dud links.
3116 * single thread that handles display of dialogs to user.
3118 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3121 * flag indicating if dialogExecutor should try to acquire a permit
3123 private volatile boolean dialogPause = true;
3128 private java.util.concurrent.Semaphore block = new Semaphore(0);
3130 private static groovy.ui.Console groovyConsole;
3133 * add another dialog thread to the queue
3137 public void addDialogThread(final Runnable prompter)
3139 dialogExecutor.submit(new Runnable()
3149 } catch (InterruptedException x)
3154 if (instance == null)
3160 SwingUtilities.invokeAndWait(prompter);
3161 } catch (Exception q)
3163 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3169 public void startDialogQueue()
3171 // set the flag so we don't pause waiting for another permit and semaphore
3172 // the current task to begin
3173 dialogPause = false;
3178 protected void snapShotWindow_actionPerformed(ActionEvent e)
3182 ImageMaker im = new jalview.util.ImageMaker(
3183 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3184 getHeight(), of = new File("Jalview_snapshot"
3185 + System.currentTimeMillis() + ".eps"),
3186 "View of desktop", null, 0, false);
3189 paintAll(im.getGraphics());
3191 } catch (Exception q)
3193 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3197 Cache.log.info("Successfully written snapshot to file "
3198 + of.getAbsolutePath());
3202 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3203 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3204 * and location last time the view was expanded (if any). However it does not
3205 * remember the split pane divider location - this is set to match the
3206 * 'exploding' frame.
3210 public void explodeViews(SplitFrame sf)
3212 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3213 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3214 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3216 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3218 int viewCount = topPanels.size();
3225 * Processing in reverse order works, forwards order leaves the first panels
3226 * not visible. I don't know why!
3228 for (int i = viewCount - 1; i >= 0; i--)
3231 * Make new top and bottom frames. These take over the respective
3232 * AlignmentPanel objects, including their AlignmentViewports, so the
3233 * cdna/protein relationships between the viewports is carried over to the
3236 * explodedGeometry holds the (x, y) position of the previously exploded
3237 * SplitFrame, and the (width, height) of the AlignFrame component
3239 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3240 AlignFrame newTopFrame = new AlignFrame(topPanel);
3241 newTopFrame.setSize(oldTopFrame.getSize());
3242 newTopFrame.setVisible(true);
3243 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3244 .getExplodedGeometry();
3245 if (geometry != null)
3247 newTopFrame.setSize(geometry.getSize());
3250 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3251 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3252 newBottomFrame.setSize(oldBottomFrame.getSize());
3253 newBottomFrame.setVisible(true);
3254 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3255 .getExplodedGeometry();
3256 if (geometry != null)
3258 newBottomFrame.setSize(geometry.getSize());
3261 topPanel.av.setGatherViewsHere(false);
3262 bottomPanel.av.setGatherViewsHere(false);
3263 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3265 if (geometry != null)
3267 splitFrame.setLocation(geometry.getLocation());
3269 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3273 * Clear references to the panels (now relocated in the new SplitFrames)
3274 * before closing the old SplitFrame.
3277 bottomPanels.clear();
3282 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3283 * back into the given SplitFrame as additional views. Note that the gathered
3284 * frames may themselves have multiple views.
3288 public void gatherViews(GSplitFrame source)
3291 * special handling of explodedGeometry for a view within a SplitFrame: - it
3292 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3293 * height) of the AlignFrame component
3295 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3296 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3297 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3298 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3299 myBottomFrame.viewport
3300 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3301 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3302 myTopFrame.viewport.setGatherViewsHere(true);
3303 myBottomFrame.viewport.setGatherViewsHere(true);
3304 String topViewId = myTopFrame.viewport.getSequenceSetId();
3305 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3307 JInternalFrame[] frames = desktop.getAllFrames();
3308 for (JInternalFrame frame : frames)
3310 if (frame instanceof SplitFrame && frame != source)
3312 SplitFrame sf = (SplitFrame) frame;
3313 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3314 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3315 boolean gatherThis = false;
3316 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3318 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3319 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3320 if (topViewId.equals(topPanel.av.getSequenceSetId())
3321 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3324 topPanel.av.setGatherViewsHere(false);
3325 bottomPanel.av.setGatherViewsHere(false);
3326 topPanel.av.setExplodedGeometry(
3327 new Rectangle(sf.getLocation(), topFrame.getSize()));
3328 bottomPanel.av.setExplodedGeometry(
3329 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3330 myTopFrame.addAlignmentPanel(topPanel, false);
3331 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3337 topFrame.getAlignPanels().clear();
3338 bottomFrame.getAlignPanels().clear();
3345 * The dust settles...give focus to the tab we did this from.
3347 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3350 public static groovy.ui.Console getGroovyConsole()
3352 return groovyConsole;
3356 * handles the payload of a drag and drop event.
3358 * TODO refactor to desktop utilities class
3361 * - Data source strings extracted from the drop event
3363 * - protocol for each data source extracted from the drop event
3367 * - the payload from the drop event
3370 public static void transferFromDropTarget(List<String> files,
3371 List<DataSourceType> protocols, DropTargetDropEvent evt,
3372 Transferable t) throws Exception
3375 DataFlavor uriListFlavor = new DataFlavor(
3376 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3379 urlFlavour = new DataFlavor(
3380 "application/x-java-url; class=java.net.URL");
3381 } catch (ClassNotFoundException cfe)
3383 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3386 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3391 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3392 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3393 // means url may be null.
3396 protocols.add(DataSourceType.URL);
3397 files.add(url.toString());
3398 Cache.log.debug("Drop handled as URL dataflavor "
3399 + files.get(files.size() - 1));
3404 if (Platform.isAMac())
3407 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3411 } catch (Throwable ex)
3413 Cache.log.debug("URL drop handler failed.", ex);
3416 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3418 // Works on Windows and MacOSX
3419 Cache.log.debug("Drop handled as javaFileListFlavor");
3420 for (Object file : (List) t
3421 .getTransferData(DataFlavor.javaFileListFlavor))
3423 files.add(((File) file).toString());
3424 protocols.add(DataSourceType.FILE);
3429 // Unix like behaviour
3430 boolean added = false;
3432 if (t.isDataFlavorSupported(uriListFlavor))
3434 Cache.log.debug("Drop handled as uriListFlavor");
3435 // This is used by Unix drag system
3436 data = (String) t.getTransferData(uriListFlavor);
3440 // fallback to text: workaround - on OSX where there's a JVM bug
3441 Cache.log.debug("standard URIListFlavor failed. Trying text");
3442 // try text fallback
3443 DataFlavor textDf = new DataFlavor(
3444 "text/plain;class=java.lang.String");
3445 if (t.isDataFlavorSupported(textDf))
3447 data = (String) t.getTransferData(textDf);
3450 Cache.log.debug("Plain text drop content returned "
3451 + (data == null ? "Null - failed" : data));
3456 while (protocols.size() < files.size())
3458 Cache.log.debug("Adding missing FILE protocol for "
3459 + files.get(protocols.size()));
3460 protocols.add(DataSourceType.FILE);
3462 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3463 data, "\r\n"); st.hasMoreTokens();)
3466 String s = st.nextToken();
3467 if (s.startsWith("#"))
3469 // the line is a comment (as per the RFC 2483)
3472 java.net.URI uri = new java.net.URI(s);
3473 if (uri.getScheme().toLowerCase().startsWith("http"))
3475 protocols.add(DataSourceType.URL);
3476 files.add(uri.toString());
3480 // otherwise preserve old behaviour: catch all for file objects
3481 java.io.File file = new java.io.File(uri);
3482 protocols.add(DataSourceType.FILE);
3483 files.add(file.toString());
3488 if (Cache.log.isDebugEnabled())
3490 if (data == null || !added)
3493 if (t.getTransferDataFlavors() != null
3494 && t.getTransferDataFlavors().length > 0)
3497 "Couldn't resolve drop data. Here are the supported flavors:");
3498 for (DataFlavor fl : t.getTransferDataFlavors())
3501 "Supported transfer dataflavor: " + fl.toString());
3502 Object df = t.getTransferData(fl);
3505 Cache.log.debug("Retrieves: " + df);
3509 Cache.log.debug("Retrieved nothing");
3515 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3521 if (Platform.isWindows())
3524 Cache.log.debug("Scanning dropped content for Windows Link Files");
3526 // resolve any .lnk files in the file drop
3527 for (int f = 0; f < files.size(); f++)
3529 String source = files.get(f).toLowerCase();
3530 if (protocols.get(f).equals(DataSourceType.FILE)
3531 && (source.endsWith(".lnk") || source.endsWith(".url")
3532 || source.endsWith(".site")))
3535 File lf = new File(files.get(f));
3536 // process link file to get a URL
3537 Cache.log.debug("Found potential link file: " + lf);
3538 WindowsShortcut wscfile = new WindowsShortcut(lf);
3539 String fullname = wscfile.getRealFilename();
3540 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3541 files.set(f, fullname);
3542 Cache.log.debug("Parsed real filename " + fullname
3543 + " to extract protocol: " + protocols.get(f));
3545 catch (Exception ex)
3547 Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
3555 * Sets the Preferences property for experimental features to True or False
3556 * depending on the state of the controlling menu item
3559 protected void showExperimental_actionPerformed(boolean selected)
3561 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3565 * Answers a (possibly empty) list of any structure viewer frames (currently
3566 * for either Jmol or Chimera) which are currently open. This may optionally
3567 * be restricted to viewers of a specified class, or viewers linked to a
3568 * specified alignment panel.
3571 * if not null, only return viewers linked to this panel
3572 * @param structureViewerClass
3573 * if not null, only return viewers of this class
3576 public List<StructureViewerBase> getStructureViewers(
3577 AlignmentPanel apanel,
3578 Class<? extends StructureViewerBase> structureViewerClass)
3580 List<StructureViewerBase> result = new ArrayList<>();
3581 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3583 for (JInternalFrame frame : frames)
3585 if (frame instanceof StructureViewerBase)
3587 if (structureViewerClass == null
3588 || structureViewerClass.isInstance(frame))
3591 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3593 result.add((StructureViewerBase) frame);