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 addDialogThread(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 addDialogThread(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"
560 protected void showNews_actionPerformed(ActionEvent e)
562 showNews(showNews.isSelected());
565 void showNews(boolean visible)
568 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
569 showNews.setSelected(visible);
570 if (visible && !jvnews.isVisible())
572 new Thread(new Runnable()
577 long now = System.currentTimeMillis();
578 Desktop.instance.setProgressBar(
579 MessageManager.getString("status.refreshing_news"),
581 jvnews.refreshNews();
582 Desktop.instance.setProgressBar(null, now);
591 * recover the last known dimensions for a jalview window
594 * - empty string is desktop, all other windows have unique prefix
595 * @return null or last known dimensions scaled to current geometry (if last
596 * window geom was known)
598 Rectangle getLastKnownDimensions(String windowName)
600 // TODO: lock aspect ratio for scaling desktop Bug #0058199
601 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
602 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
603 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
604 String width = jalview.bin.Cache
605 .getProperty(windowName + "SCREEN_WIDTH");
606 String height = jalview.bin.Cache
607 .getProperty(windowName + "SCREEN_HEIGHT");
608 if ((x != null) && (y != null) && (width != null) && (height != null))
610 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
611 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
612 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
614 // attempt #1 - try to cope with change in screen geometry - this
615 // version doesn't preserve original jv aspect ratio.
616 // take ratio of current screen size vs original screen size.
617 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
618 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
619 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
620 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
621 // rescale the bounds depending upon the current screen geometry.
622 ix = (int) (ix * sw);
623 iw = (int) (iw * sw);
624 iy = (int) (iy * sh);
625 ih = (int) (ih * sh);
626 while (ix >= screenSize.width)
628 jalview.bin.Cache.log.debug(
629 "Window geometry location recall error: shifting horizontal to within screenbounds.");
630 ix -= screenSize.width;
632 while (iy >= screenSize.height)
634 jalview.bin.Cache.log.debug(
635 "Window geometry location recall error: shifting vertical to within screenbounds.");
636 iy -= screenSize.height;
638 jalview.bin.Cache.log.debug(
639 "Got last known dimensions for " + windowName + ": x:" + ix
640 + " y:" + iy + " width:" + iw + " height:" + ih);
642 // return dimensions for new instance
643 return new Rectangle(ix, iy, iw, ih);
648 private void doVamsasClientCheck()
650 if (jalview.bin.Cache.vamsasJarsPresent())
652 setupVamsasDisconnectedGui();
653 VamsasMenu.setVisible(true);
654 final Desktop us = this;
655 VamsasMenu.addMenuListener(new MenuListener()
657 // this listener remembers when the menu was first selected, and
658 // doesn't rebuild the session list until it has been cleared and
660 boolean refresh = true;
663 public void menuCanceled(MenuEvent e)
669 public void menuDeselected(MenuEvent e)
675 public void menuSelected(MenuEvent e)
679 us.buildVamsasStMenu();
684 vamsasStart.setVisible(true);
688 void showPasteMenu(int x, int y)
690 JPopupMenu popup = new JPopupMenu();
691 JMenuItem item = new JMenuItem(
692 MessageManager.getString("label.paste_new_window"));
693 item.addActionListener(new ActionListener()
696 public void actionPerformed(ActionEvent evt)
703 popup.show(this, x, y);
710 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
711 Transferable contents = c.getContents(this);
713 if (contents != null)
715 String file = (String) contents
716 .getTransferData(DataFlavor.stringFlavor);
718 FileFormatI format = new IdentifyFile().identify(file,
719 DataSourceType.PASTE);
721 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
724 } catch (Exception ex)
727 "Unable to paste alignment from system clipboard:\n" + ex);
732 * Adds and opens the given frame to the desktop
743 public static synchronized void addInternalFrame(
744 final JInternalFrame frame, String title, int w, int h)
746 addInternalFrame(frame, title, true, w, h, true, false);
750 * Add an internal frame to the Jalview desktop
757 * When true, display frame immediately, otherwise, caller must call
758 * setVisible themselves.
764 public static synchronized void addInternalFrame(
765 final JInternalFrame frame, String title, boolean makeVisible,
768 addInternalFrame(frame, title, makeVisible, w, h, true, false);
772 * Add an internal frame to the Jalview desktop and make it visible
785 public static synchronized void addInternalFrame(
786 final JInternalFrame frame, String title, int w, int h,
789 addInternalFrame(frame, title, true, w, h, resizable, false);
793 * Add an internal frame to the Jalview desktop
800 * When true, display frame immediately, otherwise, caller must call
801 * setVisible themselves.
808 * @param ignoreMinSize
809 * Do not set the default minimum size for frame
811 public static synchronized void addInternalFrame(
812 final JInternalFrame frame, String title, boolean makeVisible,
813 int w, int h, boolean resizable, boolean ignoreMinSize)
816 // TODO: allow callers to determine X and Y position of frame (eg. via
818 // TODO: consider fixing method to update entries in the window submenu with
819 // the current window title
821 frame.setTitle(title);
822 if (frame.getWidth() < 1 || frame.getHeight() < 1)
826 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
827 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
828 // IF JALVIEW IS RUNNING HEADLESS
829 // ///////////////////////////////////////////////
830 if (instance == null || (System.getProperty("java.awt.headless") != null
831 && System.getProperty("java.awt.headless").equals("true")))
840 frame.setMinimumSize(
841 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
843 // Set default dimension for Alignment Frame window.
844 // The Alignment Frame window could be added from a number of places,
846 // I did this here in order not to miss out on any Alignment frame.
847 if (frame instanceof AlignFrame)
849 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
850 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
854 frame.setVisible(makeVisible);
855 frame.setClosable(true);
856 frame.setResizable(resizable);
857 frame.setMaximizable(resizable);
858 frame.setIconifiable(resizable);
859 frame.setOpaque(false);
861 if (frame.getX() < 1 && frame.getY() < 1)
863 frame.setLocation(xOffset * openFrameCount,
864 yOffset * ((openFrameCount - 1) % 10) + yOffset);
868 * add an entry for the new frame in the Window menu
869 * (and remove it when the frame is closed)
871 final JMenuItem menuItem = new JMenuItem(title);
872 frame.addInternalFrameListener(new InternalFrameAdapter()
875 public void internalFrameActivated(InternalFrameEvent evt)
877 JInternalFrame itf = desktop.getSelectedFrame();
880 if (itf instanceof AlignFrame)
882 Jalview.setCurrentAlignFrame((AlignFrame) itf);
889 public void internalFrameClosed(InternalFrameEvent evt)
891 PaintRefresher.RemoveComponent(frame);
894 * defensive check to prevent frames being
895 * added half off the window
897 if (openFrameCount > 0)
903 * ensure no reference to alignFrame retained by menu item listener
905 if (menuItem.getActionListeners().length > 0)
907 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
909 windowMenu.remove(menuItem);
913 menuItem.addActionListener(new ActionListener()
916 public void actionPerformed(ActionEvent e)
920 frame.setSelected(true);
921 frame.setIcon(false);
922 } catch (java.beans.PropertyVetoException ex)
929 setKeyBindings(frame);
933 windowMenu.add(menuItem);
938 frame.setSelected(true);
939 frame.requestFocus();
940 } catch (java.beans.PropertyVetoException ve)
942 } catch (java.lang.ClassCastException cex)
945 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
951 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
956 private static void setKeyBindings(JInternalFrame frame)
958 @SuppressWarnings("serial")
959 final Action closeAction = new AbstractAction()
962 public void actionPerformed(ActionEvent e)
969 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
971 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
972 InputEvent.CTRL_DOWN_MASK);
973 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
974 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
976 InputMap inputMap = frame
977 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
978 String ctrlW = ctrlWKey.toString();
979 inputMap.put(ctrlWKey, ctrlW);
980 inputMap.put(cmdWKey, ctrlW);
982 ActionMap actionMap = frame.getActionMap();
983 actionMap.put(ctrlW, closeAction);
987 public void lostOwnership(Clipboard clipboard, Transferable contents)
991 Desktop.jalviewClipboard = null;
994 internalCopy = false;
998 public void dragEnter(DropTargetDragEvent evt)
1003 public void dragExit(DropTargetEvent evt)
1008 public void dragOver(DropTargetDragEvent evt)
1013 public void dropActionChanged(DropTargetDragEvent evt)
1024 public void drop(DropTargetDropEvent evt)
1026 boolean success = true;
1027 // JAL-1552 - acceptDrop required before getTransferable call for
1028 // Java's Transferable for native dnd
1029 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1030 Transferable t = evt.getTransferable();
1031 List<String> files = new ArrayList<>();
1032 List<DataSourceType> protocols = new ArrayList<>();
1036 Desktop.transferFromDropTarget(files, protocols, evt, t);
1037 } catch (Exception e)
1039 e.printStackTrace();
1047 for (int i = 0; i < files.size(); i++)
1049 String file = files.get(i).toString();
1050 DataSourceType protocol = (protocols == null)
1051 ? DataSourceType.FILE
1053 FileFormatI format = null;
1055 if (file.endsWith(".jar"))
1057 format = FileFormat.Jalview;
1062 format = new IdentifyFile().identify(file, protocol);
1065 new FileLoader().LoadFile(file, protocol, format);
1068 } catch (Exception ex)
1073 evt.dropComplete(success); // need this to ensure input focus is properly
1074 // transfered to any new windows created
1084 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1086 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1087 JalviewFileChooser chooser = JalviewFileChooser
1088 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1090 chooser.setFileView(new JalviewFileView());
1091 chooser.setDialogTitle(
1092 MessageManager.getString("label.open_local_file"));
1093 chooser.setToolTipText(MessageManager.getString("action.open"));
1095 int value = chooser.showOpenDialog(this);
1097 if (value == JalviewFileChooser.APPROVE_OPTION)
1099 String choice = chooser.getSelectedFile().getPath();
1100 Cache.setProperty("LAST_DIRECTORY",
1101 chooser.getSelectedFile().getParent());
1103 FileFormatI format = chooser.getSelectedFormat();
1106 * Call IdentifyFile to verify the file contains what its extension implies.
1107 * Skip this step for dynamically added file formats, because
1108 * IdentifyFile does not know how to recognise them.
1110 if (FileFormats.getInstance().isIdentifiable(format))
1114 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1115 } catch (FileFormatException e)
1117 // format = null; //??
1121 if (viewport != null)
1123 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1128 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1140 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1142 // This construct allows us to have a wider textfield
1144 JLabel label = new JLabel(
1145 MessageManager.getString("label.input_file_url"));
1146 final JComboBox history = new JComboBox();
1148 JPanel panel = new JPanel(new GridLayout(2, 1));
1151 history.setPreferredSize(new Dimension(400, 20));
1152 history.setEditable(true);
1153 history.addItem("http://www.");
1155 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1159 if (historyItems != null)
1161 st = new StringTokenizer(historyItems, "\t");
1163 while (st.hasMoreTokens())
1165 history.addItem(st.nextElement());
1169 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1170 MessageManager.getString("label.input_alignment_from_url"),
1171 JvOptionPane.OK_CANCEL_OPTION);
1173 if (reply != JvOptionPane.OK_OPTION)
1178 String url = history.getSelectedItem().toString();
1180 if (url.toLowerCase().endsWith(".jar"))
1182 if (viewport != null)
1184 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1185 FileFormat.Jalview);
1189 new FileLoader().LoadFile(url, DataSourceType.URL,
1190 FileFormat.Jalview);
1195 FileFormatI format = null;
1198 format = new IdentifyFile().identify(url, DataSourceType.URL);
1199 } catch (FileFormatException e)
1201 // TODO revise error handling, distinguish between
1202 // URL not found and response not valid
1207 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1208 MessageManager.formatMessage("label.couldnt_locate",
1211 MessageManager.getString("label.url_not_found"),
1212 JvOptionPane.WARNING_MESSAGE);
1217 if (viewport != null)
1219 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1224 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1230 * Opens the CutAndPaste window for the user to paste an alignment in to
1233 * - if not null, the pasted alignment is added to the current
1234 * alignment; if null, to a new alignment window
1237 public void inputTextboxMenuItem_actionPerformed(
1238 AlignmentViewPanel viewPanel)
1240 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1241 cap.setForInput(viewPanel);
1242 Desktop.addInternalFrame(cap,
1243 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1253 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1254 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1256 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1257 screen.height + "");
1258 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1259 getWidth(), getHeight()));
1261 if (jconsole != null)
1263 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1264 jconsole.stopConsole();
1268 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1271 if (dialogExecutor != null)
1273 dialogExecutor.shutdownNow();
1275 closeAll_actionPerformed(null);
1277 if (groovyConsole != null)
1279 // suppress a possible repeat prompt to save script
1280 groovyConsole.setDirty(false);
1281 groovyConsole.exit();
1286 private void storeLastKnownDimensions(String string, Rectangle jc)
1288 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1289 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1290 + " height:" + jc.height);
1292 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1293 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1294 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1295 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1305 public void aboutMenuItem_actionPerformed(ActionEvent e)
1307 // StringBuffer message = getAboutMessage(false);
1308 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1310 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1311 new Thread(new Runnable()
1316 new SplashScreen(true);
1321 public StringBuffer getAboutMessage(boolean shortv)
1323 StringBuffer message = new StringBuffer();
1324 message.append("<html>");
1327 message.append("<h1><strong>Version: "
1328 + jalview.bin.Cache.getProperty("VERSION")
1329 + "</strong></h1>");
1330 message.append("<strong>Last Updated: <em>"
1331 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1332 + "</em></strong>");
1338 message.append("<strong>Version "
1339 + jalview.bin.Cache.getProperty("VERSION")
1340 + "; last updated: "
1341 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1344 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1345 .equals("Checking"))
1347 message.append("<br>...Checking latest version...</br>");
1349 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1350 .equals(jalview.bin.Cache.getProperty("VERSION")))
1352 boolean red = false;
1353 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1354 .indexOf("automated build") == -1)
1357 // Displayed when code version and jnlp version do not match and code
1358 // version is not a development build
1359 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1362 message.append("<br>!! Version "
1363 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1365 + " is available for download from "
1366 + jalview.bin.Cache.getDefault("www.jalview.org",
1367 "http://www.jalview.org")
1371 message.append("</div>");
1374 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1376 "The Jalview Authors (See AUTHORS file for current list)")
1377 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1378 + "<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"
1379 + "<br><br>If you use Jalview, please cite:"
1380 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1381 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1382 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1394 public void documentationMenuItem_actionPerformed(ActionEvent e)
1398 Help.showHelpWindow();
1399 } catch (Exception ex)
1405 public void closeAll_actionPerformed(ActionEvent e)
1407 // TODO show a progress bar while closing?
1408 JInternalFrame[] frames = desktop.getAllFrames();
1409 for (int i = 0; i < frames.length; i++)
1413 frames[i].setClosed(true);
1414 } catch (java.beans.PropertyVetoException ex)
1418 Jalview.setCurrentAlignFrame(null);
1419 System.out.println("ALL CLOSED");
1420 if (v_client != null)
1422 // TODO clear binding to vamsas document objects on close_all
1426 * reset state of singleton objects as appropriate (clear down session state
1427 * when all windows are closed)
1429 StructureSelectionManager ssm = StructureSelectionManager
1430 .getStructureSelectionManager(this);
1438 public void raiseRelated_actionPerformed(ActionEvent e)
1440 reorderAssociatedWindows(false, false);
1444 public void minimizeAssociated_actionPerformed(ActionEvent e)
1446 reorderAssociatedWindows(true, false);
1449 void closeAssociatedWindows()
1451 reorderAssociatedWindows(false, true);
1457 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1461 protected void garbageCollect_actionPerformed(ActionEvent e)
1463 // We simply collect the garbage
1464 jalview.bin.Cache.log.debug("Collecting garbage...");
1466 jalview.bin.Cache.log.debug("Finished garbage collection.");
1473 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1477 protected void showMemusage_actionPerformed(ActionEvent e)
1479 desktop.showMemoryUsage(showMemusage.isSelected());
1486 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1490 protected void showConsole_actionPerformed(ActionEvent e)
1492 showConsole(showConsole.isSelected());
1495 Console jconsole = null;
1498 * control whether the java console is visible or not
1502 void showConsole(boolean selected)
1504 showConsole.setSelected(selected);
1505 // TODO: decide if we should update properties file
1506 Cache.setProperty("SHOW_JAVA_CONSOLE",
1507 Boolean.valueOf(selected).toString());
1508 jconsole.setVisible(selected);
1511 void reorderAssociatedWindows(boolean minimize, boolean close)
1513 JInternalFrame[] frames = desktop.getAllFrames();
1514 if (frames == null || frames.length < 1)
1519 AlignmentViewport source = null, target = null;
1520 if (frames[0] instanceof AlignFrame)
1522 source = ((AlignFrame) frames[0]).getCurrentView();
1524 else if (frames[0] instanceof TreePanel)
1526 source = ((TreePanel) frames[0]).getViewPort();
1528 else if (frames[0] instanceof PCAPanel)
1530 source = ((PCAPanel) frames[0]).av;
1532 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1534 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1539 for (int i = 0; i < frames.length; i++)
1542 if (frames[i] == null)
1546 if (frames[i] instanceof AlignFrame)
1548 target = ((AlignFrame) frames[i]).getCurrentView();
1550 else if (frames[i] instanceof TreePanel)
1552 target = ((TreePanel) frames[i]).getViewPort();
1554 else if (frames[i] instanceof PCAPanel)
1556 target = ((PCAPanel) frames[i]).av;
1558 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1560 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1563 if (source == target)
1569 frames[i].setClosed(true);
1573 frames[i].setIcon(minimize);
1576 frames[i].toFront();
1580 } catch (java.beans.PropertyVetoException ex)
1595 protected void preferences_actionPerformed(ActionEvent e)
1607 public void saveState_actionPerformed(ActionEvent e)
1609 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1612 chooser.setFileView(new JalviewFileView());
1613 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1615 int value = chooser.showSaveDialog(this);
1617 if (value == JalviewFileChooser.APPROVE_OPTION)
1619 final Desktop me = this;
1620 final java.io.File choice = chooser.getSelectedFile();
1621 setProjectFile(choice);
1623 new Thread(new Runnable()
1628 // TODO: refactor to Jalview desktop session controller action.
1629 setProgressBar(MessageManager.formatMessage(
1630 "label.saving_jalview_project", new Object[]
1631 { choice.getName() }), choice.hashCode());
1632 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1633 choice.getParent());
1634 // TODO catch and handle errors for savestate
1635 // TODO prevent user from messing with the Desktop whilst we're saving
1638 new Jalview2XML().saveState(choice);
1639 } catch (OutOfMemoryError oom)
1642 "Whilst saving current state to " + choice.getName(),
1644 } catch (Exception ex)
1647 "Problems whilst trying to save to " + choice.getName(),
1649 JvOptionPane.showMessageDialog(me,
1650 MessageManager.formatMessage(
1651 "label.error_whilst_saving_current_state_to",
1653 { choice.getName() }),
1654 MessageManager.getString("label.couldnt_save_project"),
1655 JvOptionPane.WARNING_MESSAGE);
1657 setProgressBar(null, choice.hashCode());
1663 private void setProjectFile(File choice)
1665 this.projectFile = choice;
1668 public File getProjectFile()
1670 return this.projectFile;
1680 public void loadState_actionPerformed(ActionEvent e)
1682 JalviewFileChooser chooser = new JalviewFileChooser(
1683 Cache.getProperty("LAST_DIRECTORY"), new String[]
1686 { "Jalview Project", "Jalview Project (old)" },
1688 chooser.setFileView(new JalviewFileView());
1689 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1691 int value = chooser.showOpenDialog(this);
1693 if (value == JalviewFileChooser.APPROVE_OPTION)
1695 final File selectedFile = chooser.getSelectedFile();
1696 setProjectFile(selectedFile);
1697 final String choice = selectedFile.getAbsolutePath();
1698 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1699 new Thread(new Runnable()
1704 setProgressBar(MessageManager.formatMessage(
1705 "label.loading_jalview_project", new Object[]
1706 { choice }), choice.hashCode());
1709 new Jalview2XML().loadJalviewAlign(choice);
1710 } catch (OutOfMemoryError oom)
1712 new OOMWarning("Whilst loading project from " + choice, oom);
1713 } catch (Exception ex)
1716 "Problems whilst loading project from " + choice, ex);
1717 JvOptionPane.showMessageDialog(Desktop.desktop,
1718 MessageManager.formatMessage(
1719 "label.error_whilst_loading_project_from",
1722 MessageManager.getString("label.couldnt_load_project"),
1723 JvOptionPane.WARNING_MESSAGE);
1725 setProgressBar(null, choice.hashCode());
1732 public void inputSequence_actionPerformed(ActionEvent e)
1734 new SequenceFetcher(this);
1737 JPanel progressPanel;
1739 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1741 public void startLoading(final String fileName)
1743 if (fileLoadingCount == 0)
1745 fileLoadingPanels.add(addProgressPanel(MessageManager
1746 .formatMessage("label.loading_file", new Object[]
1752 private JPanel addProgressPanel(String string)
1754 if (progressPanel == null)
1756 progressPanel = new JPanel(new GridLayout(1, 1));
1757 totalProgressCount = 0;
1758 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1760 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1761 JProgressBar progressBar = new JProgressBar();
1762 progressBar.setIndeterminate(true);
1764 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1766 thisprogress.add(progressBar, BorderLayout.CENTER);
1767 progressPanel.add(thisprogress);
1768 ((GridLayout) progressPanel.getLayout()).setRows(
1769 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1770 ++totalProgressCount;
1771 instance.validate();
1772 return thisprogress;
1775 int totalProgressCount = 0;
1777 private void removeProgressPanel(JPanel progbar)
1779 if (progressPanel != null)
1781 synchronized (progressPanel)
1783 progressPanel.remove(progbar);
1784 GridLayout gl = (GridLayout) progressPanel.getLayout();
1785 gl.setRows(gl.getRows() - 1);
1786 if (--totalProgressCount < 1)
1788 this.getContentPane().remove(progressPanel);
1789 progressPanel = null;
1796 public void stopLoading()
1799 if (fileLoadingCount < 1)
1801 while (fileLoadingPanels.size() > 0)
1803 removeProgressPanel(fileLoadingPanels.remove(0));
1805 fileLoadingPanels.clear();
1806 fileLoadingCount = 0;
1811 public static int getViewCount(String alignmentId)
1813 AlignmentViewport[] aps = getViewports(alignmentId);
1814 return (aps == null) ? 0 : aps.length;
1819 * @param alignmentId
1820 * - if null, all sets are returned
1821 * @return all AlignmentPanels concerning the alignmentId sequence set
1823 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1825 if (Desktop.desktop == null)
1827 // no frames created and in headless mode
1828 // TODO: verify that frames are recoverable when in headless mode
1831 List<AlignmentPanel> aps = new ArrayList<>();
1832 AlignFrame[] frames = getAlignFrames();
1837 for (AlignFrame af : frames)
1839 for (AlignmentPanel ap : af.alignPanels)
1841 if (alignmentId == null
1842 || alignmentId.equals(ap.av.getSequenceSetId()))
1848 if (aps.size() == 0)
1852 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1857 * get all the viewports on an alignment.
1859 * @param sequenceSetId
1860 * unique alignment id (may be null - all viewports returned in that
1862 * @return all viewports on the alignment bound to sequenceSetId
1864 public static AlignmentViewport[] getViewports(String sequenceSetId)
1866 List<AlignmentViewport> viewp = new ArrayList<>();
1867 if (desktop != null)
1869 AlignFrame[] frames = Desktop.getAlignFrames();
1871 for (AlignFrame afr : frames)
1873 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1874 .equals(sequenceSetId))
1876 if (afr.alignPanels != null)
1878 for (AlignmentPanel ap : afr.alignPanels)
1880 if (sequenceSetId == null
1881 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1889 viewp.add(afr.getViewport());
1893 if (viewp.size() > 0)
1895 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1902 * Explode the views in the given frame into separate AlignFrame
1906 public static void explodeViews(AlignFrame af)
1908 int size = af.alignPanels.size();
1914 for (int i = 0; i < size; i++)
1916 AlignmentPanel ap = af.alignPanels.get(i);
1917 AlignFrame newaf = new AlignFrame(ap);
1920 * Restore the view's last exploded frame geometry if known. Multiple
1921 * views from one exploded frame share and restore the same (frame)
1922 * position and size.
1924 Rectangle geometry = ap.av.getExplodedGeometry();
1925 if (geometry != null)
1927 newaf.setBounds(geometry);
1930 ap.av.setGatherViewsHere(false);
1932 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1933 AlignFrame.DEFAULT_HEIGHT);
1936 af.alignPanels.clear();
1937 af.closeMenuItem_actionPerformed(true);
1942 * Gather expanded views (separate AlignFrame's) with the same sequence set
1943 * identifier back in to this frame as additional views, and close the
1944 * expanded views. Note the expanded frames may themselves have multiple
1945 * views. We take the lot.
1949 public void gatherViews(AlignFrame source)
1951 source.viewport.setGatherViewsHere(true);
1952 source.viewport.setExplodedGeometry(source.getBounds());
1953 JInternalFrame[] frames = desktop.getAllFrames();
1954 String viewId = source.viewport.getSequenceSetId();
1956 for (int t = 0; t < frames.length; t++)
1958 if (frames[t] instanceof AlignFrame && frames[t] != source)
1960 AlignFrame af = (AlignFrame) frames[t];
1961 boolean gatherThis = false;
1962 for (int a = 0; a < af.alignPanels.size(); a++)
1964 AlignmentPanel ap = af.alignPanels.get(a);
1965 if (viewId.equals(ap.av.getSequenceSetId()))
1968 ap.av.setGatherViewsHere(false);
1969 ap.av.setExplodedGeometry(af.getBounds());
1970 source.addAlignmentPanel(ap, false);
1976 af.alignPanels.clear();
1977 af.closeMenuItem_actionPerformed(true);
1984 jalview.gui.VamsasApplication v_client = null;
1987 public void vamsasImport_actionPerformed(ActionEvent e)
1989 if (v_client == null)
1991 // Load and try to start a session.
1992 JalviewFileChooser chooser = new JalviewFileChooser(
1993 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
1995 chooser.setFileView(new JalviewFileView());
1996 chooser.setDialogTitle(
1997 MessageManager.getString("label.open_saved_vamsas_session"));
1998 chooser.setToolTipText(MessageManager.getString(
1999 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2001 int value = chooser.showOpenDialog(this);
2003 if (value == JalviewFileChooser.APPROVE_OPTION)
2005 String fle = chooser.getSelectedFile().toString();
2006 if (!vamsasImport(chooser.getSelectedFile()))
2008 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2009 MessageManager.formatMessage(
2010 "label.couldnt_import_as_vamsas_session",
2014 .getString("label.vamsas_document_import_failed"),
2015 JvOptionPane.ERROR_MESSAGE);
2021 jalview.bin.Cache.log.error(
2022 "Implementation error - load session from a running session is not supported.");
2027 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2030 * @return true if import was a success and a session was started.
2032 public boolean vamsasImport(URL url)
2034 // TODO: create progress bar
2035 if (v_client != null)
2038 jalview.bin.Cache.log.error(
2039 "Implementation error - load session from a running session is not supported.");
2045 // copy the URL content to a temporary local file
2046 // TODO: be a bit cleverer here with nio (?!)
2047 File file = File.createTempFile("vdocfromurl", ".vdj");
2048 FileOutputStream fos = new FileOutputStream(file);
2049 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2050 byte[] buffer = new byte[2048];
2052 while ((ln = bis.read(buffer)) > -1)
2054 fos.write(buffer, 0, ln);
2058 v_client = new jalview.gui.VamsasApplication(this, file,
2059 url.toExternalForm());
2060 } catch (Exception ex)
2062 jalview.bin.Cache.log.error(
2063 "Failed to create new vamsas session from contents of URL "
2068 setupVamsasConnectedGui();
2069 v_client.initial_update(); // TODO: thread ?
2070 return v_client.inSession();
2074 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2077 * @return true if import was a success and a session was started.
2079 public boolean vamsasImport(File file)
2081 if (v_client != null)
2084 jalview.bin.Cache.log.error(
2085 "Implementation error - load session from a running session is not supported.");
2089 setProgressBar(MessageManager.formatMessage(
2090 "status.importing_vamsas_session_from", new Object[]
2091 { file.getName() }), file.hashCode());
2094 v_client = new jalview.gui.VamsasApplication(this, file, null);
2095 } catch (Exception ex)
2097 setProgressBar(MessageManager.formatMessage(
2098 "status.importing_vamsas_session_from", new Object[]
2099 { file.getName() }), file.hashCode());
2100 jalview.bin.Cache.log.error(
2101 "New vamsas session from existing session file failed:", ex);
2104 setupVamsasConnectedGui();
2105 v_client.initial_update(); // TODO: thread ?
2106 setProgressBar(MessageManager.formatMessage(
2107 "status.importing_vamsas_session_from", new Object[]
2108 { file.getName() }), file.hashCode());
2109 return v_client.inSession();
2112 public boolean joinVamsasSession(String mysesid)
2114 if (v_client != null)
2116 throw new Error(MessageManager
2117 .getString("error.try_join_vamsas_session_another"));
2119 if (mysesid == null)
2122 MessageManager.getString("error.invalid_vamsas_session_id"));
2124 v_client = new VamsasApplication(this, mysesid);
2125 setupVamsasConnectedGui();
2126 v_client.initial_update();
2127 return (v_client.inSession());
2131 public void vamsasStart_actionPerformed(ActionEvent e)
2133 if (v_client == null)
2136 // we just start a default session for moment.
2138 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2139 * getProperty("LAST_DIRECTORY"));
2141 * chooser.setFileView(new JalviewFileView());
2142 * chooser.setDialogTitle("Load Vamsas file");
2143 * chooser.setToolTipText("Import");
2145 * int value = chooser.showOpenDialog(this);
2147 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2148 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2150 v_client = new VamsasApplication(this);
2151 setupVamsasConnectedGui();
2152 v_client.initial_update(); // TODO: thread ?
2156 // store current data in session.
2157 v_client.push_update(); // TODO: thread
2161 protected void setupVamsasConnectedGui()
2163 vamsasStart.setText(MessageManager.getString("label.session_update"));
2164 vamsasSave.setVisible(true);
2165 vamsasStop.setVisible(true);
2166 vamsasImport.setVisible(false); // Document import to existing session is
2167 // not possible for vamsas-client-1.0.
2170 protected void setupVamsasDisconnectedGui()
2172 vamsasSave.setVisible(false);
2173 vamsasStop.setVisible(false);
2174 vamsasImport.setVisible(true);
2176 .setText(MessageManager.getString("label.new_vamsas_session"));
2180 public void vamsasStop_actionPerformed(ActionEvent e)
2182 if (v_client != null)
2184 v_client.end_session();
2186 setupVamsasDisconnectedGui();
2190 protected void buildVamsasStMenu()
2192 if (v_client == null)
2194 String[] sess = null;
2197 sess = VamsasApplication.getSessionList();
2198 } catch (Exception e)
2200 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2206 jalview.bin.Cache.log.debug(
2207 "Got current sessions list: " + sess.length + " entries.");
2208 VamsasStMenu.removeAll();
2209 for (int i = 0; i < sess.length; i++)
2211 JMenuItem sessit = new JMenuItem();
2212 sessit.setText(sess[i]);
2213 sessit.setToolTipText(MessageManager
2214 .formatMessage("label.connect_to_session", new Object[]
2216 final Desktop dsktp = this;
2217 final String mysesid = sess[i];
2218 sessit.addActionListener(new ActionListener()
2222 public void actionPerformed(ActionEvent e)
2224 if (dsktp.v_client == null)
2226 Thread rthr = new Thread(new Runnable()
2232 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2233 dsktp.setupVamsasConnectedGui();
2234 dsktp.v_client.initial_update();
2242 VamsasStMenu.add(sessit);
2244 // don't show an empty menu.
2245 VamsasStMenu.setVisible(sess.length > 0);
2250 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2251 VamsasStMenu.removeAll();
2252 VamsasStMenu.setVisible(false);
2257 // Not interested in the content. Just hide ourselves.
2258 VamsasStMenu.setVisible(false);
2263 public void vamsasSave_actionPerformed(ActionEvent e)
2265 if (v_client != null)
2267 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2268 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2271 chooser.setFileView(new JalviewFileView());
2272 chooser.setDialogTitle(MessageManager
2273 .getString("label.save_vamsas_document_archive"));
2275 int value = chooser.showSaveDialog(this);
2277 if (value == JalviewFileChooser.APPROVE_OPTION)
2279 java.io.File choice = chooser.getSelectedFile();
2280 JPanel progpanel = addProgressPanel(MessageManager
2281 .formatMessage("label.saving_vamsas_doc", new Object[]
2282 { choice.getName() }));
2283 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2284 String warnmsg = null;
2285 String warnttl = null;
2288 v_client.vclient.storeDocument(choice);
2291 warnttl = "Serious Problem saving Vamsas Document";
2292 warnmsg = ex.toString();
2293 jalview.bin.Cache.log
2294 .error("Error Whilst saving document to " + choice, ex);
2296 } catch (Exception ex)
2298 warnttl = "Problem saving Vamsas Document.";
2299 warnmsg = ex.toString();
2300 jalview.bin.Cache.log.warn(
2301 "Exception Whilst saving document to " + choice, ex);
2304 removeProgressPanel(progpanel);
2305 if (warnmsg != null)
2307 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2309 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2315 JPanel vamUpdate = null;
2318 * hide vamsas user gui bits when a vamsas document event is being handled.
2321 * true to hide gui, false to reveal gui
2323 public void setVamsasUpdate(boolean b)
2325 Cache.log.debug("Setting gui for Vamsas update "
2326 + (b ? "in progress" : "finished"));
2328 if (vamUpdate != null)
2330 this.removeProgressPanel(vamUpdate);
2334 vamUpdate = this.addProgressPanel(
2335 MessageManager.getString("label.updating_vamsas_session"));
2337 vamsasStart.setVisible(!b);
2338 vamsasStop.setVisible(!b);
2339 vamsasSave.setVisible(!b);
2342 public JInternalFrame[] getAllFrames()
2344 return desktop.getAllFrames();
2348 * Checks the given url to see if it gives a response indicating that the user
2349 * should be informed of a new questionnaire.
2353 public void checkForQuestionnaire(String url)
2355 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2356 // javax.swing.SwingUtilities.invokeLater(jvq);
2357 new Thread(jvq).start();
2360 public void checkURLLinks()
2362 // Thread off the URL link checker
2363 addDialogThread(new Runnable()
2368 if (Cache.getDefault("CHECKURLLINKS", true))
2370 // check what the actual links are - if it's just the default don't
2371 // bother with the warning
2372 List<String> links = Preferences.sequenceUrlLinks
2375 // only need to check links if there is one with a
2376 // SEQUENCE_ID which is not the default EMBL_EBI link
2377 ListIterator<String> li = links.listIterator();
2378 boolean check = false;
2379 List<JLabel> urls = new ArrayList<>();
2380 while (li.hasNext())
2382 String link = li.next();
2383 if (link.contains(SEQUENCE_ID)
2384 && !UrlConstants.isDefaultString(link))
2387 int barPos = link.indexOf("|");
2388 String urlMsg = barPos == -1 ? link
2389 : link.substring(0, barPos) + ": "
2390 + link.substring(barPos + 1);
2391 urls.add(new JLabel(urlMsg));
2399 // ask user to check in case URL links use old style tokens
2400 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2401 JPanel msgPanel = new JPanel();
2402 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2403 msgPanel.add(Box.createVerticalGlue());
2404 JLabel msg = new JLabel(MessageManager
2405 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2406 JLabel msg2 = new JLabel(MessageManager
2407 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2409 for (JLabel url : urls)
2415 final JCheckBox jcb = new JCheckBox(
2416 MessageManager.getString("label.do_not_display_again"));
2417 jcb.addActionListener(new ActionListener()
2420 public void actionPerformed(ActionEvent e)
2422 // update Cache settings for "don't show this again"
2423 boolean showWarningAgain = !jcb.isSelected();
2424 Cache.setProperty("CHECKURLLINKS",
2425 Boolean.valueOf(showWarningAgain).toString());
2430 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2432 .getString("label.SEQUENCE_ID_no_longer_used"),
2433 JvOptionPane.WARNING_MESSAGE);
2440 * Proxy class for JDesktopPane which optionally displays the current memory
2441 * usage and highlights the desktop area with a red bar if free memory runs
2446 public class MyDesktopPane extends JDesktopPane implements Runnable
2449 private static final float ONE_MB = 1048576f;
2451 boolean showMemoryUsage = false;
2455 java.text.NumberFormat df;
2457 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2460 public MyDesktopPane(boolean showMemoryUsage)
2462 showMemoryUsage(showMemoryUsage);
2465 public void showMemoryUsage(boolean showMemory)
2467 this.showMemoryUsage = showMemory;
2470 Thread worker = new Thread(this);
2476 public boolean isShowMemoryUsage()
2478 return showMemoryUsage;
2484 df = java.text.NumberFormat.getNumberInstance();
2485 df.setMaximumFractionDigits(2);
2486 runtime = Runtime.getRuntime();
2488 while (showMemoryUsage)
2492 maxMemory = runtime.maxMemory() / ONE_MB;
2493 allocatedMemory = runtime.totalMemory() / ONE_MB;
2494 freeMemory = runtime.freeMemory() / ONE_MB;
2495 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2497 percentUsage = (totalFreeMemory / maxMemory) * 100;
2499 // if (percentUsage < 20)
2501 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2503 // instance.set.setBorder(border1);
2506 // sleep after showing usage
2508 } catch (Exception ex)
2510 ex.printStackTrace();
2516 public void paintComponent(Graphics g)
2518 if (showMemoryUsage && g != null && df != null)
2520 if (percentUsage < 20)
2522 g.setColor(Color.red);
2524 FontMetrics fm = g.getFontMetrics();
2527 g.drawString(MessageManager.formatMessage("label.memory_stats",
2529 { df.format(totalFreeMemory), df.format(maxMemory),
2530 df.format(percentUsage) }),
2531 10, getHeight() - fm.getHeight());
2539 * Accessor method to quickly get all the AlignmentFrames loaded.
2541 * @return an array of AlignFrame, or null if none found
2543 public static AlignFrame[] getAlignFrames()
2545 if (Jalview.isHeadlessMode())
2547 // Desktop.desktop is null in headless mode
2548 return new AlignFrame[] { Jalview.currentAlignFrame };
2551 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2557 List<AlignFrame> avp = new ArrayList<>();
2559 for (int i = frames.length - 1; i > -1; i--)
2561 if (frames[i] instanceof AlignFrame)
2563 avp.add((AlignFrame) frames[i]);
2565 else if (frames[i] instanceof SplitFrame)
2568 * Also check for a split frame containing an AlignFrame
2570 GSplitFrame sf = (GSplitFrame) frames[i];
2571 if (sf.getTopFrame() instanceof AlignFrame)
2573 avp.add((AlignFrame) sf.getTopFrame());
2575 if (sf.getBottomFrame() instanceof AlignFrame)
2577 avp.add((AlignFrame) sf.getBottomFrame());
2581 if (avp.size() == 0)
2585 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2590 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2594 public GStructureViewer[] getJmols()
2596 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2602 List<GStructureViewer> avp = new ArrayList<>();
2604 for (int i = frames.length - 1; i > -1; i--)
2606 if (frames[i] instanceof AppJmol)
2608 GStructureViewer af = (GStructureViewer) frames[i];
2612 if (avp.size() == 0)
2616 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2621 * Add Groovy Support to Jalview
2624 public void groovyShell_actionPerformed()
2628 openGroovyConsole();
2629 } catch (Exception ex)
2631 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2632 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2634 MessageManager.getString("label.couldnt_create_groovy_shell"),
2635 MessageManager.getString("label.groovy_support_failed"),
2636 JvOptionPane.ERROR_MESSAGE);
2641 * Open the Groovy console
2643 void openGroovyConsole()
2645 if (groovyConsole == null)
2647 groovyConsole = new groovy.ui.Console();
2648 groovyConsole.setVariable("Jalview", this);
2649 groovyConsole.run();
2652 * We allow only one console at a time, so that AlignFrame menu option
2653 * 'Calculate | Run Groovy script' is unambiguous.
2654 * Disable 'Groovy Console', and enable 'Run script', when the console is
2655 * opened, and the reverse when it is closed
2657 Window window = (Window) groovyConsole.getFrame();
2658 window.addWindowListener(new WindowAdapter()
2661 public void windowClosed(WindowEvent e)
2664 * rebind CMD-Q from Groovy Console to Jalview Quit
2667 enableExecuteGroovy(false);
2673 * show Groovy console window (after close and reopen)
2675 ((Window) groovyConsole.getFrame()).setVisible(true);
2678 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2679 * and disable opening a second console
2681 enableExecuteGroovy(true);
2685 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2686 * binding when opened
2688 protected void addQuitHandler()
2690 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2691 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2692 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2694 getRootPane().getActionMap().put("Quit", new AbstractAction()
2697 public void actionPerformed(ActionEvent e)
2705 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2708 * true if Groovy console is open
2710 public void enableExecuteGroovy(boolean enabled)
2713 * disable opening a second Groovy console
2714 * (or re-enable when the console is closed)
2716 groovyShell.setEnabled(!enabled);
2718 AlignFrame[] alignFrames = getAlignFrames();
2719 if (alignFrames != null)
2721 for (AlignFrame af : alignFrames)
2723 af.setGroovyEnabled(enabled);
2729 * Progress bars managed by the IProgressIndicator method.
2731 private Hashtable<Long, JPanel> progressBars;
2733 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2738 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2741 public void setProgressBar(String message, long id)
2743 if (progressBars == null)
2745 progressBars = new Hashtable<>();
2746 progressBarHandlers = new Hashtable<>();
2749 if (progressBars.get(new Long(id)) != null)
2751 JPanel panel = progressBars.remove(new Long(id));
2752 if (progressBarHandlers.contains(new Long(id)))
2754 progressBarHandlers.remove(new Long(id));
2756 removeProgressPanel(panel);
2760 progressBars.put(new Long(id), addProgressPanel(message));
2767 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2768 * jalview.gui.IProgressIndicatorHandler)
2771 public void registerHandler(final long id,
2772 final IProgressIndicatorHandler handler)
2774 if (progressBarHandlers == null
2775 || !progressBars.containsKey(new Long(id)))
2777 throw new Error(MessageManager.getString(
2778 "error.call_setprogressbar_before_registering_handler"));
2780 progressBarHandlers.put(new Long(id), handler);
2781 final JPanel progressPanel = progressBars.get(new Long(id));
2782 if (handler.canCancel())
2784 JButton cancel = new JButton(
2785 MessageManager.getString("action.cancel"));
2786 final IProgressIndicator us = this;
2787 cancel.addActionListener(new ActionListener()
2791 public void actionPerformed(ActionEvent e)
2793 handler.cancelActivity(id);
2794 us.setProgressBar(MessageManager
2795 .formatMessage("label.cancelled_params", new Object[]
2796 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2800 progressPanel.add(cancel, BorderLayout.EAST);
2806 * @return true if any progress bars are still active
2809 public boolean operationInProgress()
2811 if (progressBars != null && progressBars.size() > 0)
2819 * This will return the first AlignFrame holding the given viewport instance.
2820 * It will break if there are more than one AlignFrames viewing a particular
2824 * @return alignFrame for viewport
2826 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2828 if (desktop != null)
2830 AlignmentPanel[] aps = getAlignmentPanels(
2831 viewport.getSequenceSetId());
2832 for (int panel = 0; aps != null && panel < aps.length; panel++)
2834 if (aps[panel] != null && aps[panel].av == viewport)
2836 return aps[panel].alignFrame;
2843 public VamsasApplication getVamsasApplication()
2850 * flag set if jalview GUI is being operated programmatically
2852 private boolean inBatchMode = false;
2855 * check if jalview GUI is being operated programmatically
2857 * @return inBatchMode
2859 public boolean isInBatchMode()
2865 * set flag if jalview GUI is being operated programmatically
2867 * @param inBatchMode
2869 public void setInBatchMode(boolean inBatchMode)
2871 this.inBatchMode = inBatchMode;
2874 public void startServiceDiscovery()
2876 startServiceDiscovery(false);
2879 public void startServiceDiscovery(boolean blocking)
2881 boolean alive = true;
2882 Thread t0 = null, t1 = null, t2 = null;
2883 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2886 // todo: changesupport handlers need to be transferred
2887 if (discoverer == null)
2889 discoverer = new jalview.ws.jws1.Discoverer();
2890 // register PCS handler for desktop.
2891 discoverer.addPropertyChangeListener(changeSupport);
2893 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2894 // until we phase out completely
2895 (t0 = new Thread(discoverer)).start();
2898 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2900 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2901 .startDiscoverer(changeSupport);
2905 // TODO: do rest service discovery
2914 } catch (Exception e)
2917 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2918 || (t3 != null && t3.isAlive())
2919 || (t0 != null && t0.isAlive());
2925 * called to check if the service discovery process completed successfully.
2929 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2931 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2933 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2934 .getErrorMessages();
2937 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
2939 if (serviceChangedDialog == null)
2941 // only run if we aren't already displaying one of these.
2942 addDialogThread(serviceChangedDialog = new Runnable()
2949 * JalviewDialog jd =new JalviewDialog() {
2951 * @Override protected void cancelPressed() { // TODO
2952 * Auto-generated method stub
2954 * }@Override protected void okPressed() { // TODO
2955 * Auto-generated method stub
2957 * }@Override protected void raiseClosed() { // TODO
2958 * Auto-generated method stub
2960 * } }; jd.initDialogFrame(new
2961 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
2962 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
2963 * + " or mis-configured HTTP proxy settings.<br/>" +
2964 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
2966 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
2967 * ), true, true, "Web Service Configuration Problem", 450,
2970 * jd.waitForInput();
2972 JvOptionPane.showConfirmDialog(Desktop.desktop,
2973 new JLabel("<html><table width=\"450\"><tr><td>"
2974 + ermsg + "</td></tr></table>"
2975 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
2976 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
2977 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
2978 + " Tools->Preferences dialog box to change them.</p></html>"),
2979 "Web Service Configuration Problem",
2980 JvOptionPane.DEFAULT_OPTION,
2981 JvOptionPane.ERROR_MESSAGE);
2982 serviceChangedDialog = null;
2991 "Errors reported by JABA discovery service. Check web services preferences.\n"
2998 private Runnable serviceChangedDialog = null;
3001 * start a thread to open a URL in the configured browser. Pops up a warning
3002 * dialog to the user if there is an exception when calling out to the browser
3007 public static void showUrl(final String url)
3009 showUrl(url, Desktop.instance);
3013 * Like showUrl but allows progress handler to be specified
3017 * (null) or object implementing IProgressIndicator
3019 public static void showUrl(final String url,
3020 final IProgressIndicator progress)
3022 new Thread(new Runnable()
3029 if (progress != null)
3031 progress.setProgressBar(MessageManager
3032 .formatMessage("status.opening_params", new Object[]
3033 { url }), this.hashCode());
3035 jalview.util.BrowserLauncher.openURL(url);
3036 } catch (Exception ex)
3038 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3040 .getString("label.web_browser_not_found_unix"),
3041 MessageManager.getString("label.web_browser_not_found"),
3042 JvOptionPane.WARNING_MESSAGE);
3044 ex.printStackTrace();
3046 if (progress != null)
3048 progress.setProgressBar(null, this.hashCode());
3054 public static WsParamSetManager wsparamManager = null;
3056 public static ParamManager getUserParameterStore()
3058 if (wsparamManager == null)
3060 wsparamManager = new WsParamSetManager();
3062 return wsparamManager;
3066 * static hyperlink handler proxy method for use by Jalview's internal windows
3070 public static void hyperlinkUpdate(HyperlinkEvent e)
3072 if (e.getEventType() == EventType.ACTIVATED)
3077 url = e.getURL().toString();
3078 Desktop.showUrl(url);
3079 } catch (Exception x)
3083 if (Cache.log != null)
3085 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3090 "Couldn't handle string " + url + " as a URL.");
3093 // ignore any exceptions due to dud links.
3100 * single thread that handles display of dialogs to user.
3102 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3105 * flag indicating if dialogExecutor should try to acquire a permit
3107 private volatile boolean dialogPause = true;
3112 private java.util.concurrent.Semaphore block = new Semaphore(0);
3114 private static groovy.ui.Console groovyConsole;
3117 * add another dialog thread to the queue
3121 public void addDialogThread(final Runnable prompter)
3123 dialogExecutor.submit(new Runnable()
3133 } catch (InterruptedException x)
3138 if (instance == null)
3144 SwingUtilities.invokeAndWait(prompter);
3145 } catch (Exception q)
3147 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3153 public void startDialogQueue()
3155 // set the flag so we don't pause waiting for another permit and semaphore
3156 // the current task to begin
3157 dialogPause = false;
3162 protected void snapShotWindow_actionPerformed(ActionEvent e)
3166 ImageMaker im = new jalview.util.ImageMaker(
3167 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3168 getHeight(), of = new File("Jalview_snapshot"
3169 + System.currentTimeMillis() + ".eps"),
3170 "View of desktop", null, 0, false);
3173 paintAll(im.getGraphics());
3175 } catch (Exception q)
3177 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3181 Cache.log.info("Successfully written snapshot to file "
3182 + of.getAbsolutePath());
3186 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3187 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3188 * and location last time the view was expanded (if any). However it does not
3189 * remember the split pane divider location - this is set to match the
3190 * 'exploding' frame.
3194 public void explodeViews(SplitFrame sf)
3196 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3197 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3198 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3200 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3202 int viewCount = topPanels.size();
3209 * Processing in reverse order works, forwards order leaves the first panels
3210 * not visible. I don't know why!
3212 for (int i = viewCount - 1; i >= 0; i--)
3215 * Make new top and bottom frames. These take over the respective
3216 * AlignmentPanel objects, including their AlignmentViewports, so the
3217 * cdna/protein relationships between the viewports is carried over to the
3220 * explodedGeometry holds the (x, y) position of the previously exploded
3221 * SplitFrame, and the (width, height) of the AlignFrame component
3223 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3224 AlignFrame newTopFrame = new AlignFrame(topPanel);
3225 newTopFrame.setSize(oldTopFrame.getSize());
3226 newTopFrame.setVisible(true);
3227 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3228 .getExplodedGeometry();
3229 if (geometry != null)
3231 newTopFrame.setSize(geometry.getSize());
3234 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3235 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3236 newBottomFrame.setSize(oldBottomFrame.getSize());
3237 newBottomFrame.setVisible(true);
3238 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3239 .getExplodedGeometry();
3240 if (geometry != null)
3242 newBottomFrame.setSize(geometry.getSize());
3245 topPanel.av.setGatherViewsHere(false);
3246 bottomPanel.av.setGatherViewsHere(false);
3247 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3249 if (geometry != null)
3251 splitFrame.setLocation(geometry.getLocation());
3253 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3257 * Clear references to the panels (now relocated in the new SplitFrames)
3258 * before closing the old SplitFrame.
3261 bottomPanels.clear();
3266 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3267 * back into the given SplitFrame as additional views. Note that the gathered
3268 * frames may themselves have multiple views.
3272 public void gatherViews(GSplitFrame source)
3275 * special handling of explodedGeometry for a view within a SplitFrame: - it
3276 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3277 * height) of the AlignFrame component
3279 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3280 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3281 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3282 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3283 myBottomFrame.viewport
3284 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3285 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3286 myTopFrame.viewport.setGatherViewsHere(true);
3287 myBottomFrame.viewport.setGatherViewsHere(true);
3288 String topViewId = myTopFrame.viewport.getSequenceSetId();
3289 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3291 JInternalFrame[] frames = desktop.getAllFrames();
3292 for (JInternalFrame frame : frames)
3294 if (frame instanceof SplitFrame && frame != source)
3296 SplitFrame sf = (SplitFrame) frame;
3297 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3298 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3299 boolean gatherThis = false;
3300 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3302 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3303 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3304 if (topViewId.equals(topPanel.av.getSequenceSetId())
3305 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3308 topPanel.av.setGatherViewsHere(false);
3309 bottomPanel.av.setGatherViewsHere(false);
3310 topPanel.av.setExplodedGeometry(
3311 new Rectangle(sf.getLocation(), topFrame.getSize()));
3312 bottomPanel.av.setExplodedGeometry(
3313 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3314 myTopFrame.addAlignmentPanel(topPanel, false);
3315 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3321 topFrame.getAlignPanels().clear();
3322 bottomFrame.getAlignPanels().clear();
3329 * The dust settles...give focus to the tab we did this from.
3331 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3334 public static groovy.ui.Console getGroovyConsole()
3336 return groovyConsole;
3340 * handles the payload of a drag and drop event.
3342 * TODO refactor to desktop utilities class
3345 * - Data source strings extracted from the drop event
3347 * - protocol for each data source extracted from the drop event
3351 * - the payload from the drop event
3354 public static void transferFromDropTarget(List<String> files,
3355 List<DataSourceType> protocols, DropTargetDropEvent evt,
3356 Transferable t) throws Exception
3359 DataFlavor uriListFlavor = new DataFlavor(
3360 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3363 urlFlavour = new DataFlavor(
3364 "application/x-java-url; class=java.net.URL");
3365 } catch (ClassNotFoundException cfe)
3367 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3370 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3375 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3376 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3377 // means url may be null.
3380 protocols.add(DataSourceType.URL);
3381 files.add(url.toString());
3382 Cache.log.debug("Drop handled as URL dataflavor "
3383 + files.get(files.size() - 1));
3388 if (Platform.isAMac())
3391 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3395 } catch (Throwable ex)
3397 Cache.log.debug("URL drop handler failed.", ex);
3400 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3402 // Works on Windows and MacOSX
3403 Cache.log.debug("Drop handled as javaFileListFlavor");
3404 for (Object file : (List) t
3405 .getTransferData(DataFlavor.javaFileListFlavor))
3407 files.add(((File) file).toString());
3408 protocols.add(DataSourceType.FILE);
3413 // Unix like behaviour
3414 boolean added = false;
3416 if (t.isDataFlavorSupported(uriListFlavor))
3418 Cache.log.debug("Drop handled as uriListFlavor");
3419 // This is used by Unix drag system
3420 data = (String) t.getTransferData(uriListFlavor);
3424 // fallback to text: workaround - on OSX where there's a JVM bug
3425 Cache.log.debug("standard URIListFlavor failed. Trying text");
3426 // try text fallback
3427 DataFlavor textDf = new DataFlavor(
3428 "text/plain;class=java.lang.String");
3429 if (t.isDataFlavorSupported(textDf))
3431 data = (String) t.getTransferData(textDf);
3434 Cache.log.debug("Plain text drop content returned "
3435 + (data == null ? "Null - failed" : data));
3440 while (protocols.size() < files.size())
3442 Cache.log.debug("Adding missing FILE protocol for "
3443 + files.get(protocols.size()));
3444 protocols.add(DataSourceType.FILE);
3446 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3447 data, "\r\n"); st.hasMoreTokens();)
3450 String s = st.nextToken();
3451 if (s.startsWith("#"))
3453 // the line is a comment (as per the RFC 2483)
3456 java.net.URI uri = new java.net.URI(s);
3457 if (uri.getScheme().toLowerCase().startsWith("http"))
3459 protocols.add(DataSourceType.URL);
3460 files.add(uri.toString());
3464 // otherwise preserve old behaviour: catch all for file objects
3465 java.io.File file = new java.io.File(uri);
3466 protocols.add(DataSourceType.FILE);
3467 files.add(file.toString());
3472 if (Cache.log.isDebugEnabled())
3474 if (data == null || !added)
3477 if (t.getTransferDataFlavors() != null
3478 && t.getTransferDataFlavors().length > 0)
3481 "Couldn't resolve drop data. Here are the supported flavors:");
3482 for (DataFlavor fl : t.getTransferDataFlavors())
3485 "Supported transfer dataflavor: " + fl.toString());
3486 Object df = t.getTransferData(fl);
3489 Cache.log.debug("Retrieves: " + df);
3493 Cache.log.debug("Retrieved nothing");
3499 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3505 if (Platform.isWindows())
3508 Cache.log.debug("Scanning dropped content for Windows Link Files");
3510 // resolve any .lnk files in the file drop
3511 for (int f = 0; f < files.size(); f++)
3513 String source = files.get(f).toLowerCase();
3514 if (protocols.get(f).equals(DataSourceType.FILE)
3515 && (source.endsWith(".lnk") || source.endsWith(".url")
3516 || source.endsWith(".site")))
3519 File lf = new File(files.get(f));
3520 // process link file to get a URL
3521 Cache.log.debug("Found potential link file: " + lf);
3522 WindowsShortcut wscfile = new WindowsShortcut(lf);
3523 String fullname = wscfile.getRealFilename();
3524 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3525 files.set(f, fullname);
3526 Cache.log.debug("Parsed real filename " + fullname
3527 + " to extract protocol: " + protocols.get(f));
3529 catch (Exception ex)
3531 Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
3539 * Sets the Preferences property for experimental features to True or False
3540 * depending on the state of the controlling menu item
3543 protected void showExperimental_actionPerformed(boolean selected)
3545 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3549 * Answers a (possibly empty) list of any structure viewer frames (currently
3550 * for either Jmol or Chimera) which are currently open. This may optionally
3551 * be restricted to viewers of a specified class, or viewers linked to a
3552 * specified alignment panel.
3555 * if not null, only return viewers linked to this panel
3556 * @param structureViewerClass
3557 * if not null, only return viewers of this class
3560 public List<StructureViewerBase> getStructureViewers(
3561 AlignmentPanel apanel,
3562 Class<? extends StructureViewerBase> structureViewerClass)
3564 List<StructureViewerBase> result = new ArrayList<>();
3565 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3567 for (JInternalFrame frame : frames)
3569 if (frame instanceof StructureViewerBase)
3571 if (structureViewerClass == null
3572 || structureViewerClass.isInstance(frame))
3575 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3577 result.add((StructureViewerBase) frame);