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.BackupFiles;
30 import jalview.io.DataSourceType;
31 import jalview.io.FileFormat;
32 import jalview.io.FileFormatException;
33 import jalview.io.FileFormatI;
34 import jalview.io.FileFormats;
35 import jalview.io.FileLoader;
36 import jalview.io.FormatAdapter;
37 import jalview.io.IdentifyFile;
38 import jalview.io.JalviewFileChooser;
39 import jalview.io.JalviewFileView;
40 import jalview.jbgui.GSplitFrame;
41 import jalview.jbgui.GStructureViewer;
42 import jalview.project.Jalview2XML;
43 import jalview.structure.StructureSelectionManager;
44 import jalview.urls.IdOrgSettings;
45 import jalview.util.ImageMaker;
46 import jalview.util.MessageManager;
47 import jalview.util.Platform;
48 import jalview.util.UrlConstants;
49 import jalview.viewmodel.AlignmentViewport;
50 import jalview.ws.params.ParamManager;
51 import jalview.ws.utils.UrlDownloadClient;
53 import java.awt.BorderLayout;
54 import java.awt.Color;
55 import java.awt.Dimension;
56 import java.awt.FontMetrics;
57 import java.awt.Graphics;
58 import java.awt.GridLayout;
59 import java.awt.Point;
60 import java.awt.Rectangle;
61 import java.awt.Toolkit;
62 import java.awt.Window;
63 import java.awt.datatransfer.Clipboard;
64 import java.awt.datatransfer.ClipboardOwner;
65 import java.awt.datatransfer.DataFlavor;
66 import java.awt.datatransfer.Transferable;
67 import java.awt.dnd.DnDConstants;
68 import java.awt.dnd.DropTargetDragEvent;
69 import java.awt.dnd.DropTargetDropEvent;
70 import java.awt.dnd.DropTargetEvent;
71 import java.awt.dnd.DropTargetListener;
72 import java.awt.event.ActionEvent;
73 import java.awt.event.ActionListener;
74 import java.awt.event.InputEvent;
75 import java.awt.event.KeyEvent;
76 import java.awt.event.MouseAdapter;
77 import java.awt.event.MouseEvent;
78 import java.awt.event.WindowAdapter;
79 import java.awt.event.WindowEvent;
80 import java.beans.PropertyChangeEvent;
81 import java.beans.PropertyChangeListener;
82 import java.io.BufferedInputStream;
84 import java.io.FileOutputStream;
85 import java.io.IOException;
87 import java.util.ArrayList;
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.JFrame;
111 import javax.swing.JInternalFrame;
112 import javax.swing.JLabel;
113 import javax.swing.JMenuItem;
114 import javax.swing.JPanel;
115 import javax.swing.JPopupMenu;
116 import javax.swing.JProgressBar;
117 import javax.swing.KeyStroke;
118 import javax.swing.SwingUtilities;
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;
133 * @version $Revision: 1.155 $
135 public class Desktop extends jalview.jbgui.GDesktop
136 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
137 jalview.api.StructureSelectionManagerProvider
139 private static int DEFAULT_MIN_WIDTH = 300;
141 private static int DEFAULT_MIN_HEIGHT = 250;
143 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
145 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
147 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
149 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
152 * news reader - null if it was never started.
154 private BlogReader jvnews = null;
156 private File projectFile;
160 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
162 public void addJalviewPropertyChangeListener(
163 PropertyChangeListener listener)
165 changeSupport.addJalviewPropertyChangeListener(listener);
169 * @param propertyName
171 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
172 * java.beans.PropertyChangeListener)
174 public void addJalviewPropertyChangeListener(String propertyName,
175 PropertyChangeListener listener)
177 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
181 * @param propertyName
183 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
184 * java.beans.PropertyChangeListener)
186 public void removeJalviewPropertyChangeListener(String propertyName,
187 PropertyChangeListener listener)
189 changeSupport.removeJalviewPropertyChangeListener(propertyName,
193 /** Singleton Desktop instance */
194 public static Desktop instance;
196 public static MyDesktopPane desktop;
198 static int openFrameCount = 0;
200 static final int xOffset = 30;
202 static final int yOffset = 30;
204 public static jalview.ws.jws1.Discoverer discoverer;
206 public static Object[] jalviewClipboard;
208 public static boolean internalCopy = false;
210 static int fileLoadingCount = 0;
212 class MyDesktopManager implements DesktopManager
215 private DesktopManager delegate;
217 public MyDesktopManager(DesktopManager delegate)
219 this.delegate = delegate;
223 public void activateFrame(JInternalFrame f)
227 delegate.activateFrame(f);
228 } catch (NullPointerException npe)
230 Point p = getMousePosition();
231 instance.showPasteMenu(p.x, p.y);
236 public void beginDraggingFrame(JComponent f)
238 delegate.beginDraggingFrame(f);
242 public void beginResizingFrame(JComponent f, int direction)
244 delegate.beginResizingFrame(f, direction);
248 public void closeFrame(JInternalFrame f)
250 delegate.closeFrame(f);
254 public void deactivateFrame(JInternalFrame f)
256 delegate.deactivateFrame(f);
260 public void deiconifyFrame(JInternalFrame f)
262 delegate.deiconifyFrame(f);
266 public void dragFrame(JComponent f, int newX, int newY)
272 delegate.dragFrame(f, newX, newY);
276 public void endDraggingFrame(JComponent f)
278 delegate.endDraggingFrame(f);
283 public void endResizingFrame(JComponent f)
285 delegate.endResizingFrame(f);
290 public void iconifyFrame(JInternalFrame f)
292 delegate.iconifyFrame(f);
296 public void maximizeFrame(JInternalFrame f)
298 delegate.maximizeFrame(f);
302 public void minimizeFrame(JInternalFrame f)
304 delegate.minimizeFrame(f);
308 public void openFrame(JInternalFrame f)
310 delegate.openFrame(f);
314 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
321 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
325 public void setBoundsForFrame(JComponent f, int newX, int newY,
326 int newWidth, int newHeight)
328 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
331 // All other methods, simply delegate
336 * Creates a new Desktop object.
341 * A note to implementors. It is ESSENTIAL that any activities that might
342 * block are spawned off as threads rather than waited for during this
346 doVamsasClientCheck();
348 doConfigureStructurePrefs();
349 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
350 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
351 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
353 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
355 desktop = new MyDesktopPane(selmemusage);
356 showMemusage.setSelected(selmemusage);
357 desktop.setBackground(Color.white);
358 getContentPane().setLayout(new BorderLayout());
359 // alternate config - have scrollbars - see notes in JAL-153
360 // JScrollPane sp = new JScrollPane();
361 // sp.getViewport().setView(desktop);
362 // getContentPane().add(sp, BorderLayout.CENTER);
363 getContentPane().add(desktop, BorderLayout.CENTER);
364 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
366 // This line prevents Windows Look&Feel resizing all new windows to maximum
367 // if previous window was maximised
368 desktop.setDesktopManager(
369 new MyDesktopManager(
370 (Platform.isWindows() ? new DefaultDesktopManager()
372 ? new AquaInternalFrameManager(
373 desktop.getDesktopManager())
374 : desktop.getDesktopManager())));
376 Rectangle dims = getLastKnownDimensions("");
383 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
384 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
387 jconsole = new Console(this, showjconsole);
388 // add essential build information
390 "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
391 + "\n" + "Jalview Installation: "
392 + jalview.bin.Cache.getDefault("INSTALLATION",
394 + "\n" + "Build Date: "
395 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
396 + "\n" + "Java version: "
397 + System.getProperty("java.version") + "\n"
398 + System.getProperty("os.arch") + " "
399 + System.getProperty("os.name") + " "
400 + System.getProperty("os.version"));
402 showConsole(showjconsole);
404 showNews.setVisible(false);
406 experimentalFeatures.setSelected(showExperimental());
408 getIdentifiersOrgData();
412 this.addWindowListener(new WindowAdapter()
415 public void windowClosing(WindowEvent evt)
422 this.addMouseListener(ma = new MouseAdapter()
425 public void mousePressed(MouseEvent evt)
427 if (evt.isPopupTrigger()) // Mac
429 showPasteMenu(evt.getX(), evt.getY());
434 public void mouseReleased(MouseEvent evt)
436 if (evt.isPopupTrigger()) // Windows
438 showPasteMenu(evt.getX(), evt.getY());
442 desktop.addMouseListener(ma);
444 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
445 // Spawn a thread that shows the splashscreen
446 SwingUtilities.invokeLater(new Runnable()
455 // Thread off a new instance of the file chooser - this reduces the time it
456 // takes to open it later on.
457 new Thread(new Runnable()
462 Cache.log.debug("Filechooser init thread started.");
463 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
464 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
466 Cache.log.debug("Filechooser init thread finished.");
469 // Add the service change listener
470 changeSupport.addJalviewPropertyChangeListener("services",
471 new PropertyChangeListener()
475 public void propertyChange(PropertyChangeEvent evt)
477 Cache.log.debug("Firing service changed event for "
478 + evt.getNewValue());
479 JalviewServicesChanged(evt);
486 * Answers true if user preferences to enable experimental features is True
491 public boolean showExperimental()
493 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
494 Boolean.FALSE.toString());
495 return Boolean.valueOf(experimental).booleanValue();
498 public void doConfigureStructurePrefs()
500 // configure services
501 StructureSelectionManager ssm = StructureSelectionManager
502 .getStructureSelectionManager(this);
503 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
505 ssm.setAddTempFacAnnot(jalview.bin.Cache
506 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
507 ssm.setProcessSecondaryStructure(jalview.bin.Cache
508 .getDefault(Preferences.STRUCT_FROM_PDB, true));
509 ssm.setSecStructServices(
510 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
514 ssm.setAddTempFacAnnot(false);
515 ssm.setProcessSecondaryStructure(false);
516 ssm.setSecStructServices(false);
520 public void checkForNews()
522 final Desktop me = this;
523 // Thread off the news reader, in case there are connection problems.
524 new Thread(new Runnable()
529 Cache.log.debug("Starting news thread.");
531 jvnews = new BlogReader(me);
532 showNews.setVisible(true);
533 Cache.log.debug("Completed news thread.");
538 public void getIdentifiersOrgData()
540 // Thread off the identifiers fetcher
541 new Thread(new Runnable()
546 Cache.log.debug("Downloading data from identifiers.org");
547 UrlDownloadClient client = new UrlDownloadClient();
550 client.download(IdOrgSettings.getUrl(),
551 IdOrgSettings.getDownloadLocation());
552 } catch (IOException e)
554 Cache.log.debug("Exception downloading identifiers.org data"
563 protected void showNews_actionPerformed(ActionEvent e)
565 showNews(showNews.isSelected());
568 void showNews(boolean visible)
571 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
572 showNews.setSelected(visible);
573 if (visible && !jvnews.isVisible())
575 new Thread(new Runnable()
580 long now = System.currentTimeMillis();
581 Desktop.instance.setProgressBar(
582 MessageManager.getString("status.refreshing_news"),
584 jvnews.refreshNews();
585 Desktop.instance.setProgressBar(null, now);
594 * recover the last known dimensions for a jalview window
597 * - empty string is desktop, all other windows have unique prefix
598 * @return null or last known dimensions scaled to current geometry (if last
599 * window geom was known)
601 Rectangle getLastKnownDimensions(String windowName)
603 // TODO: lock aspect ratio for scaling desktop Bug #0058199
604 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
605 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
606 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
607 String width = jalview.bin.Cache
608 .getProperty(windowName + "SCREEN_WIDTH");
609 String height = jalview.bin.Cache
610 .getProperty(windowName + "SCREEN_HEIGHT");
611 if ((x != null) && (y != null) && (width != null) && (height != null))
613 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
614 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
615 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
617 // attempt #1 - try to cope with change in screen geometry - this
618 // version doesn't preserve original jv aspect ratio.
619 // take ratio of current screen size vs original screen size.
620 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
621 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
622 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
623 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
624 // rescale the bounds depending upon the current screen geometry.
625 ix = (int) (ix * sw);
626 iw = (int) (iw * sw);
627 iy = (int) (iy * sh);
628 ih = (int) (ih * sh);
629 while (ix >= screenSize.width)
631 jalview.bin.Cache.log.debug(
632 "Window geometry location recall error: shifting horizontal to within screenbounds.");
633 ix -= screenSize.width;
635 while (iy >= screenSize.height)
637 jalview.bin.Cache.log.debug(
638 "Window geometry location recall error: shifting vertical to within screenbounds.");
639 iy -= screenSize.height;
641 jalview.bin.Cache.log.debug(
642 "Got last known dimensions for " + windowName + ": x:" + ix
643 + " y:" + iy + " width:" + iw + " height:" + ih);
645 // return dimensions for new instance
646 return new Rectangle(ix, iy, iw, ih);
651 private void doVamsasClientCheck()
653 if (jalview.bin.Cache.vamsasJarsPresent())
655 setupVamsasDisconnectedGui();
656 VamsasMenu.setVisible(true);
657 final Desktop us = this;
658 VamsasMenu.addMenuListener(new MenuListener()
660 // this listener remembers when the menu was first selected, and
661 // doesn't rebuild the session list until it has been cleared and
663 boolean refresh = true;
666 public void menuCanceled(MenuEvent e)
672 public void menuDeselected(MenuEvent e)
678 public void menuSelected(MenuEvent e)
682 us.buildVamsasStMenu();
687 vamsasStart.setVisible(true);
691 void showPasteMenu(int x, int y)
693 JPopupMenu popup = new JPopupMenu();
694 JMenuItem item = new JMenuItem(
695 MessageManager.getString("label.paste_new_window"));
696 item.addActionListener(new ActionListener()
699 public void actionPerformed(ActionEvent evt)
706 popup.show(this, x, y);
713 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
714 Transferable contents = c.getContents(this);
716 if (contents != null)
718 String file = (String) contents
719 .getTransferData(DataFlavor.stringFlavor);
721 FileFormatI format = new IdentifyFile().identify(file,
722 DataSourceType.PASTE);
724 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
727 } catch (Exception ex)
730 "Unable to paste alignment from system clipboard:\n" + ex);
735 * Adds and opens the given frame to the desktop
746 public static synchronized void addInternalFrame(
747 final JInternalFrame frame, String title, int w, int h)
749 addInternalFrame(frame, title, true, w, h, true, false);
753 * Add an internal frame to the Jalview desktop
760 * When true, display frame immediately, otherwise, caller must call
761 * setVisible themselves.
767 public static synchronized void addInternalFrame(
768 final JInternalFrame frame, String title, boolean makeVisible,
771 addInternalFrame(frame, title, makeVisible, w, h, true, false);
775 * Add an internal frame to the Jalview desktop and make it visible
788 public static synchronized void addInternalFrame(
789 final JInternalFrame frame, String title, int w, int h,
792 addInternalFrame(frame, title, true, w, h, resizable, false);
796 * Add an internal frame to the Jalview desktop
803 * When true, display frame immediately, otherwise, caller must call
804 * setVisible themselves.
811 * @param ignoreMinSize
812 * Do not set the default minimum size for frame
814 public static synchronized void addInternalFrame(
815 final JInternalFrame frame, String title, boolean makeVisible,
816 int w, int h, boolean resizable, boolean ignoreMinSize)
819 // TODO: allow callers to determine X and Y position of frame (eg. via
821 // TODO: consider fixing method to update entries in the window submenu with
822 // the current window title
824 frame.setTitle(title);
825 if (frame.getWidth() < 1 || frame.getHeight() < 1)
829 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
830 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
831 // IF JALVIEW IS RUNNING HEADLESS
832 // ///////////////////////////////////////////////
833 if (instance == null || (System.getProperty("java.awt.headless") != null
834 && System.getProperty("java.awt.headless").equals("true")))
843 frame.setMinimumSize(
844 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
846 // Set default dimension for Alignment Frame window.
847 // The Alignment Frame window could be added from a number of places,
849 // I did this here in order not to miss out on any Alignment frame.
850 if (frame instanceof AlignFrame)
852 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
853 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
857 frame.setVisible(makeVisible);
858 frame.setClosable(true);
859 frame.setResizable(resizable);
860 frame.setMaximizable(resizable);
861 frame.setIconifiable(resizable);
862 frame.setOpaque(false);
864 if (frame.getX() < 1 && frame.getY() < 1)
866 frame.setLocation(xOffset * openFrameCount,
867 yOffset * ((openFrameCount - 1) % 10) + yOffset);
871 * add an entry for the new frame in the Window menu
872 * (and remove it when the frame is closed)
874 final JMenuItem menuItem = new JMenuItem(title);
875 frame.addInternalFrameListener(new InternalFrameAdapter()
878 public void internalFrameActivated(InternalFrameEvent evt)
880 JInternalFrame itf = desktop.getSelectedFrame();
883 if (itf instanceof AlignFrame)
885 Jalview.setCurrentAlignFrame((AlignFrame) itf);
892 public void internalFrameClosed(InternalFrameEvent evt)
894 PaintRefresher.RemoveComponent(frame);
897 * defensive check to prevent frames being
898 * added half off the window
900 if (openFrameCount > 0)
906 * ensure no reference to alignFrame retained by menu item listener
908 if (menuItem.getActionListeners().length > 0)
910 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
912 windowMenu.remove(menuItem);
916 menuItem.addActionListener(new ActionListener()
919 public void actionPerformed(ActionEvent e)
923 frame.setSelected(true);
924 frame.setIcon(false);
925 } catch (java.beans.PropertyVetoException ex)
932 setKeyBindings(frame);
936 windowMenu.add(menuItem);
941 frame.setSelected(true);
942 frame.requestFocus();
943 } catch (java.beans.PropertyVetoException ve)
945 } catch (java.lang.ClassCastException cex)
948 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
954 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
959 private static void setKeyBindings(JInternalFrame frame)
961 @SuppressWarnings("serial")
962 final Action closeAction = new AbstractAction()
965 public void actionPerformed(ActionEvent e)
972 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
974 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
975 InputEvent.CTRL_DOWN_MASK);
976 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
977 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
979 InputMap inputMap = frame
980 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
981 String ctrlW = ctrlWKey.toString();
982 inputMap.put(ctrlWKey, ctrlW);
983 inputMap.put(cmdWKey, ctrlW);
985 ActionMap actionMap = frame.getActionMap();
986 actionMap.put(ctrlW, closeAction);
990 public void lostOwnership(Clipboard clipboard, Transferable contents)
994 Desktop.jalviewClipboard = null;
997 internalCopy = false;
1001 public void dragEnter(DropTargetDragEvent evt)
1006 public void dragExit(DropTargetEvent evt)
1011 public void dragOver(DropTargetDragEvent evt)
1016 public void dropActionChanged(DropTargetDragEvent evt)
1027 public void drop(DropTargetDropEvent evt)
1029 boolean success = true;
1030 // JAL-1552 - acceptDrop required before getTransferable call for
1031 // Java's Transferable for native dnd
1032 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1033 Transferable t = evt.getTransferable();
1034 List<String> files = new ArrayList<>();
1035 List<DataSourceType> protocols = new ArrayList<>();
1039 Desktop.transferFromDropTarget(files, protocols, evt, t);
1040 } catch (Exception e)
1042 e.printStackTrace();
1050 for (int i = 0; i < files.size(); i++)
1052 String file = files.get(i).toString();
1053 DataSourceType protocol = (protocols == null)
1054 ? DataSourceType.FILE
1056 FileFormatI format = null;
1058 if (file.endsWith(".jar"))
1060 format = FileFormat.Jalview;
1065 format = new IdentifyFile().identify(file, protocol);
1068 new FileLoader().LoadFile(file, protocol, format);
1071 } catch (Exception ex)
1076 evt.dropComplete(success); // need this to ensure input focus is properly
1077 // transfered to any new windows created
1087 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1089 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1090 JalviewFileChooser chooser = JalviewFileChooser
1091 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1093 chooser.setFileView(new JalviewFileView());
1094 chooser.setDialogTitle(
1095 MessageManager.getString("label.open_local_file"));
1096 chooser.setToolTipText(MessageManager.getString("action.open"));
1098 int value = chooser.showOpenDialog(this);
1100 if (value == JalviewFileChooser.APPROVE_OPTION)
1102 String choice = chooser.getSelectedFile().getPath();
1103 Cache.setProperty("LAST_DIRECTORY",
1104 chooser.getSelectedFile().getParent());
1106 FileFormatI format = chooser.getSelectedFormat();
1109 * Call IdentifyFile to verify the file contains what its extension implies.
1110 * Skip this step for dynamically added file formats, because
1111 * IdentifyFile does not know how to recognise them.
1113 if (FileFormats.getInstance().isIdentifiable(format))
1117 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1118 } catch (FileFormatException e)
1120 // format = null; //??
1124 if (viewport != null)
1126 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1131 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1143 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1145 // This construct allows us to have a wider textfield
1147 JLabel label = new JLabel(
1148 MessageManager.getString("label.input_file_url"));
1149 final JComboBox history = new JComboBox();
1151 JPanel panel = new JPanel(new GridLayout(2, 1));
1154 history.setPreferredSize(new Dimension(400, 20));
1155 history.setEditable(true);
1156 history.addItem("http://www.");
1158 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1162 if (historyItems != null)
1164 st = new StringTokenizer(historyItems, "\t");
1166 while (st.hasMoreTokens())
1168 history.addItem(st.nextElement());
1172 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1173 MessageManager.getString("label.input_alignment_from_url"),
1174 JvOptionPane.OK_CANCEL_OPTION);
1176 if (reply != JvOptionPane.OK_OPTION)
1181 String url = history.getSelectedItem().toString();
1183 if (url.toLowerCase().endsWith(".jar"))
1185 if (viewport != null)
1187 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1188 FileFormat.Jalview);
1192 new FileLoader().LoadFile(url, DataSourceType.URL,
1193 FileFormat.Jalview);
1198 FileFormatI format = null;
1201 format = new IdentifyFile().identify(url, DataSourceType.URL);
1202 } catch (FileFormatException e)
1204 // TODO revise error handling, distinguish between
1205 // URL not found and response not valid
1210 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1211 MessageManager.formatMessage("label.couldnt_locate",
1214 MessageManager.getString("label.url_not_found"),
1215 JvOptionPane.WARNING_MESSAGE);
1220 if (viewport != null)
1222 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1227 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1233 * Opens the CutAndPaste window for the user to paste an alignment in to
1236 * - if not null, the pasted alignment is added to the current
1237 * alignment; if null, to a new alignment window
1240 public void inputTextboxMenuItem_actionPerformed(
1241 AlignmentViewPanel viewPanel)
1243 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1244 cap.setForInput(viewPanel);
1245 Desktop.addInternalFrame(cap,
1246 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1256 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1257 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1259 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1260 screen.height + "");
1261 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1262 getWidth(), getHeight()));
1264 if (jconsole != null)
1266 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1267 jconsole.stopConsole();
1271 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1274 if (dialogExecutor != null)
1276 dialogExecutor.shutdownNow();
1278 closeAll_actionPerformed(null);
1280 if (groovyConsole != null)
1282 // suppress a possible repeat prompt to save script
1283 groovyConsole.setDirty(false);
1284 groovyConsole.exit();
1289 private void storeLastKnownDimensions(String string, Rectangle jc)
1291 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1292 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1293 + " height:" + jc.height);
1295 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1296 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1297 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1298 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1308 public void aboutMenuItem_actionPerformed(ActionEvent e)
1310 // StringBuffer message = getAboutMessage(false);
1311 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1313 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1314 new Thread(new Runnable()
1319 new SplashScreen(true);
1324 public StringBuffer getAboutMessage(boolean shortv)
1326 StringBuffer message = new StringBuffer();
1327 message.append("<html>");
1330 message.append("<h1><strong>Version: "
1331 + jalview.bin.Cache.getProperty("VERSION")
1332 + "</strong></h1>");
1333 message.append("<strong>Last Updated: <em>"
1334 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1335 + "</em></strong>");
1341 message.append("<strong>Version "
1342 + jalview.bin.Cache.getProperty("VERSION")
1343 + "; last updated: "
1344 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1347 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1348 .equals("Checking"))
1350 message.append("<br>...Checking latest version...</br>");
1352 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1353 .equals(jalview.bin.Cache.getProperty("VERSION")))
1355 boolean red = false;
1356 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1357 .indexOf("automated build") == -1)
1360 // Displayed when code version and jnlp version do not match and code
1361 // version is not a development build
1362 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1365 message.append("<br>!! Version "
1366 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1368 + " is available for download from "
1369 + jalview.bin.Cache.getDefault("www.jalview.org",
1370 "http://www.jalview.org")
1374 message.append("</div>");
1377 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1379 "The Jalview Authors (See AUTHORS file for current list)")
1380 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1381 + "<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"
1382 + "<br><br>If you use Jalview, please cite:"
1383 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1384 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1385 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1397 public void documentationMenuItem_actionPerformed(ActionEvent e)
1401 Help.showHelpWindow();
1402 } catch (Exception ex)
1408 public void closeAll_actionPerformed(ActionEvent e)
1410 // TODO show a progress bar while closing?
1411 JInternalFrame[] frames = desktop.getAllFrames();
1412 for (int i = 0; i < frames.length; i++)
1416 frames[i].setClosed(true);
1417 } catch (java.beans.PropertyVetoException ex)
1421 Jalview.setCurrentAlignFrame(null);
1422 System.out.println("ALL CLOSED");
1423 if (v_client != null)
1425 // TODO clear binding to vamsas document objects on close_all
1429 * reset state of singleton objects as appropriate (clear down session state
1430 * when all windows are closed)
1432 StructureSelectionManager ssm = StructureSelectionManager
1433 .getStructureSelectionManager(this);
1441 public void raiseRelated_actionPerformed(ActionEvent e)
1443 reorderAssociatedWindows(false, false);
1447 public void minimizeAssociated_actionPerformed(ActionEvent e)
1449 reorderAssociatedWindows(true, false);
1452 void closeAssociatedWindows()
1454 reorderAssociatedWindows(false, true);
1460 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1464 protected void garbageCollect_actionPerformed(ActionEvent e)
1466 // We simply collect the garbage
1467 jalview.bin.Cache.log.debug("Collecting garbage...");
1469 jalview.bin.Cache.log.debug("Finished garbage collection.");
1476 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1480 protected void showMemusage_actionPerformed(ActionEvent e)
1482 desktop.showMemoryUsage(showMemusage.isSelected());
1489 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1493 protected void showConsole_actionPerformed(ActionEvent e)
1495 showConsole(showConsole.isSelected());
1498 Console jconsole = null;
1501 * control whether the java console is visible or not
1505 void showConsole(boolean selected)
1507 showConsole.setSelected(selected);
1508 // TODO: decide if we should update properties file
1509 Cache.setProperty("SHOW_JAVA_CONSOLE",
1510 Boolean.valueOf(selected).toString());
1511 jconsole.setVisible(selected);
1514 void reorderAssociatedWindows(boolean minimize, boolean close)
1516 JInternalFrame[] frames = desktop.getAllFrames();
1517 if (frames == null || frames.length < 1)
1522 AlignmentViewport source = null, target = null;
1523 if (frames[0] instanceof AlignFrame)
1525 source = ((AlignFrame) frames[0]).getCurrentView();
1527 else if (frames[0] instanceof TreePanel)
1529 source = ((TreePanel) frames[0]).getViewPort();
1531 else if (frames[0] instanceof PCAPanel)
1533 source = ((PCAPanel) frames[0]).av;
1535 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1537 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1542 for (int i = 0; i < frames.length; i++)
1545 if (frames[i] == null)
1549 if (frames[i] instanceof AlignFrame)
1551 target = ((AlignFrame) frames[i]).getCurrentView();
1553 else if (frames[i] instanceof TreePanel)
1555 target = ((TreePanel) frames[i]).getViewPort();
1557 else if (frames[i] instanceof PCAPanel)
1559 target = ((PCAPanel) frames[i]).av;
1561 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1563 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1566 if (source == target)
1572 frames[i].setClosed(true);
1576 frames[i].setIcon(minimize);
1579 frames[i].toFront();
1583 } catch (java.beans.PropertyVetoException ex)
1598 protected void preferences_actionPerformed(ActionEvent e)
1604 * Shows a file chooser dialog and writes out the current session as a Jalview
1608 public void saveState_actionPerformed()
1610 saveState_actionPerformed(false);
1613 public void saveState_actionPerformed(boolean saveAs)
1615 java.io.File projectFile = getProjectFile();
1616 // autoSave indicates we already have a file and don't need to ask
1617 boolean autoSave = projectFile != null && !saveAs && BackupFiles.getEnabled();
1619 //System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"', saveAs="+saveAs+", Backups "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1621 boolean approveSave = false;
1624 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1627 chooser.setFileView(new JalviewFileView());
1628 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1630 int value = chooser.showSaveDialog(this);
1632 if (value == JalviewFileChooser.APPROVE_OPTION)
1634 projectFile = chooser.getSelectedFile();
1635 setProjectFile(projectFile);
1640 if (approveSave || autoSave) {
1641 final Desktop me = this;
1642 final java.io.File chosenFile = projectFile;
1643 new Thread(new Runnable()
1648 // TODO: refactor to Jalview desktop session controller action.
1649 setProgressBar(MessageManager.formatMessage(
1650 "label.saving_jalview_project", new Object[]
1651 { chosenFile.getName() }), chosenFile.hashCode());
1652 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1653 chosenFile.getParent());
1654 // TODO catch and handle errors for savestate
1655 // TODO prevent user from messing with the Desktop whilst we're saving
1658 BackupFiles backupfiles = new BackupFiles(chosenFile);
1660 new Jalview2XML().saveState(backupfiles.getTempFile());
1662 backupfiles.setWriteSuccess(true);
1663 backupfiles.rollBackupsAndRenameTempFile();
1664 } catch (OutOfMemoryError oom)
1667 "Whilst saving current state to " + chosenFile.getName(),
1669 } catch (Exception ex)
1672 "Problems whilst trying to save to " + chosenFile.getName(),
1674 JvOptionPane.showMessageDialog(me,
1675 MessageManager.formatMessage(
1676 "label.error_whilst_saving_current_state_to",
1678 { chosenFile.getName() }),
1679 MessageManager.getString("label.couldnt_save_project"),
1680 JvOptionPane.WARNING_MESSAGE);
1682 setProgressBar(null, chosenFile.hashCode());
1689 public void saveAsState_actionPerformed(ActionEvent e)
1691 saveState_actionPerformed(true);
1694 private void setProjectFile(File choice)
1696 this.projectFile = choice;
1699 public File getProjectFile()
1701 return this.projectFile;
1705 * Shows a file chooser dialog and tries to read in the selected file as a
1709 public void loadState_actionPerformed()
1711 final String[] suffix = new String[] { "jvp", "jar" };
1712 final String[] desc = new String[] { "Jalview Project",
1713 "Jalview Project (old)" };
1714 JalviewFileChooser chooser = new JalviewFileChooser(
1715 Cache.getProperty("LAST_DIRECTORY"), suffix,
1718 chooser.setFileView(new JalviewFileView());
1719 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1721 int value = chooser.showOpenDialog(this);
1723 if (value == JalviewFileChooser.APPROVE_OPTION)
1725 final File selectedFile = chooser.getSelectedFile();
1726 setProjectFile(selectedFile);
1727 final String choice = selectedFile.getAbsolutePath();
1728 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1729 new Thread(new Runnable()
1734 setProgressBar(MessageManager.formatMessage(
1735 "label.loading_jalview_project", new Object[]
1736 { choice }), choice.hashCode());
1739 new Jalview2XML().loadJalviewAlign(choice);
1740 } catch (OutOfMemoryError oom)
1742 new OOMWarning("Whilst loading project from " + choice, oom);
1743 } catch (Exception ex)
1746 "Problems whilst loading project from " + choice, ex);
1747 JvOptionPane.showMessageDialog(Desktop.desktop,
1748 MessageManager.formatMessage(
1749 "label.error_whilst_loading_project_from",
1752 MessageManager.getString("label.couldnt_load_project"),
1753 JvOptionPane.WARNING_MESSAGE);
1755 setProgressBar(null, choice.hashCode());
1762 public void inputSequence_actionPerformed(ActionEvent e)
1764 new SequenceFetcher(this);
1767 JPanel progressPanel;
1769 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1771 public void startLoading(final String fileName)
1773 if (fileLoadingCount == 0)
1775 fileLoadingPanels.add(addProgressPanel(MessageManager
1776 .formatMessage("label.loading_file", new Object[]
1782 private JPanel addProgressPanel(String string)
1784 if (progressPanel == null)
1786 progressPanel = new JPanel(new GridLayout(1, 1));
1787 totalProgressCount = 0;
1788 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1790 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1791 JProgressBar progressBar = new JProgressBar();
1792 progressBar.setIndeterminate(true);
1794 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1796 thisprogress.add(progressBar, BorderLayout.CENTER);
1797 progressPanel.add(thisprogress);
1798 ((GridLayout) progressPanel.getLayout()).setRows(
1799 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1800 ++totalProgressCount;
1801 instance.validate();
1802 return thisprogress;
1805 int totalProgressCount = 0;
1807 private void removeProgressPanel(JPanel progbar)
1809 if (progressPanel != null)
1811 synchronized (progressPanel)
1813 progressPanel.remove(progbar);
1814 GridLayout gl = (GridLayout) progressPanel.getLayout();
1815 gl.setRows(gl.getRows() - 1);
1816 if (--totalProgressCount < 1)
1818 this.getContentPane().remove(progressPanel);
1819 progressPanel = null;
1826 public void stopLoading()
1829 if (fileLoadingCount < 1)
1831 while (fileLoadingPanels.size() > 0)
1833 removeProgressPanel(fileLoadingPanels.remove(0));
1835 fileLoadingPanels.clear();
1836 fileLoadingCount = 0;
1841 public static int getViewCount(String alignmentId)
1843 AlignmentViewport[] aps = getViewports(alignmentId);
1844 return (aps == null) ? 0 : aps.length;
1849 * @param alignmentId
1850 * - if null, all sets are returned
1851 * @return all AlignmentPanels concerning the alignmentId sequence set
1853 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1855 if (Desktop.desktop == null)
1857 // no frames created and in headless mode
1858 // TODO: verify that frames are recoverable when in headless mode
1861 List<AlignmentPanel> aps = new ArrayList<>();
1862 AlignFrame[] frames = getAlignFrames();
1867 for (AlignFrame af : frames)
1869 for (AlignmentPanel ap : af.alignPanels)
1871 if (alignmentId == null
1872 || alignmentId.equals(ap.av.getSequenceSetId()))
1878 if (aps.size() == 0)
1882 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1887 * get all the viewports on an alignment.
1889 * @param sequenceSetId
1890 * unique alignment id (may be null - all viewports returned in that
1892 * @return all viewports on the alignment bound to sequenceSetId
1894 public static AlignmentViewport[] getViewports(String sequenceSetId)
1896 List<AlignmentViewport> viewp = new ArrayList<>();
1897 if (desktop != null)
1899 AlignFrame[] frames = Desktop.getAlignFrames();
1901 for (AlignFrame afr : frames)
1903 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1904 .equals(sequenceSetId))
1906 if (afr.alignPanels != null)
1908 for (AlignmentPanel ap : afr.alignPanels)
1910 if (sequenceSetId == null
1911 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1919 viewp.add(afr.getViewport());
1923 if (viewp.size() > 0)
1925 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1932 * Explode the views in the given frame into separate AlignFrame
1936 public static void explodeViews(AlignFrame af)
1938 int size = af.alignPanels.size();
1944 for (int i = 0; i < size; i++)
1946 AlignmentPanel ap = af.alignPanels.get(i);
1947 AlignFrame newaf = new AlignFrame(ap);
1950 * Restore the view's last exploded frame geometry if known. Multiple
1951 * views from one exploded frame share and restore the same (frame)
1952 * position and size.
1954 Rectangle geometry = ap.av.getExplodedGeometry();
1955 if (geometry != null)
1957 newaf.setBounds(geometry);
1960 ap.av.setGatherViewsHere(false);
1962 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1963 AlignFrame.DEFAULT_HEIGHT);
1966 af.alignPanels.clear();
1967 af.closeMenuItem_actionPerformed(true);
1972 * Gather expanded views (separate AlignFrame's) with the same sequence set
1973 * identifier back in to this frame as additional views, and close the
1974 * expanded views. Note the expanded frames may themselves have multiple
1975 * views. We take the lot.
1979 public void gatherViews(AlignFrame source)
1981 source.viewport.setGatherViewsHere(true);
1982 source.viewport.setExplodedGeometry(source.getBounds());
1983 JInternalFrame[] frames = desktop.getAllFrames();
1984 String viewId = source.viewport.getSequenceSetId();
1986 for (int t = 0; t < frames.length; t++)
1988 if (frames[t] instanceof AlignFrame && frames[t] != source)
1990 AlignFrame af = (AlignFrame) frames[t];
1991 boolean gatherThis = false;
1992 for (int a = 0; a < af.alignPanels.size(); a++)
1994 AlignmentPanel ap = af.alignPanels.get(a);
1995 if (viewId.equals(ap.av.getSequenceSetId()))
1998 ap.av.setGatherViewsHere(false);
1999 ap.av.setExplodedGeometry(af.getBounds());
2000 source.addAlignmentPanel(ap, false);
2006 af.alignPanels.clear();
2007 af.closeMenuItem_actionPerformed(true);
2014 jalview.gui.VamsasApplication v_client = null;
2017 public void vamsasImport_actionPerformed(ActionEvent e)
2019 if (v_client == null)
2021 // Load and try to start a session.
2022 JalviewFileChooser chooser = new JalviewFileChooser(
2023 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2025 chooser.setFileView(new JalviewFileView());
2026 chooser.setDialogTitle(
2027 MessageManager.getString("label.open_saved_vamsas_session"));
2028 chooser.setToolTipText(MessageManager.getString(
2029 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2031 int value = chooser.showOpenDialog(this);
2033 if (value == JalviewFileChooser.APPROVE_OPTION)
2035 String fle = chooser.getSelectedFile().toString();
2036 if (!vamsasImport(chooser.getSelectedFile()))
2038 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2039 MessageManager.formatMessage(
2040 "label.couldnt_import_as_vamsas_session",
2044 .getString("label.vamsas_document_import_failed"),
2045 JvOptionPane.ERROR_MESSAGE);
2051 jalview.bin.Cache.log.error(
2052 "Implementation error - load session from a running session is not supported.");
2057 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2060 * @return true if import was a success and a session was started.
2062 public boolean vamsasImport(URL url)
2064 // TODO: create progress bar
2065 if (v_client != null)
2068 jalview.bin.Cache.log.error(
2069 "Implementation error - load session from a running session is not supported.");
2075 // copy the URL content to a temporary local file
2076 // TODO: be a bit cleverer here with nio (?!)
2077 File file = File.createTempFile("vdocfromurl", ".vdj");
2078 FileOutputStream fos = new FileOutputStream(file);
2079 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2080 byte[] buffer = new byte[2048];
2082 while ((ln = bis.read(buffer)) > -1)
2084 fos.write(buffer, 0, ln);
2088 v_client = new jalview.gui.VamsasApplication(this, file,
2089 url.toExternalForm());
2090 } catch (Exception ex)
2092 jalview.bin.Cache.log.error(
2093 "Failed to create new vamsas session from contents of URL "
2098 setupVamsasConnectedGui();
2099 v_client.initial_update(); // TODO: thread ?
2100 return v_client.inSession();
2104 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2107 * @return true if import was a success and a session was started.
2109 public boolean vamsasImport(File file)
2111 if (v_client != null)
2114 jalview.bin.Cache.log.error(
2115 "Implementation error - load session from a running session is not supported.");
2119 setProgressBar(MessageManager.formatMessage(
2120 "status.importing_vamsas_session_from", new Object[]
2121 { file.getName() }), file.hashCode());
2124 v_client = new jalview.gui.VamsasApplication(this, file, null);
2125 } catch (Exception ex)
2127 setProgressBar(MessageManager.formatMessage(
2128 "status.importing_vamsas_session_from", new Object[]
2129 { file.getName() }), file.hashCode());
2130 jalview.bin.Cache.log.error(
2131 "New vamsas session from existing session file failed:", ex);
2134 setupVamsasConnectedGui();
2135 v_client.initial_update(); // TODO: thread ?
2136 setProgressBar(MessageManager.formatMessage(
2137 "status.importing_vamsas_session_from", new Object[]
2138 { file.getName() }), file.hashCode());
2139 return v_client.inSession();
2142 public boolean joinVamsasSession(String mysesid)
2144 if (v_client != null)
2146 throw new Error(MessageManager
2147 .getString("error.try_join_vamsas_session_another"));
2149 if (mysesid == null)
2152 MessageManager.getString("error.invalid_vamsas_session_id"));
2154 v_client = new VamsasApplication(this, mysesid);
2155 setupVamsasConnectedGui();
2156 v_client.initial_update();
2157 return (v_client.inSession());
2161 public void vamsasStart_actionPerformed(ActionEvent e)
2163 if (v_client == null)
2166 // we just start a default session for moment.
2168 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2169 * getProperty("LAST_DIRECTORY"));
2171 * chooser.setFileView(new JalviewFileView());
2172 * chooser.setDialogTitle("Load Vamsas file");
2173 * chooser.setToolTipText("Import");
2175 * int value = chooser.showOpenDialog(this);
2177 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2178 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2180 v_client = new VamsasApplication(this);
2181 setupVamsasConnectedGui();
2182 v_client.initial_update(); // TODO: thread ?
2186 // store current data in session.
2187 v_client.push_update(); // TODO: thread
2191 protected void setupVamsasConnectedGui()
2193 vamsasStart.setText(MessageManager.getString("label.session_update"));
2194 vamsasSave.setVisible(true);
2195 vamsasStop.setVisible(true);
2196 vamsasImport.setVisible(false); // Document import to existing session is
2197 // not possible for vamsas-client-1.0.
2200 protected void setupVamsasDisconnectedGui()
2202 vamsasSave.setVisible(false);
2203 vamsasStop.setVisible(false);
2204 vamsasImport.setVisible(true);
2206 .setText(MessageManager.getString("label.new_vamsas_session"));
2210 public void vamsasStop_actionPerformed(ActionEvent e)
2212 if (v_client != null)
2214 v_client.end_session();
2216 setupVamsasDisconnectedGui();
2220 protected void buildVamsasStMenu()
2222 if (v_client == null)
2224 String[] sess = null;
2227 sess = VamsasApplication.getSessionList();
2228 } catch (Exception e)
2230 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2236 jalview.bin.Cache.log.debug(
2237 "Got current sessions list: " + sess.length + " entries.");
2238 VamsasStMenu.removeAll();
2239 for (int i = 0; i < sess.length; i++)
2241 JMenuItem sessit = new JMenuItem();
2242 sessit.setText(sess[i]);
2243 sessit.setToolTipText(MessageManager
2244 .formatMessage("label.connect_to_session", new Object[]
2246 final Desktop dsktp = this;
2247 final String mysesid = sess[i];
2248 sessit.addActionListener(new ActionListener()
2252 public void actionPerformed(ActionEvent e)
2254 if (dsktp.v_client == null)
2256 Thread rthr = new Thread(new Runnable()
2262 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2263 dsktp.setupVamsasConnectedGui();
2264 dsktp.v_client.initial_update();
2272 VamsasStMenu.add(sessit);
2274 // don't show an empty menu.
2275 VamsasStMenu.setVisible(sess.length > 0);
2280 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2281 VamsasStMenu.removeAll();
2282 VamsasStMenu.setVisible(false);
2287 // Not interested in the content. Just hide ourselves.
2288 VamsasStMenu.setVisible(false);
2293 public void vamsasSave_actionPerformed(ActionEvent e)
2295 if (v_client != null)
2297 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2298 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2301 chooser.setFileView(new JalviewFileView());
2302 chooser.setDialogTitle(MessageManager
2303 .getString("label.save_vamsas_document_archive"));
2305 int value = chooser.showSaveDialog(this);
2307 if (value == JalviewFileChooser.APPROVE_OPTION)
2309 java.io.File choice = chooser.getSelectedFile();
2310 JPanel progpanel = addProgressPanel(MessageManager
2311 .formatMessage("label.saving_vamsas_doc", new Object[]
2312 { choice.getName() }));
2313 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2314 String warnmsg = null;
2315 String warnttl = null;
2318 v_client.vclient.storeDocument(choice);
2321 warnttl = "Serious Problem saving Vamsas Document";
2322 warnmsg = ex.toString();
2323 jalview.bin.Cache.log
2324 .error("Error Whilst saving document to " + choice, ex);
2326 } catch (Exception ex)
2328 warnttl = "Problem saving Vamsas Document.";
2329 warnmsg = ex.toString();
2330 jalview.bin.Cache.log.warn(
2331 "Exception Whilst saving document to " + choice, ex);
2334 removeProgressPanel(progpanel);
2335 if (warnmsg != null)
2337 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2339 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2345 JPanel vamUpdate = null;
2348 * hide vamsas user gui bits when a vamsas document event is being handled.
2351 * true to hide gui, false to reveal gui
2353 public void setVamsasUpdate(boolean b)
2355 Cache.log.debug("Setting gui for Vamsas update "
2356 + (b ? "in progress" : "finished"));
2358 if (vamUpdate != null)
2360 this.removeProgressPanel(vamUpdate);
2364 vamUpdate = this.addProgressPanel(
2365 MessageManager.getString("label.updating_vamsas_session"));
2367 vamsasStart.setVisible(!b);
2368 vamsasStop.setVisible(!b);
2369 vamsasSave.setVisible(!b);
2372 public JInternalFrame[] getAllFrames()
2374 return desktop.getAllFrames();
2378 * Checks the given url to see if it gives a response indicating that the user
2379 * should be informed of a new questionnaire.
2383 public void checkForQuestionnaire(String url)
2385 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2386 // javax.swing.SwingUtilities.invokeLater(jvq);
2387 new Thread(jvq).start();
2390 public void checkURLLinks()
2392 // Thread off the URL link checker
2393 addDialogThread(new Runnable()
2398 if (Cache.getDefault("CHECKURLLINKS", true))
2400 // check what the actual links are - if it's just the default don't
2401 // bother with the warning
2402 List<String> links = Preferences.sequenceUrlLinks
2405 // only need to check links if there is one with a
2406 // SEQUENCE_ID which is not the default EMBL_EBI link
2407 ListIterator<String> li = links.listIterator();
2408 boolean check = false;
2409 List<JLabel> urls = new ArrayList<>();
2410 while (li.hasNext())
2412 String link = li.next();
2413 if (link.contains(SEQUENCE_ID)
2414 && !UrlConstants.isDefaultString(link))
2417 int barPos = link.indexOf("|");
2418 String urlMsg = barPos == -1 ? link
2419 : link.substring(0, barPos) + ": "
2420 + link.substring(barPos + 1);
2421 urls.add(new JLabel(urlMsg));
2429 // ask user to check in case URL links use old style tokens
2430 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2431 JPanel msgPanel = new JPanel();
2432 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2433 msgPanel.add(Box.createVerticalGlue());
2434 JLabel msg = new JLabel(MessageManager
2435 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2436 JLabel msg2 = new JLabel(MessageManager
2437 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2439 for (JLabel url : urls)
2445 final JCheckBox jcb = new JCheckBox(
2446 MessageManager.getString("label.do_not_display_again"));
2447 jcb.addActionListener(new ActionListener()
2450 public void actionPerformed(ActionEvent e)
2452 // update Cache settings for "don't show this again"
2453 boolean showWarningAgain = !jcb.isSelected();
2454 Cache.setProperty("CHECKURLLINKS",
2455 Boolean.valueOf(showWarningAgain).toString());
2460 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2462 .getString("label.SEQUENCE_ID_no_longer_used"),
2463 JvOptionPane.WARNING_MESSAGE);
2470 * Proxy class for JDesktopPane which optionally displays the current memory
2471 * usage and highlights the desktop area with a red bar if free memory runs
2476 public class MyDesktopPane extends JDesktopPane implements Runnable
2479 private static final float ONE_MB = 1048576f;
2481 boolean showMemoryUsage = false;
2485 java.text.NumberFormat df;
2487 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2490 public MyDesktopPane(boolean showMemoryUsage)
2492 showMemoryUsage(showMemoryUsage);
2495 public void showMemoryUsage(boolean showMemory)
2497 this.showMemoryUsage = showMemory;
2500 Thread worker = new Thread(this);
2506 public boolean isShowMemoryUsage()
2508 return showMemoryUsage;
2514 df = java.text.NumberFormat.getNumberInstance();
2515 df.setMaximumFractionDigits(2);
2516 runtime = Runtime.getRuntime();
2518 while (showMemoryUsage)
2522 maxMemory = runtime.maxMemory() / ONE_MB;
2523 allocatedMemory = runtime.totalMemory() / ONE_MB;
2524 freeMemory = runtime.freeMemory() / ONE_MB;
2525 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2527 percentUsage = (totalFreeMemory / maxMemory) * 100;
2529 // if (percentUsage < 20)
2531 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2533 // instance.set.setBorder(border1);
2536 // sleep after showing usage
2538 } catch (Exception ex)
2540 ex.printStackTrace();
2546 public void paintComponent(Graphics g)
2548 if (showMemoryUsage && g != null && df != null)
2550 if (percentUsage < 20)
2552 g.setColor(Color.red);
2554 FontMetrics fm = g.getFontMetrics();
2557 g.drawString(MessageManager.formatMessage("label.memory_stats",
2559 { df.format(totalFreeMemory), df.format(maxMemory),
2560 df.format(percentUsage) }),
2561 10, getHeight() - fm.getHeight());
2569 * Accessor method to quickly get all the AlignmentFrames loaded.
2571 * @return an array of AlignFrame, or null if none found
2573 public static AlignFrame[] getAlignFrames()
2575 if (Jalview.isHeadlessMode())
2577 // Desktop.desktop is null in headless mode
2578 return new AlignFrame[] { Jalview.currentAlignFrame };
2581 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2587 List<AlignFrame> avp = new ArrayList<>();
2589 for (int i = frames.length - 1; i > -1; i--)
2591 if (frames[i] instanceof AlignFrame)
2593 avp.add((AlignFrame) frames[i]);
2595 else if (frames[i] instanceof SplitFrame)
2598 * Also check for a split frame containing an AlignFrame
2600 GSplitFrame sf = (GSplitFrame) frames[i];
2601 if (sf.getTopFrame() instanceof AlignFrame)
2603 avp.add((AlignFrame) sf.getTopFrame());
2605 if (sf.getBottomFrame() instanceof AlignFrame)
2607 avp.add((AlignFrame) sf.getBottomFrame());
2611 if (avp.size() == 0)
2615 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2620 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2624 public GStructureViewer[] getJmols()
2626 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2632 List<GStructureViewer> avp = new ArrayList<>();
2634 for (int i = frames.length - 1; i > -1; i--)
2636 if (frames[i] instanceof AppJmol)
2638 GStructureViewer af = (GStructureViewer) frames[i];
2642 if (avp.size() == 0)
2646 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2651 * Add Groovy Support to Jalview
2654 public void groovyShell_actionPerformed()
2658 openGroovyConsole();
2659 } catch (Exception ex)
2661 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2662 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2664 MessageManager.getString("label.couldnt_create_groovy_shell"),
2665 MessageManager.getString("label.groovy_support_failed"),
2666 JvOptionPane.ERROR_MESSAGE);
2671 * Open the Groovy console
2673 void openGroovyConsole()
2675 if (groovyConsole == null)
2677 groovyConsole = new groovy.ui.Console();
2678 groovyConsole.setVariable("Jalview", this);
2679 groovyConsole.run();
2682 * We allow only one console at a time, so that AlignFrame menu option
2683 * 'Calculate | Run Groovy script' is unambiguous.
2684 * Disable 'Groovy Console', and enable 'Run script', when the console is
2685 * opened, and the reverse when it is closed
2687 Window window = (Window) groovyConsole.getFrame();
2688 window.addWindowListener(new WindowAdapter()
2691 public void windowClosed(WindowEvent e)
2694 * rebind CMD-Q from Groovy Console to Jalview Quit
2697 enableExecuteGroovy(false);
2703 * show Groovy console window (after close and reopen)
2705 ((Window) groovyConsole.getFrame()).setVisible(true);
2708 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2709 * and disable opening a second console
2711 enableExecuteGroovy(true);
2715 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2716 * binding when opened
2718 protected void addQuitHandler()
2720 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2721 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2722 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2724 getRootPane().getActionMap().put("Quit", new AbstractAction()
2727 public void actionPerformed(ActionEvent e)
2735 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2738 * true if Groovy console is open
2740 public void enableExecuteGroovy(boolean enabled)
2743 * disable opening a second Groovy console
2744 * (or re-enable when the console is closed)
2746 groovyShell.setEnabled(!enabled);
2748 AlignFrame[] alignFrames = getAlignFrames();
2749 if (alignFrames != null)
2751 for (AlignFrame af : alignFrames)
2753 af.setGroovyEnabled(enabled);
2759 * Progress bars managed by the IProgressIndicator method.
2761 private Hashtable<Long, JPanel> progressBars;
2763 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2768 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2771 public void setProgressBar(String message, long id)
2773 if (progressBars == null)
2775 progressBars = new Hashtable<>();
2776 progressBarHandlers = new Hashtable<>();
2779 if (progressBars.get(new Long(id)) != null)
2781 JPanel panel = progressBars.remove(new Long(id));
2782 if (progressBarHandlers.contains(new Long(id)))
2784 progressBarHandlers.remove(new Long(id));
2786 removeProgressPanel(panel);
2790 progressBars.put(new Long(id), addProgressPanel(message));
2797 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2798 * jalview.gui.IProgressIndicatorHandler)
2801 public void registerHandler(final long id,
2802 final IProgressIndicatorHandler handler)
2804 if (progressBarHandlers == null
2805 || !progressBars.containsKey(new Long(id)))
2807 throw new Error(MessageManager.getString(
2808 "error.call_setprogressbar_before_registering_handler"));
2810 progressBarHandlers.put(new Long(id), handler);
2811 final JPanel progressPanel = progressBars.get(new Long(id));
2812 if (handler.canCancel())
2814 JButton cancel = new JButton(
2815 MessageManager.getString("action.cancel"));
2816 final IProgressIndicator us = this;
2817 cancel.addActionListener(new ActionListener()
2821 public void actionPerformed(ActionEvent e)
2823 handler.cancelActivity(id);
2824 us.setProgressBar(MessageManager
2825 .formatMessage("label.cancelled_params", new Object[]
2826 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2830 progressPanel.add(cancel, BorderLayout.EAST);
2836 * @return true if any progress bars are still active
2839 public boolean operationInProgress()
2841 if (progressBars != null && progressBars.size() > 0)
2849 * This will return the first AlignFrame holding the given viewport instance.
2850 * It will break if there are more than one AlignFrames viewing a particular
2854 * @return alignFrame for viewport
2856 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2858 if (desktop != null)
2860 AlignmentPanel[] aps = getAlignmentPanels(
2861 viewport.getSequenceSetId());
2862 for (int panel = 0; aps != null && panel < aps.length; panel++)
2864 if (aps[panel] != null && aps[panel].av == viewport)
2866 return aps[panel].alignFrame;
2873 public VamsasApplication getVamsasApplication()
2880 * flag set if jalview GUI is being operated programmatically
2882 private boolean inBatchMode = false;
2885 * check if jalview GUI is being operated programmatically
2887 * @return inBatchMode
2889 public boolean isInBatchMode()
2895 * set flag if jalview GUI is being operated programmatically
2897 * @param inBatchMode
2899 public void setInBatchMode(boolean inBatchMode)
2901 this.inBatchMode = inBatchMode;
2904 public void startServiceDiscovery()
2906 startServiceDiscovery(false);
2909 public void startServiceDiscovery(boolean blocking)
2911 boolean alive = true;
2912 Thread t0 = null, t1 = null, t2 = null;
2913 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2916 // todo: changesupport handlers need to be transferred
2917 if (discoverer == null)
2919 discoverer = new jalview.ws.jws1.Discoverer();
2920 // register PCS handler for desktop.
2921 discoverer.addPropertyChangeListener(changeSupport);
2923 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2924 // until we phase out completely
2925 (t0 = new Thread(discoverer)).start();
2928 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2930 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2931 .startDiscoverer(changeSupport);
2935 // TODO: do rest service discovery
2944 } catch (Exception e)
2947 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2948 || (t3 != null && t3.isAlive())
2949 || (t0 != null && t0.isAlive());
2955 * called to check if the service discovery process completed successfully.
2959 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2961 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2963 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2964 .getErrorMessages();
2967 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
2969 if (serviceChangedDialog == null)
2971 // only run if we aren't already displaying one of these.
2972 addDialogThread(serviceChangedDialog = new Runnable()
2979 * JalviewDialog jd =new JalviewDialog() {
2981 * @Override protected void cancelPressed() { // TODO
2982 * Auto-generated method stub
2984 * }@Override protected void okPressed() { // TODO
2985 * Auto-generated method stub
2987 * }@Override protected void raiseClosed() { // TODO
2988 * Auto-generated method stub
2990 * } }; jd.initDialogFrame(new
2991 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
2992 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
2993 * + " or mis-configured HTTP proxy settings.<br/>" +
2994 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
2996 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
2997 * ), true, true, "Web Service Configuration Problem", 450,
3000 * jd.waitForInput();
3002 JvOptionPane.showConfirmDialog(Desktop.desktop,
3003 new JLabel("<html><table width=\"450\"><tr><td>"
3004 + ermsg + "</td></tr></table>"
3005 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3006 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3007 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3008 + " Tools->Preferences dialog box to change them.</p></html>"),
3009 "Web Service Configuration Problem",
3010 JvOptionPane.DEFAULT_OPTION,
3011 JvOptionPane.ERROR_MESSAGE);
3012 serviceChangedDialog = null;
3021 "Errors reported by JABA discovery service. Check web services preferences.\n"
3028 private Runnable serviceChangedDialog = null;
3031 * start a thread to open a URL in the configured browser. Pops up a warning
3032 * dialog to the user if there is an exception when calling out to the browser
3037 public static void showUrl(final String url)
3039 showUrl(url, Desktop.instance);
3043 * Like showUrl but allows progress handler to be specified
3047 * (null) or object implementing IProgressIndicator
3049 public static void showUrl(final String url,
3050 final IProgressIndicator progress)
3052 new Thread(new Runnable()
3059 if (progress != null)
3061 progress.setProgressBar(MessageManager
3062 .formatMessage("status.opening_params", new Object[]
3063 { url }), this.hashCode());
3065 jalview.util.BrowserLauncher.openURL(url);
3066 } catch (Exception ex)
3068 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3070 .getString("label.web_browser_not_found_unix"),
3071 MessageManager.getString("label.web_browser_not_found"),
3072 JvOptionPane.WARNING_MESSAGE);
3074 ex.printStackTrace();
3076 if (progress != null)
3078 progress.setProgressBar(null, this.hashCode());
3084 public static WsParamSetManager wsparamManager = null;
3086 public static ParamManager getUserParameterStore()
3088 if (wsparamManager == null)
3090 wsparamManager = new WsParamSetManager();
3092 return wsparamManager;
3096 * static hyperlink handler proxy method for use by Jalview's internal windows
3100 public static void hyperlinkUpdate(HyperlinkEvent e)
3102 if (e.getEventType() == EventType.ACTIVATED)
3107 url = e.getURL().toString();
3108 Desktop.showUrl(url);
3109 } catch (Exception x)
3113 if (Cache.log != null)
3115 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3120 "Couldn't handle string " + url + " as a URL.");
3123 // ignore any exceptions due to dud links.
3130 * single thread that handles display of dialogs to user.
3132 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3135 * flag indicating if dialogExecutor should try to acquire a permit
3137 private volatile boolean dialogPause = true;
3142 private java.util.concurrent.Semaphore block = new Semaphore(0);
3144 private static groovy.ui.Console groovyConsole;
3147 * add another dialog thread to the queue
3151 public void addDialogThread(final Runnable prompter)
3153 dialogExecutor.submit(new Runnable()
3163 } catch (InterruptedException x)
3168 if (instance == null)
3174 SwingUtilities.invokeAndWait(prompter);
3175 } catch (Exception q)
3177 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3183 public void startDialogQueue()
3185 // set the flag so we don't pause waiting for another permit and semaphore
3186 // the current task to begin
3187 dialogPause = false;
3192 protected void snapShotWindow_actionPerformed(ActionEvent e)
3196 ImageMaker im = new jalview.util.ImageMaker(
3197 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3198 getHeight(), of = new File("Jalview_snapshot"
3199 + System.currentTimeMillis() + ".eps"),
3200 "View of desktop", null, 0, false);
3203 paintAll(im.getGraphics());
3205 } catch (Exception q)
3207 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3211 Cache.log.info("Successfully written snapshot to file "
3212 + of.getAbsolutePath());
3216 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3217 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3218 * and location last time the view was expanded (if any). However it does not
3219 * remember the split pane divider location - this is set to match the
3220 * 'exploding' frame.
3224 public void explodeViews(SplitFrame sf)
3226 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3227 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3228 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3230 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3232 int viewCount = topPanels.size();
3239 * Processing in reverse order works, forwards order leaves the first panels
3240 * not visible. I don't know why!
3242 for (int i = viewCount - 1; i >= 0; i--)
3245 * Make new top and bottom frames. These take over the respective
3246 * AlignmentPanel objects, including their AlignmentViewports, so the
3247 * cdna/protein relationships between the viewports is carried over to the
3250 * explodedGeometry holds the (x, y) position of the previously exploded
3251 * SplitFrame, and the (width, height) of the AlignFrame component
3253 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3254 AlignFrame newTopFrame = new AlignFrame(topPanel);
3255 newTopFrame.setSize(oldTopFrame.getSize());
3256 newTopFrame.setVisible(true);
3257 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3258 .getExplodedGeometry();
3259 if (geometry != null)
3261 newTopFrame.setSize(geometry.getSize());
3264 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3265 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3266 newBottomFrame.setSize(oldBottomFrame.getSize());
3267 newBottomFrame.setVisible(true);
3268 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3269 .getExplodedGeometry();
3270 if (geometry != null)
3272 newBottomFrame.setSize(geometry.getSize());
3275 topPanel.av.setGatherViewsHere(false);
3276 bottomPanel.av.setGatherViewsHere(false);
3277 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3279 if (geometry != null)
3281 splitFrame.setLocation(geometry.getLocation());
3283 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3287 * Clear references to the panels (now relocated in the new SplitFrames)
3288 * before closing the old SplitFrame.
3291 bottomPanels.clear();
3296 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3297 * back into the given SplitFrame as additional views. Note that the gathered
3298 * frames may themselves have multiple views.
3302 public void gatherViews(GSplitFrame source)
3305 * special handling of explodedGeometry for a view within a SplitFrame: - it
3306 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3307 * height) of the AlignFrame component
3309 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3310 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3311 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3312 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3313 myBottomFrame.viewport
3314 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3315 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3316 myTopFrame.viewport.setGatherViewsHere(true);
3317 myBottomFrame.viewport.setGatherViewsHere(true);
3318 String topViewId = myTopFrame.viewport.getSequenceSetId();
3319 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3321 JInternalFrame[] frames = desktop.getAllFrames();
3322 for (JInternalFrame frame : frames)
3324 if (frame instanceof SplitFrame && frame != source)
3326 SplitFrame sf = (SplitFrame) frame;
3327 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3328 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3329 boolean gatherThis = false;
3330 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3332 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3333 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3334 if (topViewId.equals(topPanel.av.getSequenceSetId())
3335 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3338 topPanel.av.setGatherViewsHere(false);
3339 bottomPanel.av.setGatherViewsHere(false);
3340 topPanel.av.setExplodedGeometry(
3341 new Rectangle(sf.getLocation(), topFrame.getSize()));
3342 bottomPanel.av.setExplodedGeometry(
3343 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3344 myTopFrame.addAlignmentPanel(topPanel, false);
3345 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3351 topFrame.getAlignPanels().clear();
3352 bottomFrame.getAlignPanels().clear();
3359 * The dust settles...give focus to the tab we did this from.
3361 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3364 public static groovy.ui.Console getGroovyConsole()
3366 return groovyConsole;
3370 * handles the payload of a drag and drop event.
3372 * TODO refactor to desktop utilities class
3375 * - Data source strings extracted from the drop event
3377 * - protocol for each data source extracted from the drop event
3381 * - the payload from the drop event
3384 public static void transferFromDropTarget(List<String> files,
3385 List<DataSourceType> protocols, DropTargetDropEvent evt,
3386 Transferable t) throws Exception
3389 DataFlavor uriListFlavor = new DataFlavor(
3390 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3393 urlFlavour = new DataFlavor(
3394 "application/x-java-url; class=java.net.URL");
3395 } catch (ClassNotFoundException cfe)
3397 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3400 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3405 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3406 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3407 // means url may be null.
3410 protocols.add(DataSourceType.URL);
3411 files.add(url.toString());
3412 Cache.log.debug("Drop handled as URL dataflavor "
3413 + files.get(files.size() - 1));
3418 if (Platform.isAMac())
3421 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3425 } catch (Throwable ex)
3427 Cache.log.debug("URL drop handler failed.", ex);
3430 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3432 // Works on Windows and MacOSX
3433 Cache.log.debug("Drop handled as javaFileListFlavor");
3434 for (Object file : (List) t
3435 .getTransferData(DataFlavor.javaFileListFlavor))
3437 files.add(((File) file).toString());
3438 protocols.add(DataSourceType.FILE);
3443 // Unix like behaviour
3444 boolean added = false;
3446 if (t.isDataFlavorSupported(uriListFlavor))
3448 Cache.log.debug("Drop handled as uriListFlavor");
3449 // This is used by Unix drag system
3450 data = (String) t.getTransferData(uriListFlavor);
3454 // fallback to text: workaround - on OSX where there's a JVM bug
3455 Cache.log.debug("standard URIListFlavor failed. Trying text");
3456 // try text fallback
3457 DataFlavor textDf = new DataFlavor(
3458 "text/plain;class=java.lang.String");
3459 if (t.isDataFlavorSupported(textDf))
3461 data = (String) t.getTransferData(textDf);
3464 Cache.log.debug("Plain text drop content returned "
3465 + (data == null ? "Null - failed" : data));
3470 while (protocols.size() < files.size())
3472 Cache.log.debug("Adding missing FILE protocol for "
3473 + files.get(protocols.size()));
3474 protocols.add(DataSourceType.FILE);
3476 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3477 data, "\r\n"); st.hasMoreTokens();)
3480 String s = st.nextToken();
3481 if (s.startsWith("#"))
3483 // the line is a comment (as per the RFC 2483)
3486 java.net.URI uri = new java.net.URI(s);
3487 if (uri.getScheme().toLowerCase().startsWith("http"))
3489 protocols.add(DataSourceType.URL);
3490 files.add(uri.toString());
3494 // otherwise preserve old behaviour: catch all for file objects
3495 java.io.File file = new java.io.File(uri);
3496 protocols.add(DataSourceType.FILE);
3497 files.add(file.toString());
3502 if (Cache.log.isDebugEnabled())
3504 if (data == null || !added)
3507 if (t.getTransferDataFlavors() != null
3508 && t.getTransferDataFlavors().length > 0)
3511 "Couldn't resolve drop data. Here are the supported flavors:");
3512 for (DataFlavor fl : t.getTransferDataFlavors())
3515 "Supported transfer dataflavor: " + fl.toString());
3516 Object df = t.getTransferData(fl);
3519 Cache.log.debug("Retrieves: " + df);
3523 Cache.log.debug("Retrieved nothing");
3529 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3535 if (Platform.isWindows())
3538 Cache.log.debug("Scanning dropped content for Windows Link Files");
3540 // resolve any .lnk files in the file drop
3541 for (int f = 0; f < files.size(); f++)
3543 String source = files.get(f).toLowerCase();
3544 if (protocols.get(f).equals(DataSourceType.FILE)
3545 && (source.endsWith(".lnk") || source.endsWith(".url")
3546 || source.endsWith(".site")))
3549 File lf = new File(files.get(f));
3550 // process link file to get a URL
3551 Cache.log.debug("Found potential link file: " + lf);
3552 WindowsShortcut wscfile = new WindowsShortcut(lf);
3553 String fullname = wscfile.getRealFilename();
3554 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3555 files.set(f, fullname);
3556 Cache.log.debug("Parsed real filename " + fullname
3557 + " to extract protocol: " + protocols.get(f));
3559 catch (Exception ex)
3561 Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
3569 * Sets the Preferences property for experimental features to True or False
3570 * depending on the state of the controlling menu item
3573 protected void showExperimental_actionPerformed(boolean selected)
3575 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3579 * Answers a (possibly empty) list of any structure viewer frames (currently
3580 * for either Jmol or Chimera) which are currently open. This may optionally
3581 * be restricted to viewers of a specified class, or viewers linked to a
3582 * specified alignment panel.
3585 * if not null, only return viewers linked to this panel
3586 * @param structureViewerClass
3587 * if not null, only return viewers of this class
3590 public List<StructureViewerBase> getStructureViewers(
3591 AlignmentPanel apanel,
3592 Class<? extends StructureViewerBase> structureViewerClass)
3594 List<StructureViewerBase> result = new ArrayList<>();
3595 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3597 for (JInternalFrame frame : frames)
3599 if (frame instanceof StructureViewerBase)
3601 if (structureViewerClass == null
3602 || structureViewerClass.isInstance(frame))
3605 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3607 result.add((StructureViewerBase) frame);