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.IOException;
85 import java.util.ArrayList;
86 import java.util.Hashtable;
87 import java.util.List;
88 import java.util.ListIterator;
89 import java.util.StringTokenizer;
90 import java.util.Vector;
91 import java.util.concurrent.ExecutorService;
92 import java.util.concurrent.Executors;
93 import java.util.concurrent.Semaphore;
95 import javax.swing.AbstractAction;
96 import javax.swing.Action;
97 import javax.swing.ActionMap;
98 import javax.swing.Box;
99 import javax.swing.BoxLayout;
100 import javax.swing.DefaultDesktopManager;
101 import javax.swing.DesktopManager;
102 import javax.swing.InputMap;
103 import javax.swing.JButton;
104 import javax.swing.JCheckBox;
105 import javax.swing.JComboBox;
106 import javax.swing.JComponent;
107 import javax.swing.JDesktopPane;
108 import javax.swing.JFrame;
109 import javax.swing.JInternalFrame;
110 import javax.swing.JLabel;
111 import javax.swing.JMenuItem;
112 import javax.swing.JPanel;
113 import javax.swing.JPopupMenu;
114 import javax.swing.JProgressBar;
115 import javax.swing.KeyStroke;
116 import javax.swing.SwingUtilities;
117 import javax.swing.event.HyperlinkEvent;
118 import javax.swing.event.HyperlinkEvent.EventType;
119 import javax.swing.event.InternalFrameAdapter;
120 import javax.swing.event.InternalFrameEvent;
121 import javax.swing.event.MenuEvent;
122 import javax.swing.event.MenuListener;
124 import org.stackoverflowusers.file.WindowsShortcut;
131 * @version $Revision: 1.155 $
133 public class Desktop extends jalview.jbgui.GDesktop
134 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
135 jalview.api.StructureSelectionManagerProvider
137 private static int DEFAULT_MIN_WIDTH = 300;
139 private static int DEFAULT_MIN_HEIGHT = 250;
141 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
143 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
145 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
147 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
150 * news reader - null if it was never started.
152 private BlogReader jvnews = null;
154 private File projectFile;
158 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
160 public void addJalviewPropertyChangeListener(
161 PropertyChangeListener listener)
163 changeSupport.addJalviewPropertyChangeListener(listener);
167 * @param propertyName
169 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
170 * java.beans.PropertyChangeListener)
172 public void addJalviewPropertyChangeListener(String propertyName,
173 PropertyChangeListener listener)
175 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
179 * @param propertyName
181 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
182 * java.beans.PropertyChangeListener)
184 public void removeJalviewPropertyChangeListener(String propertyName,
185 PropertyChangeListener listener)
187 changeSupport.removeJalviewPropertyChangeListener(propertyName,
191 /** Singleton Desktop instance */
192 public static Desktop instance;
194 public static MyDesktopPane desktop;
196 static int openFrameCount = 0;
198 static final int xOffset = 30;
200 static final int yOffset = 30;
202 public static jalview.ws.jws1.Discoverer discoverer;
204 public static Object[] jalviewClipboard;
206 public static boolean internalCopy = false;
208 static int fileLoadingCount = 0;
210 class MyDesktopManager implements DesktopManager
213 private DesktopManager delegate;
215 public MyDesktopManager(DesktopManager delegate)
217 this.delegate = delegate;
221 public void activateFrame(JInternalFrame f)
225 delegate.activateFrame(f);
226 } catch (NullPointerException npe)
228 Point p = getMousePosition();
229 instance.showPasteMenu(p.x, p.y);
234 public void beginDraggingFrame(JComponent f)
236 delegate.beginDraggingFrame(f);
240 public void beginResizingFrame(JComponent f, int direction)
242 delegate.beginResizingFrame(f, direction);
246 public void closeFrame(JInternalFrame f)
248 delegate.closeFrame(f);
252 public void deactivateFrame(JInternalFrame f)
254 delegate.deactivateFrame(f);
258 public void deiconifyFrame(JInternalFrame f)
260 delegate.deiconifyFrame(f);
264 public void dragFrame(JComponent f, int newX, int newY)
270 delegate.dragFrame(f, newX, newY);
274 public void endDraggingFrame(JComponent f)
276 delegate.endDraggingFrame(f);
281 public void endResizingFrame(JComponent f)
283 delegate.endResizingFrame(f);
288 public void iconifyFrame(JInternalFrame f)
290 delegate.iconifyFrame(f);
294 public void maximizeFrame(JInternalFrame f)
296 delegate.maximizeFrame(f);
300 public void minimizeFrame(JInternalFrame f)
302 delegate.minimizeFrame(f);
306 public void openFrame(JInternalFrame f)
308 delegate.openFrame(f);
312 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
319 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
323 public void setBoundsForFrame(JComponent f, int newX, int newY,
324 int newWidth, int newHeight)
326 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
329 // All other methods, simply delegate
334 * Creates a new Desktop object.
339 * A note to implementors. It is ESSENTIAL that any activities that might
340 * block are spawned off as threads rather than waited for during this
344 doVamsasClientCheck();
346 doConfigureStructurePrefs();
347 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
348 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
349 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
351 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
353 desktop = new MyDesktopPane(selmemusage);
354 showMemusage.setSelected(selmemusage);
355 desktop.setBackground(Color.white);
356 getContentPane().setLayout(new BorderLayout());
357 // alternate config - have scrollbars - see notes in JAL-153
358 // JScrollPane sp = new JScrollPane();
359 // sp.getViewport().setView(desktop);
360 // getContentPane().add(sp, BorderLayout.CENTER);
361 getContentPane().add(desktop, BorderLayout.CENTER);
362 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
364 // This line prevents Windows Look&Feel resizing all new windows to maximum
365 // if previous window was maximised
366 desktop.setDesktopManager(
367 new MyDesktopManager(
368 (Platform.isWindows() ? new DefaultDesktopManager()
370 ? new AquaInternalFrameManager(
371 desktop.getDesktopManager())
372 : desktop.getDesktopManager())));
374 Rectangle dims = getLastKnownDimensions("");
381 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
382 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
385 jconsole = new Console(this, showjconsole);
386 // add essential build information
388 "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
389 + "\n" + "Jalview Installation: "
390 + jalview.bin.Cache.getDefault("INSTALLATION",
392 + "\n" + "Build Date: "
393 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
394 + "\n" + "Java version: "
395 + System.getProperty("java.version") + "\n"
396 + System.getProperty("os.arch") + " "
397 + System.getProperty("os.name") + " "
398 + System.getProperty("os.version"));
400 showConsole(showjconsole);
402 showNews.setVisible(false);
404 experimentalFeatures.setSelected(showExperimental());
406 getIdentifiersOrgData();
410 this.addWindowListener(new WindowAdapter()
413 public void windowClosing(WindowEvent evt)
420 this.addMouseListener(ma = new MouseAdapter()
423 public void mousePressed(MouseEvent evt)
425 if (evt.isPopupTrigger()) // Mac
427 showPasteMenu(evt.getX(), evt.getY());
432 public void mouseReleased(MouseEvent evt)
434 if (evt.isPopupTrigger()) // Windows
436 showPasteMenu(evt.getX(), evt.getY());
440 desktop.addMouseListener(ma);
442 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
443 // Spawn a thread that shows the splashscreen
444 SwingUtilities.invokeLater(new Runnable()
453 // Thread off a new instance of the file chooser - this reduces the time it
454 // takes to open it later on.
455 new Thread(new Runnable()
460 Cache.log.debug("Filechooser init thread started.");
461 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
462 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
464 Cache.log.debug("Filechooser init thread finished.");
467 // Add the service change listener
468 changeSupport.addJalviewPropertyChangeListener("services",
469 new PropertyChangeListener()
473 public void propertyChange(PropertyChangeEvent evt)
475 Cache.log.debug("Firing service changed event for "
476 + evt.getNewValue());
477 JalviewServicesChanged(evt);
484 * Answers true if user preferences to enable experimental features is True
489 public boolean showExperimental()
491 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
492 Boolean.FALSE.toString());
493 return Boolean.valueOf(experimental).booleanValue();
496 public void doConfigureStructurePrefs()
498 // configure services
499 StructureSelectionManager ssm = StructureSelectionManager
500 .getStructureSelectionManager(this);
501 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
503 ssm.setAddTempFacAnnot(jalview.bin.Cache
504 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
505 ssm.setProcessSecondaryStructure(jalview.bin.Cache
506 .getDefault(Preferences.STRUCT_FROM_PDB, true));
507 ssm.setSecStructServices(
508 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
512 ssm.setAddTempFacAnnot(false);
513 ssm.setProcessSecondaryStructure(false);
514 ssm.setSecStructServices(false);
518 public void checkForNews()
520 final Desktop me = this;
521 // Thread off the news reader, in case there are connection problems.
522 new Thread(new Runnable()
527 Cache.log.debug("Starting news thread.");
529 jvnews = new BlogReader(me);
530 showNews.setVisible(true);
531 Cache.log.debug("Completed news thread.");
536 public void getIdentifiersOrgData()
538 // Thread off the identifiers fetcher
539 new Thread(new Runnable()
544 Cache.log.debug("Downloading data from identifiers.org");
545 UrlDownloadClient client = new UrlDownloadClient();
548 client.download(IdOrgSettings.getUrl(),
549 IdOrgSettings.getDownloadLocation());
550 } catch (IOException e)
552 Cache.log.debug("Exception downloading identifiers.org data"
561 protected void showNews_actionPerformed(ActionEvent e)
563 showNews(showNews.isSelected());
566 void showNews(boolean visible)
569 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
570 showNews.setSelected(visible);
571 if (visible && !jvnews.isVisible())
573 new Thread(new Runnable()
578 long now = System.currentTimeMillis();
579 Desktop.instance.setProgressBar(
580 MessageManager.getString("status.refreshing_news"),
582 jvnews.refreshNews();
583 Desktop.instance.setProgressBar(null, now);
592 * recover the last known dimensions for a jalview window
595 * - empty string is desktop, all other windows have unique prefix
596 * @return null or last known dimensions scaled to current geometry (if last
597 * window geom was known)
599 Rectangle getLastKnownDimensions(String windowName)
601 // TODO: lock aspect ratio for scaling desktop Bug #0058199
602 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
603 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
604 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
605 String width = jalview.bin.Cache
606 .getProperty(windowName + "SCREEN_WIDTH");
607 String height = jalview.bin.Cache
608 .getProperty(windowName + "SCREEN_HEIGHT");
609 if ((x != null) && (y != null) && (width != null) && (height != null))
611 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
612 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
613 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
615 // attempt #1 - try to cope with change in screen geometry - this
616 // version doesn't preserve original jv aspect ratio.
617 // take ratio of current screen size vs original screen size.
618 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
619 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
620 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
621 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
622 // rescale the bounds depending upon the current screen geometry.
623 ix = (int) (ix * sw);
624 iw = (int) (iw * sw);
625 iy = (int) (iy * sh);
626 ih = (int) (ih * sh);
627 while (ix >= screenSize.width)
629 jalview.bin.Cache.log.debug(
630 "Window geometry location recall error: shifting horizontal to within screenbounds.");
631 ix -= screenSize.width;
633 while (iy >= screenSize.height)
635 jalview.bin.Cache.log.debug(
636 "Window geometry location recall error: shifting vertical to within screenbounds.");
637 iy -= screenSize.height;
639 jalview.bin.Cache.log.debug(
640 "Got last known dimensions for " + windowName + ": x:" + ix
641 + " y:" + iy + " width:" + iw + " height:" + ih);
643 // return dimensions for new instance
644 return new Rectangle(ix, iy, iw, ih);
649 private void doVamsasClientCheck()
651 if (jalview.bin.Cache.vamsasJarsPresent())
653 setupVamsasDisconnectedGui();
654 VamsasMenu.setVisible(true);
655 final Desktop us = this;
656 VamsasMenu.addMenuListener(new MenuListener()
658 // this listener remembers when the menu was first selected, and
659 // doesn't rebuild the session list until it has been cleared and
661 boolean refresh = true;
664 public void menuCanceled(MenuEvent e)
670 public void menuDeselected(MenuEvent e)
676 public void menuSelected(MenuEvent e)
680 us.buildVamsasStMenu();
685 vamsasStart.setVisible(true);
689 void showPasteMenu(int x, int y)
691 JPopupMenu popup = new JPopupMenu();
692 JMenuItem item = new JMenuItem(
693 MessageManager.getString("label.paste_new_window"));
694 item.addActionListener(new ActionListener()
697 public void actionPerformed(ActionEvent evt)
704 popup.show(this, x, y);
711 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
712 Transferable contents = c.getContents(this);
714 if (contents != null)
716 String file = (String) contents
717 .getTransferData(DataFlavor.stringFlavor);
719 FileFormatI format = new IdentifyFile().identify(file,
720 DataSourceType.PASTE);
722 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
725 } catch (Exception ex)
728 "Unable to paste alignment from system clipboard:\n" + ex);
733 * Adds and opens the given frame to the desktop
744 public static synchronized void addInternalFrame(
745 final JInternalFrame frame, String title, int w, int h)
747 addInternalFrame(frame, title, true, w, h, true, false);
751 * Add an internal frame to the Jalview desktop
758 * When true, display frame immediately, otherwise, caller must call
759 * setVisible themselves.
765 public static synchronized void addInternalFrame(
766 final JInternalFrame frame, String title, boolean makeVisible,
769 addInternalFrame(frame, title, makeVisible, w, h, true, false);
773 * Add an internal frame to the Jalview desktop and make it visible
786 public static synchronized void addInternalFrame(
787 final JInternalFrame frame, String title, int w, int h,
790 addInternalFrame(frame, title, true, w, h, resizable, false);
794 * Add an internal frame to the Jalview desktop
801 * When true, display frame immediately, otherwise, caller must call
802 * setVisible themselves.
809 * @param ignoreMinSize
810 * Do not set the default minimum size for frame
812 public static synchronized void addInternalFrame(
813 final JInternalFrame frame, String title, boolean makeVisible,
814 int w, int h, boolean resizable, boolean ignoreMinSize)
817 // TODO: allow callers to determine X and Y position of frame (eg. via
819 // TODO: consider fixing method to update entries in the window submenu with
820 // the current window title
822 frame.setTitle(title);
823 if (frame.getWidth() < 1 || frame.getHeight() < 1)
827 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
828 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
829 // IF JALVIEW IS RUNNING HEADLESS
830 // ///////////////////////////////////////////////
831 if (instance == null || (System.getProperty("java.awt.headless") != null
832 && System.getProperty("java.awt.headless").equals("true")))
841 frame.setMinimumSize(
842 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
844 // Set default dimension for Alignment Frame window.
845 // The Alignment Frame window could be added from a number of places,
847 // I did this here in order not to miss out on any Alignment frame.
848 if (frame instanceof AlignFrame)
850 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
851 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
855 frame.setVisible(makeVisible);
856 frame.setClosable(true);
857 frame.setResizable(resizable);
858 frame.setMaximizable(resizable);
859 frame.setIconifiable(resizable);
860 frame.setOpaque(false);
862 if (frame.getX() < 1 && frame.getY() < 1)
864 frame.setLocation(xOffset * openFrameCount,
865 yOffset * ((openFrameCount - 1) % 10) + yOffset);
869 * add an entry for the new frame in the Window menu
870 * (and remove it when the frame is closed)
872 final JMenuItem menuItem = new JMenuItem(title);
873 frame.addInternalFrameListener(new InternalFrameAdapter()
876 public void internalFrameActivated(InternalFrameEvent evt)
878 JInternalFrame itf = desktop.getSelectedFrame();
881 if (itf instanceof AlignFrame)
883 Jalview.setCurrentAlignFrame((AlignFrame) itf);
890 public void internalFrameClosed(InternalFrameEvent evt)
892 PaintRefresher.RemoveComponent(frame);
895 * defensive check to prevent frames being
896 * added half off the window
898 if (openFrameCount > 0)
904 * ensure no reference to alignFrame retained by menu item listener
906 if (menuItem.getActionListeners().length > 0)
908 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
910 windowMenu.remove(menuItem);
914 menuItem.addActionListener(new ActionListener()
917 public void actionPerformed(ActionEvent e)
921 frame.setSelected(true);
922 frame.setIcon(false);
923 } catch (java.beans.PropertyVetoException ex)
930 setKeyBindings(frame);
934 windowMenu.add(menuItem);
939 frame.setSelected(true);
940 frame.requestFocus();
941 } catch (java.beans.PropertyVetoException ve)
943 } catch (java.lang.ClassCastException cex)
946 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
952 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
957 private static void setKeyBindings(JInternalFrame frame)
959 @SuppressWarnings("serial")
960 final Action closeAction = new AbstractAction()
963 public void actionPerformed(ActionEvent e)
970 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
972 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
973 InputEvent.CTRL_DOWN_MASK);
974 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
975 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
977 InputMap inputMap = frame
978 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
979 String ctrlW = ctrlWKey.toString();
980 inputMap.put(ctrlWKey, ctrlW);
981 inputMap.put(cmdWKey, ctrlW);
983 ActionMap actionMap = frame.getActionMap();
984 actionMap.put(ctrlW, closeAction);
988 public void lostOwnership(Clipboard clipboard, Transferable contents)
992 Desktop.jalviewClipboard = null;
995 internalCopy = false;
999 public void dragEnter(DropTargetDragEvent evt)
1004 public void dragExit(DropTargetEvent evt)
1009 public void dragOver(DropTargetDragEvent evt)
1014 public void dropActionChanged(DropTargetDragEvent evt)
1025 public void drop(DropTargetDropEvent evt)
1027 boolean success = true;
1028 // JAL-1552 - acceptDrop required before getTransferable call for
1029 // Java's Transferable for native dnd
1030 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1031 Transferable t = evt.getTransferable();
1032 List<String> files = new ArrayList<>();
1033 List<DataSourceType> protocols = new ArrayList<>();
1037 Desktop.transferFromDropTarget(files, protocols, evt, t);
1038 } catch (Exception e)
1040 e.printStackTrace();
1048 for (int i = 0; i < files.size(); i++)
1050 String file = files.get(i).toString();
1051 DataSourceType protocol = (protocols == null)
1052 ? DataSourceType.FILE
1054 FileFormatI format = null;
1056 if (file.endsWith(".jar"))
1058 format = FileFormat.Jalview;
1063 format = new IdentifyFile().identify(file, protocol);
1066 new FileLoader().LoadFile(file, protocol, format);
1069 } catch (Exception ex)
1074 evt.dropComplete(success); // need this to ensure input focus is properly
1075 // transfered to any new windows created
1085 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1087 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1088 JalviewFileChooser chooser = JalviewFileChooser
1089 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1091 chooser.setFileView(new JalviewFileView());
1092 chooser.setDialogTitle(
1093 MessageManager.getString("label.open_local_file"));
1094 chooser.setToolTipText(MessageManager.getString("action.open"));
1096 int value = chooser.showOpenDialog(this);
1098 if (value == JalviewFileChooser.APPROVE_OPTION)
1100 String choice = chooser.getSelectedFile().getPath();
1101 Cache.setProperty("LAST_DIRECTORY",
1102 chooser.getSelectedFile().getParent());
1104 FileFormatI format = chooser.getSelectedFormat();
1107 * Call IdentifyFile to verify the file contains what its extension implies.
1108 * Skip this step for dynamically added file formats, because
1109 * IdentifyFile does not know how to recognise them.
1111 if (FileFormats.getInstance().isIdentifiable(format))
1115 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1116 } catch (FileFormatException e)
1118 // format = null; //??
1122 if (viewport != null)
1124 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1129 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1141 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1143 // This construct allows us to have a wider textfield
1145 JLabel label = new JLabel(
1146 MessageManager.getString("label.input_file_url"));
1147 final JComboBox history = new JComboBox();
1149 JPanel panel = new JPanel(new GridLayout(2, 1));
1152 history.setPreferredSize(new Dimension(400, 20));
1153 history.setEditable(true);
1154 history.addItem("http://www.");
1156 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1160 if (historyItems != null)
1162 st = new StringTokenizer(historyItems, "\t");
1164 while (st.hasMoreTokens())
1166 history.addItem(st.nextElement());
1170 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1171 MessageManager.getString("label.input_alignment_from_url"),
1172 JvOptionPane.OK_CANCEL_OPTION);
1174 if (reply != JvOptionPane.OK_OPTION)
1179 String url = history.getSelectedItem().toString();
1181 if (url.toLowerCase().endsWith(".jar"))
1183 if (viewport != null)
1185 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1186 FileFormat.Jalview);
1190 new FileLoader().LoadFile(url, DataSourceType.URL,
1191 FileFormat.Jalview);
1196 FileFormatI format = null;
1199 format = new IdentifyFile().identify(url, DataSourceType.URL);
1200 } catch (FileFormatException e)
1202 // TODO revise error handling, distinguish between
1203 // URL not found and response not valid
1208 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1209 MessageManager.formatMessage("label.couldnt_locate",
1212 MessageManager.getString("label.url_not_found"),
1213 JvOptionPane.WARNING_MESSAGE);
1218 if (viewport != null)
1220 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1225 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1231 * Opens the CutAndPaste window for the user to paste an alignment in to
1234 * - if not null, the pasted alignment is added to the current
1235 * alignment; if null, to a new alignment window
1238 public void inputTextboxMenuItem_actionPerformed(
1239 AlignmentViewPanel viewPanel)
1241 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1242 cap.setForInput(viewPanel);
1243 Desktop.addInternalFrame(cap,
1244 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1254 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1255 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1257 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1258 screen.height + "");
1259 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1260 getWidth(), getHeight()));
1262 if (jconsole != null)
1264 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1265 jconsole.stopConsole();
1269 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1272 if (dialogExecutor != null)
1274 dialogExecutor.shutdownNow();
1276 closeAll_actionPerformed(null);
1278 if (groovyConsole != null)
1280 // suppress a possible repeat prompt to save script
1281 groovyConsole.setDirty(false);
1282 groovyConsole.exit();
1287 private void storeLastKnownDimensions(String string, Rectangle jc)
1289 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1290 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1291 + " height:" + jc.height);
1293 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1294 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1295 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1296 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1306 public void aboutMenuItem_actionPerformed(ActionEvent e)
1308 // StringBuffer message = getAboutMessage(false);
1309 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1311 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1312 new Thread(new Runnable()
1317 new SplashScreen(true);
1322 public StringBuffer getAboutMessage(boolean shortv)
1324 StringBuffer message = new StringBuffer();
1325 message.append("<html>");
1328 message.append("<h1><strong>Version: "
1329 + jalview.bin.Cache.getProperty("VERSION")
1330 + "</strong></h1>");
1331 message.append("<strong>Last Updated: <em>"
1332 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1333 + "</em></strong>");
1339 message.append("<strong>Version "
1340 + jalview.bin.Cache.getProperty("VERSION")
1341 + "; last updated: "
1342 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1345 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1346 .equals("Checking"))
1348 message.append("<br>...Checking latest version...</br>");
1350 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1351 .equals(jalview.bin.Cache.getProperty("VERSION")))
1353 boolean red = false;
1354 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1355 .indexOf("automated build") == -1)
1358 // Displayed when code version and jnlp version do not match and code
1359 // version is not a development build
1360 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1363 message.append("<br>!! Version "
1364 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1366 + " is available for download from "
1367 + jalview.bin.Cache.getDefault("www.jalview.org",
1368 "http://www.jalview.org")
1372 message.append("</div>");
1375 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1377 "The Jalview Authors (See AUTHORS file for current list)")
1378 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1379 + "<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"
1380 + "<br><br>If you use Jalview, please cite:"
1381 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1382 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1383 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1395 public void documentationMenuItem_actionPerformed(ActionEvent e)
1399 Help.showHelpWindow();
1400 } catch (Exception ex)
1406 public void closeAll_actionPerformed(ActionEvent e)
1408 // TODO show a progress bar while closing?
1409 JInternalFrame[] frames = desktop.getAllFrames();
1410 for (int i = 0; i < frames.length; i++)
1414 frames[i].setClosed(true);
1415 } catch (java.beans.PropertyVetoException ex)
1419 Jalview.setCurrentAlignFrame(null);
1420 System.out.println("ALL CLOSED");
1421 if (v_client != null)
1423 // TODO clear binding to vamsas document objects on close_all
1427 * reset state of singleton objects as appropriate (clear down session state
1428 * when all windows are closed)
1430 StructureSelectionManager ssm = StructureSelectionManager
1431 .getStructureSelectionManager(this);
1439 public void raiseRelated_actionPerformed(ActionEvent e)
1441 reorderAssociatedWindows(false, false);
1445 public void minimizeAssociated_actionPerformed(ActionEvent e)
1447 reorderAssociatedWindows(true, false);
1450 void closeAssociatedWindows()
1452 reorderAssociatedWindows(false, true);
1458 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1462 protected void garbageCollect_actionPerformed(ActionEvent e)
1464 // We simply collect the garbage
1465 jalview.bin.Cache.log.debug("Collecting garbage...");
1467 jalview.bin.Cache.log.debug("Finished garbage collection.");
1474 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1478 protected void showMemusage_actionPerformed(ActionEvent e)
1480 desktop.showMemoryUsage(showMemusage.isSelected());
1487 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1491 protected void showConsole_actionPerformed(ActionEvent e)
1493 showConsole(showConsole.isSelected());
1496 Console jconsole = null;
1499 * control whether the java console is visible or not
1503 void showConsole(boolean selected)
1505 showConsole.setSelected(selected);
1506 // TODO: decide if we should update properties file
1507 Cache.setProperty("SHOW_JAVA_CONSOLE",
1508 Boolean.valueOf(selected).toString());
1509 jconsole.setVisible(selected);
1512 void reorderAssociatedWindows(boolean minimize, boolean close)
1514 JInternalFrame[] frames = desktop.getAllFrames();
1515 if (frames == null || frames.length < 1)
1520 AlignmentViewport source = null, target = null;
1521 if (frames[0] instanceof AlignFrame)
1523 source = ((AlignFrame) frames[0]).getCurrentView();
1525 else if (frames[0] instanceof TreePanel)
1527 source = ((TreePanel) frames[0]).getViewPort();
1529 else if (frames[0] instanceof PCAPanel)
1531 source = ((PCAPanel) frames[0]).av;
1533 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1535 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1540 for (int i = 0; i < frames.length; i++)
1543 if (frames[i] == null)
1547 if (frames[i] instanceof AlignFrame)
1549 target = ((AlignFrame) frames[i]).getCurrentView();
1551 else if (frames[i] instanceof TreePanel)
1553 target = ((TreePanel) frames[i]).getViewPort();
1555 else if (frames[i] instanceof PCAPanel)
1557 target = ((PCAPanel) frames[i]).av;
1559 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1561 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1564 if (source == target)
1570 frames[i].setClosed(true);
1574 frames[i].setIcon(minimize);
1577 frames[i].toFront();
1581 } catch (java.beans.PropertyVetoException ex)
1596 protected void preferences_actionPerformed(ActionEvent e)
1608 public void saveState_actionPerformed(ActionEvent e)
1610 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1613 chooser.setFileView(new JalviewFileView());
1614 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1616 int value = chooser.showSaveDialog(this);
1618 if (value == JalviewFileChooser.APPROVE_OPTION)
1620 final Desktop me = this;
1621 final java.io.File choice = chooser.getSelectedFile();
1622 setProjectFile(choice);
1624 new Thread(new Runnable()
1629 // TODO: refactor to Jalview desktop session controller action.
1630 setProgressBar(MessageManager.formatMessage(
1631 "label.saving_jalview_project", new Object[]
1632 { choice.getName() }), choice.hashCode());
1633 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1634 choice.getParent());
1635 // TODO catch and handle errors for savestate
1636 // TODO prevent user from messing with the Desktop whilst we're saving
1639 new Jalview2XML().saveState(choice);
1640 } catch (OutOfMemoryError oom)
1643 "Whilst saving current state to " + choice.getName(),
1645 } catch (Exception ex)
1648 "Problems whilst trying to save to " + choice.getName(),
1650 JvOptionPane.showMessageDialog(me,
1651 MessageManager.formatMessage(
1652 "label.error_whilst_saving_current_state_to",
1654 { choice.getName() }),
1655 MessageManager.getString("label.couldnt_save_project"),
1656 JvOptionPane.WARNING_MESSAGE);
1658 setProgressBar(null, choice.hashCode());
1664 private void setProjectFile(File choice)
1666 this.projectFile = choice;
1669 public File getProjectFile()
1671 return this.projectFile;
1681 public void loadState_actionPerformed(ActionEvent e)
1683 JalviewFileChooser chooser = new JalviewFileChooser(
1684 Cache.getProperty("LAST_DIRECTORY"), new String[]
1687 { "Jalview Project", "Jalview Project (old)" },
1689 chooser.setFileView(new JalviewFileView());
1690 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1692 int value = chooser.showOpenDialog(this);
1694 if (value == JalviewFileChooser.APPROVE_OPTION)
1696 final File selectedFile = chooser.getSelectedFile();
1697 setProjectFile(selectedFile);
1698 final String choice = selectedFile.getAbsolutePath();
1699 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1700 new Thread(new Runnable()
1705 setProgressBar(MessageManager.formatMessage(
1706 "label.loading_jalview_project", new Object[]
1707 { choice }), choice.hashCode());
1710 new Jalview2XML().loadJalviewAlign(choice);
1711 } catch (OutOfMemoryError oom)
1713 new OOMWarning("Whilst loading project from " + choice, oom);
1714 } catch (Exception ex)
1717 "Problems whilst loading project from " + choice, ex);
1718 JvOptionPane.showMessageDialog(Desktop.desktop,
1719 MessageManager.formatMessage(
1720 "label.error_whilst_loading_project_from",
1723 MessageManager.getString("label.couldnt_load_project"),
1724 JvOptionPane.WARNING_MESSAGE);
1726 setProgressBar(null, choice.hashCode());
1733 public void inputSequence_actionPerformed(ActionEvent e)
1735 new SequenceFetcher(this);
1738 JPanel progressPanel;
1740 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1742 public void startLoading(final String fileName)
1744 if (fileLoadingCount == 0)
1746 fileLoadingPanels.add(addProgressPanel(MessageManager
1747 .formatMessage("label.loading_file", new Object[]
1753 private JPanel addProgressPanel(String string)
1755 if (progressPanel == null)
1757 progressPanel = new JPanel(new GridLayout(1, 1));
1758 totalProgressCount = 0;
1759 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1761 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1762 JProgressBar progressBar = new JProgressBar();
1763 progressBar.setIndeterminate(true);
1765 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1767 thisprogress.add(progressBar, BorderLayout.CENTER);
1768 progressPanel.add(thisprogress);
1769 ((GridLayout) progressPanel.getLayout()).setRows(
1770 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1771 ++totalProgressCount;
1772 instance.validate();
1773 return thisprogress;
1776 int totalProgressCount = 0;
1778 private void removeProgressPanel(JPanel progbar)
1780 if (progressPanel != null)
1782 synchronized (progressPanel)
1784 progressPanel.remove(progbar);
1785 GridLayout gl = (GridLayout) progressPanel.getLayout();
1786 gl.setRows(gl.getRows() - 1);
1787 if (--totalProgressCount < 1)
1789 this.getContentPane().remove(progressPanel);
1790 progressPanel = null;
1797 public void stopLoading()
1800 if (fileLoadingCount < 1)
1802 while (fileLoadingPanels.size() > 0)
1804 removeProgressPanel(fileLoadingPanels.remove(0));
1806 fileLoadingPanels.clear();
1807 fileLoadingCount = 0;
1812 public static int getViewCount(String alignmentId)
1814 AlignmentViewport[] aps = getViewports(alignmentId);
1815 return (aps == null) ? 0 : aps.length;
1820 * @param alignmentId
1821 * - if null, all sets are returned
1822 * @return all AlignmentPanels concerning the alignmentId sequence set
1824 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1826 if (Desktop.desktop == null)
1828 // no frames created and in headless mode
1829 // TODO: verify that frames are recoverable when in headless mode
1832 List<AlignmentPanel> aps = new ArrayList<>();
1833 AlignFrame[] frames = getAlignFrames();
1838 for (AlignFrame af : frames)
1840 for (AlignmentPanel ap : af.alignPanels)
1842 if (alignmentId == null
1843 || alignmentId.equals(ap.av.getSequenceSetId()))
1849 if (aps.size() == 0)
1853 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1858 * get all the viewports on an alignment.
1860 * @param sequenceSetId
1861 * unique alignment id (may be null - all viewports returned in that
1863 * @return all viewports on the alignment bound to sequenceSetId
1865 public static AlignmentViewport[] getViewports(String sequenceSetId)
1867 List<AlignmentViewport> viewp = new ArrayList<>();
1868 if (desktop != null)
1870 AlignFrame[] frames = Desktop.getAlignFrames();
1872 for (AlignFrame afr : frames)
1874 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1875 .equals(sequenceSetId))
1877 if (afr.alignPanels != null)
1879 for (AlignmentPanel ap : afr.alignPanels)
1881 if (sequenceSetId == null
1882 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1890 viewp.add(afr.getViewport());
1894 if (viewp.size() > 0)
1896 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1903 * Explode the views in the given frame into separate AlignFrame
1907 public static void explodeViews(AlignFrame af)
1909 int size = af.alignPanels.size();
1915 for (int i = 0; i < size; i++)
1917 AlignmentPanel ap = af.alignPanels.get(i);
1918 AlignFrame newaf = new AlignFrame(ap);
1921 * Restore the view's last exploded frame geometry if known. Multiple
1922 * views from one exploded frame share and restore the same (frame)
1923 * position and size.
1925 Rectangle geometry = ap.av.getExplodedGeometry();
1926 if (geometry != null)
1928 newaf.setBounds(geometry);
1931 ap.av.setGatherViewsHere(false);
1933 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1934 AlignFrame.DEFAULT_HEIGHT);
1937 af.alignPanels.clear();
1938 af.closeMenuItem_actionPerformed(true);
1943 * Gather expanded views (separate AlignFrame's) with the same sequence set
1944 * identifier back in to this frame as additional views, and close the
1945 * expanded views. Note the expanded frames may themselves have multiple
1946 * views. We take the lot.
1950 public void gatherViews(AlignFrame source)
1952 source.viewport.setGatherViewsHere(true);
1953 source.viewport.setExplodedGeometry(source.getBounds());
1954 JInternalFrame[] frames = desktop.getAllFrames();
1955 String viewId = source.viewport.getSequenceSetId();
1957 for (int t = 0; t < frames.length; t++)
1959 if (frames[t] instanceof AlignFrame && frames[t] != source)
1961 AlignFrame af = (AlignFrame) frames[t];
1962 boolean gatherThis = false;
1963 for (int a = 0; a < af.alignPanels.size(); a++)
1965 AlignmentPanel ap = af.alignPanels.get(a);
1966 if (viewId.equals(ap.av.getSequenceSetId()))
1969 ap.av.setGatherViewsHere(false);
1970 ap.av.setExplodedGeometry(af.getBounds());
1971 source.addAlignmentPanel(ap, false);
1977 af.alignPanels.clear();
1978 af.closeMenuItem_actionPerformed(true);
1985 jalview.gui.VamsasApplication v_client = null;
1988 public void vamsasImport_actionPerformed(ActionEvent e)
1990 if (v_client == null)
1992 // Load and try to start a session.
1993 JalviewFileChooser chooser = new JalviewFileChooser(
1994 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
1996 chooser.setFileView(new JalviewFileView());
1997 chooser.setDialogTitle(
1998 MessageManager.getString("label.open_saved_vamsas_session"));
1999 chooser.setToolTipText(MessageManager.getString(
2000 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2002 int value = chooser.showOpenDialog(this);
2004 if (value == JalviewFileChooser.APPROVE_OPTION)
2006 String fle = chooser.getSelectedFile().toString();
2007 if (!vamsasImport(chooser.getSelectedFile()))
2009 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2010 MessageManager.formatMessage(
2011 "label.couldnt_import_as_vamsas_session",
2015 .getString("label.vamsas_document_import_failed"),
2016 JvOptionPane.ERROR_MESSAGE);
2022 jalview.bin.Cache.log.error(
2023 "Implementation error - load session from a running session is not supported.");
2028 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2031 * @return true if import was a success and a session was started.
2033 public boolean vamsasImport(URL url)
2035 // TODO: create progress bar
2036 if (v_client != null)
2039 jalview.bin.Cache.log.error(
2040 "Implementation error - load session from a running session is not supported.");
2046 // copy the URL content to a temporary local file
2047 // TODO: be a bit cleverer here with nio (?!)
2048 File file = File.createTempFile("vdocfromurl", ".vdj");
2049 FileOutputStream fos = new FileOutputStream(file);
2050 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2051 byte[] buffer = new byte[2048];
2053 while ((ln = bis.read(buffer)) > -1)
2055 fos.write(buffer, 0, ln);
2059 v_client = new jalview.gui.VamsasApplication(this, file,
2060 url.toExternalForm());
2061 } catch (Exception ex)
2063 jalview.bin.Cache.log.error(
2064 "Failed to create new vamsas session from contents of URL "
2069 setupVamsasConnectedGui();
2070 v_client.initial_update(); // TODO: thread ?
2071 return v_client.inSession();
2075 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2078 * @return true if import was a success and a session was started.
2080 public boolean vamsasImport(File file)
2082 if (v_client != null)
2085 jalview.bin.Cache.log.error(
2086 "Implementation error - load session from a running session is not supported.");
2090 setProgressBar(MessageManager.formatMessage(
2091 "status.importing_vamsas_session_from", new Object[]
2092 { file.getName() }), file.hashCode());
2095 v_client = new jalview.gui.VamsasApplication(this, file, null);
2096 } catch (Exception ex)
2098 setProgressBar(MessageManager.formatMessage(
2099 "status.importing_vamsas_session_from", new Object[]
2100 { file.getName() }), file.hashCode());
2101 jalview.bin.Cache.log.error(
2102 "New vamsas session from existing session file failed:", ex);
2105 setupVamsasConnectedGui();
2106 v_client.initial_update(); // TODO: thread ?
2107 setProgressBar(MessageManager.formatMessage(
2108 "status.importing_vamsas_session_from", new Object[]
2109 { file.getName() }), file.hashCode());
2110 return v_client.inSession();
2113 public boolean joinVamsasSession(String mysesid)
2115 if (v_client != null)
2117 throw new Error(MessageManager
2118 .getString("error.try_join_vamsas_session_another"));
2120 if (mysesid == null)
2123 MessageManager.getString("error.invalid_vamsas_session_id"));
2125 v_client = new VamsasApplication(this, mysesid);
2126 setupVamsasConnectedGui();
2127 v_client.initial_update();
2128 return (v_client.inSession());
2132 public void vamsasStart_actionPerformed(ActionEvent e)
2134 if (v_client == null)
2137 // we just start a default session for moment.
2139 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2140 * getProperty("LAST_DIRECTORY"));
2142 * chooser.setFileView(new JalviewFileView());
2143 * chooser.setDialogTitle("Load Vamsas file");
2144 * chooser.setToolTipText("Import");
2146 * int value = chooser.showOpenDialog(this);
2148 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2149 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2151 v_client = new VamsasApplication(this);
2152 setupVamsasConnectedGui();
2153 v_client.initial_update(); // TODO: thread ?
2157 // store current data in session.
2158 v_client.push_update(); // TODO: thread
2162 protected void setupVamsasConnectedGui()
2164 vamsasStart.setText(MessageManager.getString("label.session_update"));
2165 vamsasSave.setVisible(true);
2166 vamsasStop.setVisible(true);
2167 vamsasImport.setVisible(false); // Document import to existing session is
2168 // not possible for vamsas-client-1.0.
2171 protected void setupVamsasDisconnectedGui()
2173 vamsasSave.setVisible(false);
2174 vamsasStop.setVisible(false);
2175 vamsasImport.setVisible(true);
2177 .setText(MessageManager.getString("label.new_vamsas_session"));
2181 public void vamsasStop_actionPerformed(ActionEvent e)
2183 if (v_client != null)
2185 v_client.end_session();
2187 setupVamsasDisconnectedGui();
2191 protected void buildVamsasStMenu()
2193 if (v_client == null)
2195 String[] sess = null;
2198 sess = VamsasApplication.getSessionList();
2199 } catch (Exception e)
2201 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2207 jalview.bin.Cache.log.debug(
2208 "Got current sessions list: " + sess.length + " entries.");
2209 VamsasStMenu.removeAll();
2210 for (int i = 0; i < sess.length; i++)
2212 JMenuItem sessit = new JMenuItem();
2213 sessit.setText(sess[i]);
2214 sessit.setToolTipText(MessageManager
2215 .formatMessage("label.connect_to_session", new Object[]
2217 final Desktop dsktp = this;
2218 final String mysesid = sess[i];
2219 sessit.addActionListener(new ActionListener()
2223 public void actionPerformed(ActionEvent e)
2225 if (dsktp.v_client == null)
2227 Thread rthr = new Thread(new Runnable()
2233 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2234 dsktp.setupVamsasConnectedGui();
2235 dsktp.v_client.initial_update();
2243 VamsasStMenu.add(sessit);
2245 // don't show an empty menu.
2246 VamsasStMenu.setVisible(sess.length > 0);
2251 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2252 VamsasStMenu.removeAll();
2253 VamsasStMenu.setVisible(false);
2258 // Not interested in the content. Just hide ourselves.
2259 VamsasStMenu.setVisible(false);
2264 public void vamsasSave_actionPerformed(ActionEvent e)
2266 if (v_client != null)
2268 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2269 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2272 chooser.setFileView(new JalviewFileView());
2273 chooser.setDialogTitle(MessageManager
2274 .getString("label.save_vamsas_document_archive"));
2276 int value = chooser.showSaveDialog(this);
2278 if (value == JalviewFileChooser.APPROVE_OPTION)
2280 java.io.File choice = chooser.getSelectedFile();
2281 JPanel progpanel = addProgressPanel(MessageManager
2282 .formatMessage("label.saving_vamsas_doc", new Object[]
2283 { choice.getName() }));
2284 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2285 String warnmsg = null;
2286 String warnttl = null;
2289 v_client.vclient.storeDocument(choice);
2292 warnttl = "Serious Problem saving Vamsas Document";
2293 warnmsg = ex.toString();
2294 jalview.bin.Cache.log
2295 .error("Error Whilst saving document to " + choice, ex);
2297 } catch (Exception ex)
2299 warnttl = "Problem saving Vamsas Document.";
2300 warnmsg = ex.toString();
2301 jalview.bin.Cache.log.warn(
2302 "Exception Whilst saving document to " + choice, ex);
2305 removeProgressPanel(progpanel);
2306 if (warnmsg != null)
2308 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2310 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2316 JPanel vamUpdate = null;
2319 * hide vamsas user gui bits when a vamsas document event is being handled.
2322 * true to hide gui, false to reveal gui
2324 public void setVamsasUpdate(boolean b)
2326 Cache.log.debug("Setting gui for Vamsas update "
2327 + (b ? "in progress" : "finished"));
2329 if (vamUpdate != null)
2331 this.removeProgressPanel(vamUpdate);
2335 vamUpdate = this.addProgressPanel(
2336 MessageManager.getString("label.updating_vamsas_session"));
2338 vamsasStart.setVisible(!b);
2339 vamsasStop.setVisible(!b);
2340 vamsasSave.setVisible(!b);
2343 public JInternalFrame[] getAllFrames()
2345 return desktop.getAllFrames();
2349 * Checks the given url to see if it gives a response indicating that the user
2350 * should be informed of a new questionnaire.
2354 public void checkForQuestionnaire(String url)
2356 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2357 // javax.swing.SwingUtilities.invokeLater(jvq);
2358 new Thread(jvq).start();
2361 public void checkURLLinks()
2363 // Thread off the URL link checker
2364 addDialogThread(new Runnable()
2369 if (Cache.getDefault("CHECKURLLINKS", true))
2371 // check what the actual links are - if it's just the default don't
2372 // bother with the warning
2373 List<String> links = Preferences.sequenceUrlLinks
2376 // only need to check links if there is one with a
2377 // SEQUENCE_ID which is not the default EMBL_EBI link
2378 ListIterator<String> li = links.listIterator();
2379 boolean check = false;
2380 List<JLabel> urls = new ArrayList<>();
2381 while (li.hasNext())
2383 String link = li.next();
2384 if (link.contains(SEQUENCE_ID)
2385 && !UrlConstants.isDefaultString(link))
2388 int barPos = link.indexOf("|");
2389 String urlMsg = barPos == -1 ? link
2390 : link.substring(0, barPos) + ": "
2391 + link.substring(barPos + 1);
2392 urls.add(new JLabel(urlMsg));
2400 // ask user to check in case URL links use old style tokens
2401 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2402 JPanel msgPanel = new JPanel();
2403 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2404 msgPanel.add(Box.createVerticalGlue());
2405 JLabel msg = new JLabel(MessageManager
2406 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2407 JLabel msg2 = new JLabel(MessageManager
2408 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2410 for (JLabel url : urls)
2416 final JCheckBox jcb = new JCheckBox(
2417 MessageManager.getString("label.do_not_display_again"));
2418 jcb.addActionListener(new ActionListener()
2421 public void actionPerformed(ActionEvent e)
2423 // update Cache settings for "don't show this again"
2424 boolean showWarningAgain = !jcb.isSelected();
2425 Cache.setProperty("CHECKURLLINKS",
2426 Boolean.valueOf(showWarningAgain).toString());
2431 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2433 .getString("label.SEQUENCE_ID_no_longer_used"),
2434 JvOptionPane.WARNING_MESSAGE);
2441 * Proxy class for JDesktopPane which optionally displays the current memory
2442 * usage and highlights the desktop area with a red bar if free memory runs
2447 public class MyDesktopPane extends JDesktopPane implements Runnable
2450 private static final float ONE_MB = 1048576f;
2452 boolean showMemoryUsage = false;
2456 java.text.NumberFormat df;
2458 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2461 public MyDesktopPane(boolean showMemoryUsage)
2463 showMemoryUsage(showMemoryUsage);
2466 public void showMemoryUsage(boolean showMemory)
2468 this.showMemoryUsage = showMemory;
2471 Thread worker = new Thread(this);
2477 public boolean isShowMemoryUsage()
2479 return showMemoryUsage;
2485 df = java.text.NumberFormat.getNumberInstance();
2486 df.setMaximumFractionDigits(2);
2487 runtime = Runtime.getRuntime();
2489 while (showMemoryUsage)
2493 maxMemory = runtime.maxMemory() / ONE_MB;
2494 allocatedMemory = runtime.totalMemory() / ONE_MB;
2495 freeMemory = runtime.freeMemory() / ONE_MB;
2496 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2498 percentUsage = (totalFreeMemory / maxMemory) * 100;
2500 // if (percentUsage < 20)
2502 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2504 // instance.set.setBorder(border1);
2507 // sleep after showing usage
2509 } catch (Exception ex)
2511 ex.printStackTrace();
2517 public void paintComponent(Graphics g)
2519 if (showMemoryUsage && g != null && df != null)
2521 if (percentUsage < 20)
2523 g.setColor(Color.red);
2525 FontMetrics fm = g.getFontMetrics();
2528 g.drawString(MessageManager.formatMessage("label.memory_stats",
2530 { df.format(totalFreeMemory), df.format(maxMemory),
2531 df.format(percentUsage) }),
2532 10, getHeight() - fm.getHeight());
2540 * Accessor method to quickly get all the AlignmentFrames loaded.
2542 * @return an array of AlignFrame, or null if none found
2544 public static AlignFrame[] getAlignFrames()
2546 if (Jalview.isHeadlessMode())
2548 // Desktop.desktop is null in headless mode
2549 return new AlignFrame[] { Jalview.currentAlignFrame };
2552 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2558 List<AlignFrame> avp = new ArrayList<>();
2560 for (int i = frames.length - 1; i > -1; i--)
2562 if (frames[i] instanceof AlignFrame)
2564 avp.add((AlignFrame) frames[i]);
2566 else if (frames[i] instanceof SplitFrame)
2569 * Also check for a split frame containing an AlignFrame
2571 GSplitFrame sf = (GSplitFrame) frames[i];
2572 if (sf.getTopFrame() instanceof AlignFrame)
2574 avp.add((AlignFrame) sf.getTopFrame());
2576 if (sf.getBottomFrame() instanceof AlignFrame)
2578 avp.add((AlignFrame) sf.getBottomFrame());
2582 if (avp.size() == 0)
2586 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2591 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2595 public GStructureViewer[] getJmols()
2597 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2603 List<GStructureViewer> avp = new ArrayList<>();
2605 for (int i = frames.length - 1; i > -1; i--)
2607 if (frames[i] instanceof AppJmol)
2609 GStructureViewer af = (GStructureViewer) frames[i];
2613 if (avp.size() == 0)
2617 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2622 * Add Groovy Support to Jalview
2625 public void groovyShell_actionPerformed()
2629 openGroovyConsole();
2630 } catch (Exception ex)
2632 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2633 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2635 MessageManager.getString("label.couldnt_create_groovy_shell"),
2636 MessageManager.getString("label.groovy_support_failed"),
2637 JvOptionPane.ERROR_MESSAGE);
2642 * Open the Groovy console
2644 void openGroovyConsole()
2646 if (groovyConsole == null)
2648 groovyConsole = new groovy.ui.Console();
2649 groovyConsole.setVariable("Jalview", this);
2650 groovyConsole.run();
2653 * We allow only one console at a time, so that AlignFrame menu option
2654 * 'Calculate | Run Groovy script' is unambiguous.
2655 * Disable 'Groovy Console', and enable 'Run script', when the console is
2656 * opened, and the reverse when it is closed
2658 Window window = (Window) groovyConsole.getFrame();
2659 window.addWindowListener(new WindowAdapter()
2662 public void windowClosed(WindowEvent e)
2665 * rebind CMD-Q from Groovy Console to Jalview Quit
2668 enableExecuteGroovy(false);
2674 * show Groovy console window (after close and reopen)
2676 ((Window) groovyConsole.getFrame()).setVisible(true);
2679 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2680 * and disable opening a second console
2682 enableExecuteGroovy(true);
2686 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2687 * binding when opened
2689 protected void addQuitHandler()
2691 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2692 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2693 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2695 getRootPane().getActionMap().put("Quit", new AbstractAction()
2698 public void actionPerformed(ActionEvent e)
2706 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2709 * true if Groovy console is open
2711 public void enableExecuteGroovy(boolean enabled)
2714 * disable opening a second Groovy console
2715 * (or re-enable when the console is closed)
2717 groovyShell.setEnabled(!enabled);
2719 AlignFrame[] alignFrames = getAlignFrames();
2720 if (alignFrames != null)
2722 for (AlignFrame af : alignFrames)
2724 af.setGroovyEnabled(enabled);
2730 * Progress bars managed by the IProgressIndicator method.
2732 private Hashtable<Long, JPanel> progressBars;
2734 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2739 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2742 public void setProgressBar(String message, long id)
2744 if (progressBars == null)
2746 progressBars = new Hashtable<>();
2747 progressBarHandlers = new Hashtable<>();
2750 if (progressBars.get(new Long(id)) != null)
2752 JPanel panel = progressBars.remove(new Long(id));
2753 if (progressBarHandlers.contains(new Long(id)))
2755 progressBarHandlers.remove(new Long(id));
2757 removeProgressPanel(panel);
2761 progressBars.put(new Long(id), addProgressPanel(message));
2768 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2769 * jalview.gui.IProgressIndicatorHandler)
2772 public void registerHandler(final long id,
2773 final IProgressIndicatorHandler handler)
2775 if (progressBarHandlers == null
2776 || !progressBars.containsKey(new Long(id)))
2778 throw new Error(MessageManager.getString(
2779 "error.call_setprogressbar_before_registering_handler"));
2781 progressBarHandlers.put(new Long(id), handler);
2782 final JPanel progressPanel = progressBars.get(new Long(id));
2783 if (handler.canCancel())
2785 JButton cancel = new JButton(
2786 MessageManager.getString("action.cancel"));
2787 final IProgressIndicator us = this;
2788 cancel.addActionListener(new ActionListener()
2792 public void actionPerformed(ActionEvent e)
2794 handler.cancelActivity(id);
2795 us.setProgressBar(MessageManager
2796 .formatMessage("label.cancelled_params", new Object[]
2797 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2801 progressPanel.add(cancel, BorderLayout.EAST);
2807 * @return true if any progress bars are still active
2810 public boolean operationInProgress()
2812 if (progressBars != null && progressBars.size() > 0)
2820 * This will return the first AlignFrame holding the given viewport instance.
2821 * It will break if there are more than one AlignFrames viewing a particular
2825 * @return alignFrame for viewport
2827 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2829 if (desktop != null)
2831 AlignmentPanel[] aps = getAlignmentPanels(
2832 viewport.getSequenceSetId());
2833 for (int panel = 0; aps != null && panel < aps.length; panel++)
2835 if (aps[panel] != null && aps[panel].av == viewport)
2837 return aps[panel].alignFrame;
2844 public VamsasApplication getVamsasApplication()
2851 * flag set if jalview GUI is being operated programmatically
2853 private boolean inBatchMode = false;
2856 * check if jalview GUI is being operated programmatically
2858 * @return inBatchMode
2860 public boolean isInBatchMode()
2866 * set flag if jalview GUI is being operated programmatically
2868 * @param inBatchMode
2870 public void setInBatchMode(boolean inBatchMode)
2872 this.inBatchMode = inBatchMode;
2875 public void startServiceDiscovery()
2877 startServiceDiscovery(false);
2880 public void startServiceDiscovery(boolean blocking)
2882 boolean alive = true;
2883 Thread t0 = null, t1 = null, t2 = null;
2884 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2887 // todo: changesupport handlers need to be transferred
2888 if (discoverer == null)
2890 discoverer = new jalview.ws.jws1.Discoverer();
2891 // register PCS handler for desktop.
2892 discoverer.addPropertyChangeListener(changeSupport);
2894 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2895 // until we phase out completely
2896 (t0 = new Thread(discoverer)).start();
2899 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2901 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2902 .startDiscoverer(changeSupport);
2906 // TODO: do rest service discovery
2915 } catch (Exception e)
2918 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2919 || (t3 != null && t3.isAlive())
2920 || (t0 != null && t0.isAlive());
2926 * called to check if the service discovery process completed successfully.
2930 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2932 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2934 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2935 .getErrorMessages();
2938 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
2940 if (serviceChangedDialog == null)
2942 // only run if we aren't already displaying one of these.
2943 addDialogThread(serviceChangedDialog = new Runnable()
2950 * JalviewDialog jd =new JalviewDialog() {
2952 * @Override protected void cancelPressed() { // TODO
2953 * Auto-generated method stub
2955 * }@Override protected void okPressed() { // TODO
2956 * Auto-generated method stub
2958 * }@Override protected void raiseClosed() { // TODO
2959 * Auto-generated method stub
2961 * } }; jd.initDialogFrame(new
2962 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
2963 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
2964 * + " or mis-configured HTTP proxy settings.<br/>" +
2965 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
2967 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
2968 * ), true, true, "Web Service Configuration Problem", 450,
2971 * jd.waitForInput();
2973 JvOptionPane.showConfirmDialog(Desktop.desktop,
2974 new JLabel("<html><table width=\"450\"><tr><td>"
2975 + ermsg + "</td></tr></table>"
2976 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
2977 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
2978 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
2979 + " Tools->Preferences dialog box to change them.</p></html>"),
2980 "Web Service Configuration Problem",
2981 JvOptionPane.DEFAULT_OPTION,
2982 JvOptionPane.ERROR_MESSAGE);
2983 serviceChangedDialog = null;
2992 "Errors reported by JABA discovery service. Check web services preferences.\n"
2999 private Runnable serviceChangedDialog = null;
3002 * start a thread to open a URL in the configured browser. Pops up a warning
3003 * dialog to the user if there is an exception when calling out to the browser
3008 public static void showUrl(final String url)
3010 showUrl(url, Desktop.instance);
3014 * Like showUrl but allows progress handler to be specified
3018 * (null) or object implementing IProgressIndicator
3020 public static void showUrl(final String url,
3021 final IProgressIndicator progress)
3023 new Thread(new Runnable()
3030 if (progress != null)
3032 progress.setProgressBar(MessageManager
3033 .formatMessage("status.opening_params", new Object[]
3034 { url }), this.hashCode());
3036 jalview.util.BrowserLauncher.openURL(url);
3037 } catch (Exception ex)
3039 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3041 .getString("label.web_browser_not_found_unix"),
3042 MessageManager.getString("label.web_browser_not_found"),
3043 JvOptionPane.WARNING_MESSAGE);
3045 ex.printStackTrace();
3047 if (progress != null)
3049 progress.setProgressBar(null, this.hashCode());
3055 public static WsParamSetManager wsparamManager = null;
3057 public static ParamManager getUserParameterStore()
3059 if (wsparamManager == null)
3061 wsparamManager = new WsParamSetManager();
3063 return wsparamManager;
3067 * static hyperlink handler proxy method for use by Jalview's internal windows
3071 public static void hyperlinkUpdate(HyperlinkEvent e)
3073 if (e.getEventType() == EventType.ACTIVATED)
3078 url = e.getURL().toString();
3079 Desktop.showUrl(url);
3080 } catch (Exception x)
3084 if (Cache.log != null)
3086 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3091 "Couldn't handle string " + url + " as a URL.");
3094 // ignore any exceptions due to dud links.
3101 * single thread that handles display of dialogs to user.
3103 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3106 * flag indicating if dialogExecutor should try to acquire a permit
3108 private volatile boolean dialogPause = true;
3113 private java.util.concurrent.Semaphore block = new Semaphore(0);
3115 private static groovy.ui.Console groovyConsole;
3118 * add another dialog thread to the queue
3122 public void addDialogThread(final Runnable prompter)
3124 dialogExecutor.submit(new Runnable()
3134 } catch (InterruptedException x)
3139 if (instance == null)
3145 SwingUtilities.invokeAndWait(prompter);
3146 } catch (Exception q)
3148 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3154 public void startDialogQueue()
3156 // set the flag so we don't pause waiting for another permit and semaphore
3157 // the current task to begin
3158 dialogPause = false;
3163 protected void snapShotWindow_actionPerformed(ActionEvent e)
3167 ImageMaker im = new jalview.util.ImageMaker(
3168 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3169 getHeight(), of = new File("Jalview_snapshot"
3170 + System.currentTimeMillis() + ".eps"),
3171 "View of desktop", null, 0, false);
3174 paintAll(im.getGraphics());
3176 } catch (Exception q)
3178 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3182 Cache.log.info("Successfully written snapshot to file "
3183 + of.getAbsolutePath());
3187 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3188 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3189 * and location last time the view was expanded (if any). However it does not
3190 * remember the split pane divider location - this is set to match the
3191 * 'exploding' frame.
3195 public void explodeViews(SplitFrame sf)
3197 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3198 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3199 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3201 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3203 int viewCount = topPanels.size();
3210 * Processing in reverse order works, forwards order leaves the first panels
3211 * not visible. I don't know why!
3213 for (int i = viewCount - 1; i >= 0; i--)
3216 * Make new top and bottom frames. These take over the respective
3217 * AlignmentPanel objects, including their AlignmentViewports, so the
3218 * cdna/protein relationships between the viewports is carried over to the
3221 * explodedGeometry holds the (x, y) position of the previously exploded
3222 * SplitFrame, and the (width, height) of the AlignFrame component
3224 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3225 AlignFrame newTopFrame = new AlignFrame(topPanel);
3226 newTopFrame.setSize(oldTopFrame.getSize());
3227 newTopFrame.setVisible(true);
3228 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3229 .getExplodedGeometry();
3230 if (geometry != null)
3232 newTopFrame.setSize(geometry.getSize());
3235 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3236 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3237 newBottomFrame.setSize(oldBottomFrame.getSize());
3238 newBottomFrame.setVisible(true);
3239 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3240 .getExplodedGeometry();
3241 if (geometry != null)
3243 newBottomFrame.setSize(geometry.getSize());
3246 topPanel.av.setGatherViewsHere(false);
3247 bottomPanel.av.setGatherViewsHere(false);
3248 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3250 if (geometry != null)
3252 splitFrame.setLocation(geometry.getLocation());
3254 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3258 * Clear references to the panels (now relocated in the new SplitFrames)
3259 * before closing the old SplitFrame.
3262 bottomPanels.clear();
3267 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3268 * back into the given SplitFrame as additional views. Note that the gathered
3269 * frames may themselves have multiple views.
3273 public void gatherViews(GSplitFrame source)
3276 * special handling of explodedGeometry for a view within a SplitFrame: - it
3277 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3278 * height) of the AlignFrame component
3280 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3281 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3282 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3283 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3284 myBottomFrame.viewport
3285 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3286 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3287 myTopFrame.viewport.setGatherViewsHere(true);
3288 myBottomFrame.viewport.setGatherViewsHere(true);
3289 String topViewId = myTopFrame.viewport.getSequenceSetId();
3290 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3292 JInternalFrame[] frames = desktop.getAllFrames();
3293 for (JInternalFrame frame : frames)
3295 if (frame instanceof SplitFrame && frame != source)
3297 SplitFrame sf = (SplitFrame) frame;
3298 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3299 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3300 boolean gatherThis = false;
3301 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3303 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3304 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3305 if (topViewId.equals(topPanel.av.getSequenceSetId())
3306 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3309 topPanel.av.setGatherViewsHere(false);
3310 bottomPanel.av.setGatherViewsHere(false);
3311 topPanel.av.setExplodedGeometry(
3312 new Rectangle(sf.getLocation(), topFrame.getSize()));
3313 bottomPanel.av.setExplodedGeometry(
3314 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3315 myTopFrame.addAlignmentPanel(topPanel, false);
3316 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3322 topFrame.getAlignPanels().clear();
3323 bottomFrame.getAlignPanels().clear();
3330 * The dust settles...give focus to the tab we did this from.
3332 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3335 public static groovy.ui.Console getGroovyConsole()
3337 return groovyConsole;
3341 * handles the payload of a drag and drop event.
3343 * TODO refactor to desktop utilities class
3346 * - Data source strings extracted from the drop event
3348 * - protocol for each data source extracted from the drop event
3352 * - the payload from the drop event
3355 public static void transferFromDropTarget(List<String> files,
3356 List<DataSourceType> protocols, DropTargetDropEvent evt,
3357 Transferable t) throws Exception
3360 DataFlavor uriListFlavor = new DataFlavor(
3361 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3364 urlFlavour = new DataFlavor(
3365 "application/x-java-url; class=java.net.URL");
3366 } catch (ClassNotFoundException cfe)
3368 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3371 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3376 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3377 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3378 // means url may be null.
3381 protocols.add(DataSourceType.URL);
3382 files.add(url.toString());
3383 Cache.log.debug("Drop handled as URL dataflavor "
3384 + files.get(files.size() - 1));
3389 if (Platform.isAMac())
3392 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3396 } catch (Throwable ex)
3398 Cache.log.debug("URL drop handler failed.", ex);
3401 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3403 // Works on Windows and MacOSX
3404 Cache.log.debug("Drop handled as javaFileListFlavor");
3405 for (Object file : (List) t
3406 .getTransferData(DataFlavor.javaFileListFlavor))
3408 files.add(((File) file).toString());
3409 protocols.add(DataSourceType.FILE);
3414 // Unix like behaviour
3415 boolean added = false;
3417 if (t.isDataFlavorSupported(uriListFlavor))
3419 Cache.log.debug("Drop handled as uriListFlavor");
3420 // This is used by Unix drag system
3421 data = (String) t.getTransferData(uriListFlavor);
3425 // fallback to text: workaround - on OSX where there's a JVM bug
3426 Cache.log.debug("standard URIListFlavor failed. Trying text");
3427 // try text fallback
3428 DataFlavor textDf = new DataFlavor(
3429 "text/plain;class=java.lang.String");
3430 if (t.isDataFlavorSupported(textDf))
3432 data = (String) t.getTransferData(textDf);
3435 Cache.log.debug("Plain text drop content returned "
3436 + (data == null ? "Null - failed" : data));
3441 while (protocols.size() < files.size())
3443 Cache.log.debug("Adding missing FILE protocol for "
3444 + files.get(protocols.size()));
3445 protocols.add(DataSourceType.FILE);
3447 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3448 data, "\r\n"); st.hasMoreTokens();)
3451 String s = st.nextToken();
3452 if (s.startsWith("#"))
3454 // the line is a comment (as per the RFC 2483)
3457 java.net.URI uri = new java.net.URI(s);
3458 if (uri.getScheme().toLowerCase().startsWith("http"))
3460 protocols.add(DataSourceType.URL);
3461 files.add(uri.toString());
3465 // otherwise preserve old behaviour: catch all for file objects
3466 java.io.File file = new java.io.File(uri);
3467 protocols.add(DataSourceType.FILE);
3468 files.add(file.toString());
3473 if (Cache.log.isDebugEnabled())
3475 if (data == null || !added)
3478 if (t.getTransferDataFlavors() != null
3479 && t.getTransferDataFlavors().length > 0)
3482 "Couldn't resolve drop data. Here are the supported flavors:");
3483 for (DataFlavor fl : t.getTransferDataFlavors())
3486 "Supported transfer dataflavor: " + fl.toString());
3487 Object df = t.getTransferData(fl);
3490 Cache.log.debug("Retrieves: " + df);
3494 Cache.log.debug("Retrieved nothing");
3500 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3506 if (Platform.isWindows())
3509 Cache.log.debug("Scanning dropped content for Windows Link Files");
3511 // resolve any .lnk files in the file drop
3512 for (int f = 0; f < files.size(); f++)
3514 String source = files.get(f).toLowerCase();
3515 if (protocols.get(f).equals(DataSourceType.FILE)
3516 && (source.endsWith(".lnk") || source.endsWith(".url")
3517 || source.endsWith(".site")))
3520 File lf = new File(files.get(f));
3521 // process link file to get a URL
3522 Cache.log.debug("Found potential link file: " + lf);
3523 WindowsShortcut wscfile = new WindowsShortcut(lf);
3524 String fullname = wscfile.getRealFilename();
3525 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3526 files.set(f, fullname);
3527 Cache.log.debug("Parsed real filename " + fullname
3528 + " to extract protocol: " + protocols.get(f));
3530 catch (Exception ex)
3532 Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
3540 * Sets the Preferences property for experimental features to True or False
3541 * depending on the state of the controlling menu item
3544 protected void showExperimental_actionPerformed(boolean selected)
3546 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3550 * Answers a (possibly empty) list of any structure viewer frames (currently
3551 * for either Jmol or Chimera) which are currently open. This may optionally
3552 * be restricted to viewers of a specified class, or viewers linked to a
3553 * specified alignment panel.
3556 * if not null, only return viewers linked to this panel
3557 * @param structureViewerClass
3558 * if not null, only return viewers of this class
3561 public List<StructureViewerBase> getStructureViewers(
3562 AlignmentPanel apanel,
3563 Class<? extends StructureViewerBase> structureViewerClass)
3565 List<StructureViewerBase> result = new ArrayList<>();
3566 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3568 for (JInternalFrame frame : frames)
3570 if (frame instanceof StructureViewerBase)
3572 if (structureViewerClass == null
3573 || structureViewerClass.isInstance(frame))
3576 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3578 result.add((StructureViewerBase) frame);