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,
392 jconsole = new Console(this, showjconsole);
393 // add essential build information
394 jconsole.setHeader("Jalview Version: "
395 + jalview.bin.Cache.getProperty("VERSION") + "\n"
396 + "Jalview Installation: "
397 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
398 + "\n" + "Build Date: "
399 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
400 + "Java version: " + System.getProperty("java.version") + "\n"
401 + System.getProperty("os.arch") + " "
402 + System.getProperty("os.name") + " "
403 + System.getProperty("os.version"));
405 showConsole(showjconsole);
407 showNews.setVisible(false);
409 experimentalFeatures.setSelected(showExperimental());
411 getIdentifiersOrgData();
415 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
416 // Spawn a thread that shows the splashscreen
418 SwingUtilities.invokeLater(new Runnable()
427 // Thread off a new instance of the file chooser - this reduces the time it
428 // takes to open it later on.
429 new Thread(new Runnable()
434 Cache.log.debug("Filechooser init thread started.");
435 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
436 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
438 Cache.log.debug("Filechooser init thread finished.");
441 // Add the service change listener
442 changeSupport.addJalviewPropertyChangeListener("services",
443 new PropertyChangeListener()
447 public void propertyChange(PropertyChangeEvent evt)
449 Cache.log.debug("Firing service changed event for "
450 + evt.getNewValue());
451 JalviewServicesChanged(evt);
456 } // end BH 2018 ignore
458 this.addWindowListener(new WindowAdapter()
461 public void windowClosing(WindowEvent evt)
468 this.addMouseListener(ma = new MouseAdapter()
471 public void mousePressed(MouseEvent evt)
473 if (evt.isPopupTrigger()) // Mac
475 showPasteMenu(evt.getX(), evt.getY());
480 public void mouseReleased(MouseEvent evt)
482 if (evt.isPopupTrigger()) // Windows
484 showPasteMenu(evt.getX(), evt.getY());
488 desktop.addMouseListener(ma);
493 * Answers true if user preferences to enable experimental features is True
498 public boolean showExperimental()
500 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
501 Boolean.FALSE.toString());
502 return Boolean.valueOf(experimental).booleanValue();
505 public void doConfigureStructurePrefs()
507 // configure services
508 StructureSelectionManager ssm = StructureSelectionManager
509 .getStructureSelectionManager(this);
510 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
512 ssm.setAddTempFacAnnot(jalview.bin.Cache
513 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
514 ssm.setProcessSecondaryStructure(jalview.bin.Cache
515 .getDefault(Preferences.STRUCT_FROM_PDB, true));
516 ssm.setSecStructServices(
517 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
521 ssm.setAddTempFacAnnot(false);
522 ssm.setProcessSecondaryStructure(false);
523 ssm.setSecStructServices(false);
527 public void checkForNews()
536 final Desktop me = this;
537 // Thread off the news reader, in case there are connection problems.
538 addDialogThread(new Runnable()
543 Cache.log.debug("Starting news thread.");
545 jvnews = new BlogReader(me);
546 showNews.setVisible(true);
547 Cache.log.debug("Completed news thread.");
553 public void getIdentifiersOrgData()
555 // Thread off the identifiers fetcher
556 addDialogThread(new Runnable()
561 Cache.log.debug("Downloading data from identifiers.org");
562 UrlDownloadClient client = new UrlDownloadClient();
565 client.download(IdOrgSettings.getUrl(),
566 IdOrgSettings.getDownloadLocation());
567 } catch (IOException e)
569 Cache.log.debug("Exception downloading identifiers.org data"
577 protected void showNews_actionPerformed(ActionEvent e)
579 showNews(showNews.isSelected());
582 void showNews(boolean visible)
591 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
592 showNews.setSelected(visible);
593 if (visible && !jvnews.isVisible())
595 new Thread(new Runnable()
600 long now = System.currentTimeMillis();
601 Desktop.instance.setProgressBar(
602 MessageManager.getString("status.refreshing_news"),
604 jvnews.refreshNews();
605 Desktop.instance.setProgressBar(null, now);
614 * recover the last known dimensions for a jalview window
617 * - empty string is desktop, all other windows have unique prefix
618 * @return null or last known dimensions scaled to current geometry (if last
619 * window geom was known)
621 Rectangle getLastKnownDimensions(String windowName)
623 // TODO: lock aspect ratio for scaling desktop Bug #0058199
624 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
625 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
626 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
627 String width = jalview.bin.Cache
628 .getProperty(windowName + "SCREEN_WIDTH");
629 String height = jalview.bin.Cache
630 .getProperty(windowName + "SCREEN_HEIGHT");
631 if ((x != null) && (y != null) && (width != null) && (height != null))
633 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
634 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
635 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
637 // attempt #1 - try to cope with change in screen geometry - this
638 // version doesn't preserve original jv aspect ratio.
639 // take ratio of current screen size vs original screen size.
640 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
641 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
642 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
643 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
644 // rescale the bounds depending upon the current screen geometry.
645 ix = (int) (ix * sw);
646 iw = (int) (iw * sw);
647 iy = (int) (iy * sh);
648 ih = (int) (ih * sh);
649 while (ix >= screenSize.width)
651 jalview.bin.Cache.log.debug(
652 "Window geometry location recall error: shifting horizontal to within screenbounds.");
653 ix -= screenSize.width;
655 while (iy >= screenSize.height)
657 jalview.bin.Cache.log.debug(
658 "Window geometry location recall error: shifting vertical to within screenbounds.");
659 iy -= screenSize.height;
661 jalview.bin.Cache.log.debug(
662 "Got last known dimensions for " + windowName + ": x:" + ix
663 + " y:" + iy + " width:" + iw + " height:" + ih);
665 // return dimensions for new instance
666 return new Rectangle(ix, iy, iw, ih);
671 private void doVamsasClientCheck()
673 if (/** @j2sNative false && */ // BH 2018
674 jalview.bin.Cache.vamsasJarsPresent())
676 setupVamsasDisconnectedGui();
677 VamsasMenu.setVisible(true);
678 final Desktop us = this;
679 VamsasMenu.addMenuListener(new MenuListener()
681 // this listener remembers when the menu was first selected, and
682 // doesn't rebuild the session list until it has been cleared and
684 boolean refresh = true;
687 public void menuCanceled(MenuEvent e)
693 public void menuDeselected(MenuEvent e)
699 public void menuSelected(MenuEvent e)
703 us.buildVamsasStMenu();
708 vamsasStart.setVisible(true);
712 void showPasteMenu(int x, int y)
714 JPopupMenu popup = new JPopupMenu();
715 JMenuItem item = new JMenuItem(
716 MessageManager.getString("label.paste_new_window"));
717 item.addActionListener(new ActionListener()
720 public void actionPerformed(ActionEvent evt)
727 popup.show(this, x, y);
734 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
735 Transferable contents = c.getContents(this);
737 if (contents != null)
739 String file = (String) contents
740 .getTransferData(DataFlavor.stringFlavor);
742 FileFormatI format = new IdentifyFile().identify(file,
743 DataSourceType.PASTE);
745 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
748 } catch (Exception ex)
751 "Unable to paste alignment from system clipboard:\n" + ex);
756 * Adds and opens the given frame to the desktop
767 public static synchronized void addInternalFrame(
768 final JInternalFrame frame, String title, int w, int h)
770 addInternalFrame(frame, title, true, w, h, true, false);
774 * Add an internal frame to the Jalview desktop
781 * When true, display frame immediately, otherwise, caller must call
782 * setVisible themselves.
788 public static synchronized void addInternalFrame(
789 final JInternalFrame frame, String title, boolean makeVisible,
792 addInternalFrame(frame, title, makeVisible, w, h, true, false);
796 * Add an internal frame to the Jalview desktop and make it visible
809 public static synchronized void addInternalFrame(
810 final JInternalFrame frame, String title, int w, int h,
813 addInternalFrame(frame, title, true, w, h, resizable, false);
817 * Add an internal frame to the Jalview desktop
824 * When true, display frame immediately, otherwise, caller must call
825 * setVisible themselves.
832 * @param ignoreMinSize
833 * Do not set the default minimum size for frame
835 public static synchronized void addInternalFrame(
836 final JInternalFrame frame, String title, boolean makeVisible,
837 int w, int h, boolean resizable, boolean ignoreMinSize)
840 // TODO: allow callers to determine X and Y position of frame (eg. via
842 // TODO: consider fixing method to update entries in the window submenu with
843 // the current window title
845 frame.setTitle(title);
846 if (frame.getWidth() < 1 || frame.getHeight() < 1)
850 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
851 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
852 // IF JALVIEW IS RUNNING HEADLESS
853 // ///////////////////////////////////////////////
854 if (instance == null || (System.getProperty("java.awt.headless") != null
855 && System.getProperty("java.awt.headless").equals("true")))
864 frame.setMinimumSize(
865 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
867 // Set default dimension for Alignment Frame window.
868 // The Alignment Frame window could be added from a number of places,
870 // I did this here in order not to miss out on any Alignment frame.
871 if (frame instanceof AlignFrame)
873 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
874 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
878 frame.setVisible(makeVisible);
879 frame.setClosable(true);
880 frame.setResizable(resizable);
881 frame.setMaximizable(resizable);
882 frame.setIconifiable(resizable);
883 frame.setOpaque(false);
885 if (frame.getX() < 1 && frame.getY() < 1)
887 frame.setLocation(xOffset * openFrameCount,
888 yOffset * ((openFrameCount - 1) % 10) + yOffset);
892 * add an entry for the new frame in the Window menu
893 * (and remove it when the frame is closed)
895 final JMenuItem menuItem = new JMenuItem(title);
896 frame.addInternalFrameListener(new InternalFrameAdapter()
899 public void internalFrameActivated(InternalFrameEvent evt)
901 JInternalFrame itf = desktop.getSelectedFrame();
904 if (itf instanceof AlignFrame)
906 Jalview.setCurrentAlignFrame((AlignFrame) itf);
913 public void internalFrameClosed(InternalFrameEvent evt)
915 PaintRefresher.RemoveComponent(frame);
918 * defensive check to prevent frames being
919 * added half off the window
921 if (openFrameCount > 0)
927 * ensure no reference to alignFrame retained by menu item listener
929 if (menuItem.getActionListeners().length > 0)
931 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
933 windowMenu.remove(menuItem);
937 menuItem.addActionListener(new ActionListener()
940 public void actionPerformed(ActionEvent e)
944 frame.setSelected(true);
945 frame.setIcon(false);
946 } catch (java.beans.PropertyVetoException ex)
953 setKeyBindings(frame);
957 windowMenu.add(menuItem);
962 frame.setSelected(true);
963 frame.requestFocus();
964 } catch (java.beans.PropertyVetoException ve)
966 } catch (java.lang.ClassCastException cex)
969 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
975 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
980 private static void setKeyBindings(JInternalFrame frame)
982 @SuppressWarnings("serial")
983 final Action closeAction = new AbstractAction()
986 public void actionPerformed(ActionEvent e)
993 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
995 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
996 InputEvent.CTRL_DOWN_MASK);
997 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
998 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1000 InputMap inputMap = frame
1001 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1002 String ctrlW = ctrlWKey.toString();
1003 inputMap.put(ctrlWKey, ctrlW);
1004 inputMap.put(cmdWKey, ctrlW);
1006 ActionMap actionMap = frame.getActionMap();
1007 actionMap.put(ctrlW, closeAction);
1011 public void lostOwnership(Clipboard clipboard, Transferable contents)
1015 Desktop.jalviewClipboard = null;
1018 internalCopy = false;
1022 public void dragEnter(DropTargetDragEvent evt)
1027 public void dragExit(DropTargetEvent evt)
1032 public void dragOver(DropTargetDragEvent evt)
1037 public void dropActionChanged(DropTargetDragEvent evt)
1048 public void drop(DropTargetDropEvent evt)
1050 boolean success = true;
1051 // JAL-1552 - acceptDrop required before getTransferable call for
1052 // Java's Transferable for native dnd
1053 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1054 Transferable t = evt.getTransferable();
1055 List<String> files = new ArrayList<>();
1056 List<DataSourceType> protocols = new ArrayList<>();
1060 Desktop.transferFromDropTarget(files, protocols, evt, t);
1061 } catch (Exception e)
1063 e.printStackTrace();
1071 for (int i = 0; i < files.size(); i++)
1073 String file = files.get(i).toString();
1074 DataSourceType protocol = (protocols == null)
1075 ? DataSourceType.FILE
1077 FileFormatI format = null;
1079 if (file.endsWith(".jar"))
1081 format = FileFormat.Jalview;
1086 format = new IdentifyFile().identify(file, protocol);
1089 new FileLoader().LoadFile(file, protocol, format);
1092 } catch (Exception ex)
1097 evt.dropComplete(success); // need this to ensure input focus is properly
1098 // transfered to any new windows created
1108 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1110 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1111 JalviewFileChooser chooser = JalviewFileChooser
1112 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1114 chooser.setFileView(new JalviewFileView());
1115 chooser.setDialogTitle(
1116 MessageManager.getString("label.open_local_file"));
1117 chooser.setToolTipText(MessageManager.getString("action.open"));
1119 int value = chooser.showOpenDialog(this);
1121 if (value == JalviewFileChooser.APPROVE_OPTION)
1123 String choice = chooser.getSelectedFile().getPath();
1124 Cache.setProperty("LAST_DIRECTORY",
1125 chooser.getSelectedFile().getParent());
1127 FileFormatI format = chooser.getSelectedFormat();
1130 * Call IdentifyFile to verify the file contains what its extension implies.
1131 * Skip this step for dynamically added file formats, because
1132 * IdentifyFile does not know how to recognise them.
1134 if (FileFormats.getInstance().isIdentifiable(format))
1138 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1139 } catch (FileFormatException e)
1141 // format = null; //??
1145 if (viewport != null)
1147 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1152 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1164 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1166 // This construct allows us to have a wider textfield
1168 JLabel label = new JLabel(
1169 MessageManager.getString("label.input_file_url"));
1170 final JComboBox history = new JComboBox();
1172 JPanel panel = new JPanel(new GridLayout(2, 1));
1175 history.setPreferredSize(new Dimension(400, 20));
1176 history.setEditable(true);
1177 history.addItem("http://www.");
1179 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1183 if (historyItems != null)
1185 st = new StringTokenizer(historyItems, "\t");
1187 while (st.hasMoreTokens())
1189 history.addItem(st.nextElement());
1193 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1194 MessageManager.getString("label.input_alignment_from_url"),
1195 JvOptionPane.OK_CANCEL_OPTION);
1197 if (reply != JvOptionPane.OK_OPTION)
1202 String url = history.getSelectedItem().toString();
1204 if (url.toLowerCase().endsWith(".jar"))
1206 if (viewport != null)
1208 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1209 FileFormat.Jalview);
1213 new FileLoader().LoadFile(url, DataSourceType.URL,
1214 FileFormat.Jalview);
1219 FileFormatI format = null;
1222 format = new IdentifyFile().identify(url, DataSourceType.URL);
1223 } catch (FileFormatException e)
1225 // TODO revise error handling, distinguish between
1226 // URL not found and response not valid
1231 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1232 MessageManager.formatMessage("label.couldnt_locate",
1235 MessageManager.getString("label.url_not_found"),
1236 JvOptionPane.WARNING_MESSAGE);
1241 if (viewport != null)
1243 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1248 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1254 * Opens the CutAndPaste window for the user to paste an alignment in to
1257 * - if not null, the pasted alignment is added to the current
1258 * alignment; if null, to a new alignment window
1261 public void inputTextboxMenuItem_actionPerformed(
1262 AlignmentViewPanel viewPanel)
1264 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1265 cap.setForInput(viewPanel);
1266 Desktop.addInternalFrame(cap,
1267 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1277 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1278 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1280 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1281 screen.height + "");
1282 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1283 getWidth(), getHeight()));
1285 if (jconsole != null)
1287 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1288 jconsole.stopConsole();
1292 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1295 if (dialogExecutor != null)
1297 dialogExecutor.shutdownNow();
1299 closeAll_actionPerformed(null);
1301 if (groovyConsole != null)
1303 // suppress a possible repeat prompt to save script
1304 groovyConsole.setDirty(false);
1305 groovyConsole.exit();
1310 private void storeLastKnownDimensions(String string, Rectangle jc)
1312 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1313 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1314 + " height:" + jc.height);
1316 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1317 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1318 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1319 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1329 public void aboutMenuItem_actionPerformed(ActionEvent e)
1331 // StringBuffer message = getAboutMessage(false);
1332 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1334 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1335 new Thread(new Runnable()
1340 new SplashScreen(true);
1345 public StringBuffer getAboutMessage(boolean shortv)
1347 StringBuffer message = new StringBuffer();
1348 message.append("<html>");
1351 message.append("<h1><strong>Version: "
1352 + jalview.bin.Cache.getProperty("VERSION")
1353 + "</strong></h1>");
1354 message.append("<strong>Last Updated: <em>"
1355 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1356 + "</em></strong>");
1362 message.append("<strong>Version "
1363 + jalview.bin.Cache.getProperty("VERSION")
1364 + "; last updated: "
1365 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1368 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1369 .equals("Checking"))
1371 message.append("<br>...Checking latest version...</br>");
1373 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1374 .equals(jalview.bin.Cache.getProperty("VERSION")))
1376 boolean red = false;
1377 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1378 .indexOf("automated build") == -1)
1381 // Displayed when code version and jnlp version do not match and code
1382 // version is not a development build
1383 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1386 message.append("<br>!! Version "
1387 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1389 + " is available for download from "
1390 + jalview.bin.Cache.getDefault("www.jalview.org",
1391 "http://www.jalview.org")
1395 message.append("</div>");
1398 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1400 "The Jalview Authors (See AUTHORS file for current list)")
1401 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1402 + "<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"
1403 + "<br><br>If you use Jalview, please cite:"
1404 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1405 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1406 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1418 public void documentationMenuItem_actionPerformed(ActionEvent e)
1422 Help.showHelpWindow();
1423 } catch (Exception ex)
1429 public void closeAll_actionPerformed(ActionEvent e)
1431 // TODO show a progress bar while closing?
1432 JInternalFrame[] frames = desktop.getAllFrames();
1433 for (int i = 0; i < frames.length; i++)
1437 frames[i].setClosed(true);
1438 } catch (java.beans.PropertyVetoException ex)
1442 Jalview.setCurrentAlignFrame(null);
1443 System.out.println("ALL CLOSED");
1444 if (v_client != null)
1446 // TODO clear binding to vamsas document objects on close_all
1450 * reset state of singleton objects as appropriate (clear down session state
1451 * when all windows are closed)
1453 StructureSelectionManager ssm = StructureSelectionManager
1454 .getStructureSelectionManager(this);
1462 public void raiseRelated_actionPerformed(ActionEvent e)
1464 reorderAssociatedWindows(false, false);
1468 public void minimizeAssociated_actionPerformed(ActionEvent e)
1470 reorderAssociatedWindows(true, false);
1473 void closeAssociatedWindows()
1475 reorderAssociatedWindows(false, true);
1481 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1485 protected void garbageCollect_actionPerformed(ActionEvent e)
1487 // We simply collect the garbage
1488 jalview.bin.Cache.log.debug("Collecting garbage...");
1490 jalview.bin.Cache.log.debug("Finished garbage collection.");
1497 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1501 protected void showMemusage_actionPerformed(ActionEvent e)
1503 desktop.showMemoryUsage(showMemusage.isSelected());
1510 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1514 protected void showConsole_actionPerformed(ActionEvent e)
1516 showConsole(showConsole.isSelected());
1519 Console jconsole = null;
1522 * control whether the java console is visible or not
1526 void showConsole(boolean selected)
1528 // TODO: decide if we should update properties file
1529 if (jconsole != null) // BH 2018
1531 showConsole.setSelected(selected);
1532 Cache.setProperty("SHOW_JAVA_CONSOLE",
1533 Boolean.valueOf(selected).toString());
1534 jconsole.setVisible(selected);
1538 void reorderAssociatedWindows(boolean minimize, boolean close)
1540 JInternalFrame[] frames = desktop.getAllFrames();
1541 if (frames == null || frames.length < 1)
1546 AlignmentViewport source = null, target = null;
1547 if (frames[0] instanceof AlignFrame)
1549 source = ((AlignFrame) frames[0]).getCurrentView();
1551 else if (frames[0] instanceof TreePanel)
1553 source = ((TreePanel) frames[0]).getViewPort();
1555 else if (frames[0] instanceof PCAPanel)
1557 source = ((PCAPanel) frames[0]).av;
1559 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1561 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1566 for (int i = 0; i < frames.length; i++)
1569 if (frames[i] == null)
1573 if (frames[i] instanceof AlignFrame)
1575 target = ((AlignFrame) frames[i]).getCurrentView();
1577 else if (frames[i] instanceof TreePanel)
1579 target = ((TreePanel) frames[i]).getViewPort();
1581 else if (frames[i] instanceof PCAPanel)
1583 target = ((PCAPanel) frames[i]).av;
1585 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1587 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1590 if (source == target)
1596 frames[i].setClosed(true);
1600 frames[i].setIcon(minimize);
1603 frames[i].toFront();
1607 } catch (java.beans.PropertyVetoException ex)
1622 protected void preferences_actionPerformed(ActionEvent e)
1634 public void saveState_actionPerformed(ActionEvent e)
1636 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1639 chooser.setFileView(new JalviewFileView());
1640 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1642 int value = chooser.showSaveDialog(this);
1644 if (value == JalviewFileChooser.APPROVE_OPTION)
1646 final Desktop me = this;
1647 final java.io.File choice = chooser.getSelectedFile();
1648 setProjectFile(choice);
1650 new Thread(new Runnable()
1655 // TODO: refactor to Jalview desktop session controller action.
1656 setProgressBar(MessageManager.formatMessage(
1657 "label.saving_jalview_project", new Object[]
1658 { choice.getName() }), choice.hashCode());
1659 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1660 choice.getParent());
1661 // TODO catch and handle errors for savestate
1662 // TODO prevent user from messing with the Desktop whilst we're saving
1665 new Jalview2XML().saveState(choice);
1666 } catch (OutOfMemoryError oom)
1669 "Whilst saving current state to " + choice.getName(),
1671 } catch (Exception ex)
1674 "Problems whilst trying to save to " + choice.getName(),
1676 JvOptionPane.showMessageDialog(me,
1677 MessageManager.formatMessage(
1678 "label.error_whilst_saving_current_state_to",
1680 { choice.getName() }),
1681 MessageManager.getString("label.couldnt_save_project"),
1682 JvOptionPane.WARNING_MESSAGE);
1684 setProgressBar(null, choice.hashCode());
1690 private void setProjectFile(File choice)
1692 this.projectFile = choice;
1695 public File getProjectFile()
1697 return this.projectFile;
1707 public void loadState_actionPerformed(ActionEvent e)
1709 JalviewFileChooser chooser = new JalviewFileChooser(
1710 Cache.getProperty("LAST_DIRECTORY"), new String[]
1713 { "Jalview Project", "Jalview Project (old)" },
1715 chooser.setFileView(new JalviewFileView());
1716 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1718 int value = chooser.showOpenDialog(this);
1720 if (value == JalviewFileChooser.APPROVE_OPTION)
1722 final File selectedFile = chooser.getSelectedFile();
1723 setProjectFile(selectedFile);
1724 final String choice = selectedFile.getAbsolutePath();
1725 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1726 new Thread(new Runnable()
1731 setProgressBar(MessageManager.formatMessage(
1732 "label.loading_jalview_project", new Object[]
1733 { choice }), choice.hashCode());
1736 new Jalview2XML().loadJalviewAlign(choice);
1737 } catch (OutOfMemoryError oom)
1739 new OOMWarning("Whilst loading project from " + choice, oom);
1740 } catch (Exception ex)
1743 "Problems whilst loading project from " + choice, ex);
1744 JvOptionPane.showMessageDialog(Desktop.desktop,
1745 MessageManager.formatMessage(
1746 "label.error_whilst_loading_project_from",
1749 MessageManager.getString("label.couldnt_load_project"),
1750 JvOptionPane.WARNING_MESSAGE);
1752 setProgressBar(null, choice.hashCode());
1759 public void inputSequence_actionPerformed(ActionEvent e)
1761 new SequenceFetcher(this);
1764 JPanel progressPanel;
1766 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1768 public void startLoading(final String fileName)
1770 if (fileLoadingCount == 0)
1772 fileLoadingPanels.add(addProgressPanel(MessageManager
1773 .formatMessage("label.loading_file", new Object[]
1779 private JPanel addProgressPanel(String string)
1781 if (progressPanel == null)
1783 progressPanel = new JPanel(new GridLayout(1, 1));
1784 totalProgressCount = 0;
1785 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1787 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1788 JProgressBar progressBar = new JProgressBar();
1789 progressBar.setIndeterminate(true);
1791 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1793 thisprogress.add(progressBar, BorderLayout.CENTER);
1794 progressPanel.add(thisprogress);
1795 ((GridLayout) progressPanel.getLayout()).setRows(
1796 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1797 ++totalProgressCount;
1798 instance.validate();
1799 return thisprogress;
1802 int totalProgressCount = 0;
1804 private void removeProgressPanel(JPanel progbar)
1806 if (progressPanel != null)
1808 synchronized (progressPanel)
1810 progressPanel.remove(progbar);
1811 GridLayout gl = (GridLayout) progressPanel.getLayout();
1812 gl.setRows(gl.getRows() - 1);
1813 if (--totalProgressCount < 1)
1815 this.getContentPane().remove(progressPanel);
1816 progressPanel = null;
1823 public void stopLoading()
1826 if (fileLoadingCount < 1)
1828 while (fileLoadingPanels.size() > 0)
1830 removeProgressPanel(fileLoadingPanels.remove(0));
1832 fileLoadingPanels.clear();
1833 fileLoadingCount = 0;
1838 public static int getViewCount(String alignmentId)
1840 AlignmentViewport[] aps = getViewports(alignmentId);
1841 return (aps == null) ? 0 : aps.length;
1846 * @param alignmentId
1847 * - if null, all sets are returned
1848 * @return all AlignmentPanels concerning the alignmentId sequence set
1850 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1852 if (Desktop.desktop == null)
1854 // no frames created and in headless mode
1855 // TODO: verify that frames are recoverable when in headless mode
1858 List<AlignmentPanel> aps = new ArrayList<>();
1859 AlignFrame[] frames = getAlignFrames();
1864 for (AlignFrame af : frames)
1866 for (AlignmentPanel ap : af.alignPanels)
1868 if (alignmentId == null
1869 || alignmentId.equals(ap.av.getSequenceSetId()))
1875 if (aps.size() == 0)
1879 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1884 * get all the viewports on an alignment.
1886 * @param sequenceSetId
1887 * unique alignment id (may be null - all viewports returned in that
1889 * @return all viewports on the alignment bound to sequenceSetId
1891 public static AlignmentViewport[] getViewports(String sequenceSetId)
1893 List<AlignmentViewport> viewp = new ArrayList<>();
1894 if (desktop != null)
1896 AlignFrame[] frames = Desktop.getAlignFrames();
1898 for (AlignFrame afr : frames)
1900 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1901 .equals(sequenceSetId))
1903 if (afr.alignPanels != null)
1905 for (AlignmentPanel ap : afr.alignPanels)
1907 if (sequenceSetId == null
1908 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1916 viewp.add(afr.getViewport());
1920 if (viewp.size() > 0)
1922 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1929 * Explode the views in the given frame into separate AlignFrame
1933 public static void explodeViews(AlignFrame af)
1935 int size = af.alignPanels.size();
1941 for (int i = 0; i < size; i++)
1943 AlignmentPanel ap = af.alignPanels.get(i);
1944 AlignFrame newaf = new AlignFrame(ap);
1947 * Restore the view's last exploded frame geometry if known. Multiple
1948 * views from one exploded frame share and restore the same (frame)
1949 * position and size.
1951 Rectangle geometry = ap.av.getExplodedGeometry();
1952 if (geometry != null)
1954 newaf.setBounds(geometry);
1957 ap.av.setGatherViewsHere(false);
1959 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1960 AlignFrame.DEFAULT_HEIGHT);
1963 af.alignPanels.clear();
1964 af.closeMenuItem_actionPerformed(true);
1969 * Gather expanded views (separate AlignFrame's) with the same sequence set
1970 * identifier back in to this frame as additional views, and close the
1971 * expanded views. Note the expanded frames may themselves have multiple
1972 * views. We take the lot.
1976 public void gatherViews(AlignFrame source)
1978 source.viewport.setGatherViewsHere(true);
1979 source.viewport.setExplodedGeometry(source.getBounds());
1980 JInternalFrame[] frames = desktop.getAllFrames();
1981 String viewId = source.viewport.getSequenceSetId();
1983 for (int t = 0; t < frames.length; t++)
1985 if (frames[t] instanceof AlignFrame && frames[t] != source)
1987 AlignFrame af = (AlignFrame) frames[t];
1988 boolean gatherThis = false;
1989 for (int a = 0; a < af.alignPanels.size(); a++)
1991 AlignmentPanel ap = af.alignPanels.get(a);
1992 if (viewId.equals(ap.av.getSequenceSetId()))
1995 ap.av.setGatherViewsHere(false);
1996 ap.av.setExplodedGeometry(af.getBounds());
1997 source.addAlignmentPanel(ap, false);
2003 af.alignPanels.clear();
2004 af.closeMenuItem_actionPerformed(true);
2011 jalview.gui.VamsasApplication v_client = null;
2014 public void vamsasImport_actionPerformed(ActionEvent e)
2016 if (v_client == null)
2018 // Load and try to start a session.
2019 JalviewFileChooser chooser = new JalviewFileChooser(
2020 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2022 chooser.setFileView(new JalviewFileView());
2023 chooser.setDialogTitle(
2024 MessageManager.getString("label.open_saved_vamsas_session"));
2025 chooser.setToolTipText(MessageManager.getString(
2026 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2028 int value = chooser.showOpenDialog(this);
2030 if (value == JalviewFileChooser.APPROVE_OPTION)
2032 String fle = chooser.getSelectedFile().toString();
2033 if (!vamsasImport(chooser.getSelectedFile()))
2035 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2036 MessageManager.formatMessage(
2037 "label.couldnt_import_as_vamsas_session",
2041 .getString("label.vamsas_document_import_failed"),
2042 JvOptionPane.ERROR_MESSAGE);
2048 jalview.bin.Cache.log.error(
2049 "Implementation error - load session from a running session is not supported.");
2054 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2057 * @return true if import was a success and a session was started.
2059 public boolean vamsasImport(URL url)
2061 // TODO: create progress bar
2062 if (v_client != null)
2065 jalview.bin.Cache.log.error(
2066 "Implementation error - load session from a running session is not supported.");
2072 // copy the URL content to a temporary local file
2073 // TODO: be a bit cleverer here with nio (?!)
2074 File file = File.createTempFile("vdocfromurl", ".vdj");
2075 FileOutputStream fos = new FileOutputStream(file);
2076 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2077 byte[] buffer = new byte[2048];
2079 while ((ln = bis.read(buffer)) > -1)
2081 fos.write(buffer, 0, ln);
2085 v_client = new jalview.gui.VamsasApplication(this, file,
2086 url.toExternalForm());
2087 } catch (Exception ex)
2089 jalview.bin.Cache.log.error(
2090 "Failed to create new vamsas session from contents of URL "
2095 setupVamsasConnectedGui();
2096 v_client.initial_update(); // TODO: thread ?
2097 return v_client.inSession();
2101 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2104 * @return true if import was a success and a session was started.
2106 public boolean vamsasImport(File file)
2108 if (v_client != null)
2111 jalview.bin.Cache.log.error(
2112 "Implementation error - load session from a running session is not supported.");
2116 setProgressBar(MessageManager.formatMessage(
2117 "status.importing_vamsas_session_from", new Object[]
2118 { file.getName() }), file.hashCode());
2121 v_client = new jalview.gui.VamsasApplication(this, file, null);
2122 } catch (Exception ex)
2124 setProgressBar(MessageManager.formatMessage(
2125 "status.importing_vamsas_session_from", new Object[]
2126 { file.getName() }), file.hashCode());
2127 jalview.bin.Cache.log.error(
2128 "New vamsas session from existing session file failed:", ex);
2131 setupVamsasConnectedGui();
2132 v_client.initial_update(); // TODO: thread ?
2133 setProgressBar(MessageManager.formatMessage(
2134 "status.importing_vamsas_session_from", new Object[]
2135 { file.getName() }), file.hashCode());
2136 return v_client.inSession();
2139 public boolean joinVamsasSession(String mysesid)
2141 if (v_client != null)
2143 throw new Error(MessageManager
2144 .getString("error.try_join_vamsas_session_another"));
2146 if (mysesid == null)
2149 MessageManager.getString("error.invalid_vamsas_session_id"));
2151 v_client = new VamsasApplication(this, mysesid);
2152 setupVamsasConnectedGui();
2153 v_client.initial_update();
2154 return (v_client.inSession());
2158 public void vamsasStart_actionPerformed(ActionEvent e)
2160 if (v_client == null)
2163 // we just start a default session for moment.
2165 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2166 * getProperty("LAST_DIRECTORY"));
2168 * chooser.setFileView(new JalviewFileView());
2169 * chooser.setDialogTitle("Load Vamsas file");
2170 * chooser.setToolTipText("Import");
2172 * int value = chooser.showOpenDialog(this);
2174 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2175 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2177 v_client = new VamsasApplication(this);
2178 setupVamsasConnectedGui();
2179 v_client.initial_update(); // TODO: thread ?
2183 // store current data in session.
2184 v_client.push_update(); // TODO: thread
2188 protected void setupVamsasConnectedGui()
2190 vamsasStart.setText(MessageManager.getString("label.session_update"));
2191 vamsasSave.setVisible(true);
2192 vamsasStop.setVisible(true);
2193 vamsasImport.setVisible(false); // Document import to existing session is
2194 // not possible for vamsas-client-1.0.
2197 protected void setupVamsasDisconnectedGui()
2199 vamsasSave.setVisible(false);
2200 vamsasStop.setVisible(false);
2201 vamsasImport.setVisible(true);
2203 .setText(MessageManager.getString("label.new_vamsas_session"));
2207 public void vamsasStop_actionPerformed(ActionEvent e)
2209 if (v_client != null)
2211 v_client.end_session();
2213 setupVamsasDisconnectedGui();
2217 protected void buildVamsasStMenu()
2219 if (v_client == null)
2221 String[] sess = null;
2224 sess = VamsasApplication.getSessionList();
2225 } catch (Exception e)
2227 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2233 jalview.bin.Cache.log.debug(
2234 "Got current sessions list: " + sess.length + " entries.");
2235 VamsasStMenu.removeAll();
2236 for (int i = 0; i < sess.length; i++)
2238 JMenuItem sessit = new JMenuItem();
2239 sessit.setText(sess[i]);
2240 sessit.setToolTipText(MessageManager
2241 .formatMessage("label.connect_to_session", new Object[]
2243 final Desktop dsktp = this;
2244 final String mysesid = sess[i];
2245 sessit.addActionListener(new ActionListener()
2249 public void actionPerformed(ActionEvent e)
2251 if (dsktp.v_client == null)
2253 Thread rthr = new Thread(new Runnable()
2259 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2260 dsktp.setupVamsasConnectedGui();
2261 dsktp.v_client.initial_update();
2269 VamsasStMenu.add(sessit);
2271 // don't show an empty menu.
2272 VamsasStMenu.setVisible(sess.length > 0);
2277 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2278 VamsasStMenu.removeAll();
2279 VamsasStMenu.setVisible(false);
2284 // Not interested in the content. Just hide ourselves.
2285 VamsasStMenu.setVisible(false);
2290 public void vamsasSave_actionPerformed(ActionEvent e)
2292 if (v_client != null)
2294 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2295 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2298 chooser.setFileView(new JalviewFileView());
2299 chooser.setDialogTitle(MessageManager
2300 .getString("label.save_vamsas_document_archive"));
2302 int value = chooser.showSaveDialog(this);
2304 if (value == JalviewFileChooser.APPROVE_OPTION)
2306 java.io.File choice = chooser.getSelectedFile();
2307 JPanel progpanel = addProgressPanel(MessageManager
2308 .formatMessage("label.saving_vamsas_doc", new Object[]
2309 { choice.getName() }));
2310 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2311 String warnmsg = null;
2312 String warnttl = null;
2315 v_client.vclient.storeDocument(choice);
2318 warnttl = "Serious Problem saving Vamsas Document";
2319 warnmsg = ex.toString();
2320 jalview.bin.Cache.log
2321 .error("Error Whilst saving document to " + choice, ex);
2323 } catch (Exception ex)
2325 warnttl = "Problem saving Vamsas Document.";
2326 warnmsg = ex.toString();
2327 jalview.bin.Cache.log.warn(
2328 "Exception Whilst saving document to " + choice, ex);
2331 removeProgressPanel(progpanel);
2332 if (warnmsg != null)
2334 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2336 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2342 JPanel vamUpdate = null;
2345 * hide vamsas user gui bits when a vamsas document event is being handled.
2348 * true to hide gui, false to reveal gui
2350 public void setVamsasUpdate(boolean b)
2352 Cache.log.debug("Setting gui for Vamsas update "
2353 + (b ? "in progress" : "finished"));
2355 if (vamUpdate != null)
2357 this.removeProgressPanel(vamUpdate);
2361 vamUpdate = this.addProgressPanel(
2362 MessageManager.getString("label.updating_vamsas_session"));
2364 vamsasStart.setVisible(!b);
2365 vamsasStop.setVisible(!b);
2366 vamsasSave.setVisible(!b);
2369 public JInternalFrame[] getAllFrames()
2371 return desktop.getAllFrames();
2375 * Checks the given url to see if it gives a response indicating that the user
2376 * should be informed of a new questionnaire.
2380 public void checkForQuestionnaire(String url)
2382 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2383 // javax.swing.SwingUtilities.invokeLater(jvq);
2384 new Thread(jvq).start();
2387 public void checkURLLinks()
2389 // Thread off the URL link checker
2390 addDialogThread(new Runnable()
2395 if (/** @j2sNative false && */ // BH 2018
2396 Cache.getDefault("CHECKURLLINKS", true))
2398 // check what the actual links are - if it's just the default don't
2399 // bother with the warning
2400 List<String> links = Preferences.sequenceUrlLinks
2403 // only need to check links if there is one with a
2404 // SEQUENCE_ID which is not the default EMBL_EBI link
2405 ListIterator<String> li = links.listIterator();
2406 boolean check = false;
2407 List<JLabel> urls = new ArrayList<>();
2408 while (li.hasNext())
2410 String link = li.next();
2411 if (link.contains(SEQUENCE_ID)
2412 && !UrlConstants.isDefaultString(link))
2415 int barPos = link.indexOf("|");
2416 String urlMsg = barPos == -1 ? link
2417 : link.substring(0, barPos) + ": "
2418 + link.substring(barPos + 1);
2419 urls.add(new JLabel(urlMsg));
2427 // ask user to check in case URL links use old style tokens
2428 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2429 JPanel msgPanel = new JPanel();
2430 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2431 msgPanel.add(Box.createVerticalGlue());
2432 JLabel msg = new JLabel(MessageManager
2433 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2434 JLabel msg2 = new JLabel(MessageManager
2435 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2437 for (JLabel url : urls)
2443 final JCheckBox jcb = new JCheckBox(
2444 MessageManager.getString("label.do_not_display_again"));
2445 jcb.addActionListener(new ActionListener()
2448 public void actionPerformed(ActionEvent e)
2450 // update Cache settings for "don't show this again"
2451 boolean showWarningAgain = !jcb.isSelected();
2452 Cache.setProperty("CHECKURLLINKS",
2453 Boolean.valueOf(showWarningAgain).toString());
2458 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2460 .getString("label.SEQUENCE_ID_no_longer_used"),
2461 JvOptionPane.WARNING_MESSAGE);
2468 * Proxy class for JDesktopPane which optionally displays the current memory
2469 * usage and highlights the desktop area with a red bar if free memory runs
2474 public class MyDesktopPane extends JDesktopPane implements Runnable
2477 private static final float ONE_MB = 1048576f;
2479 boolean showMemoryUsage = false;
2483 java.text.NumberFormat df;
2485 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2488 public MyDesktopPane(boolean showMemoryUsage)
2490 showMemoryUsage(showMemoryUsage);
2493 public void showMemoryUsage(boolean showMemory)
2495 this.showMemoryUsage = showMemory;
2498 Thread worker = new Thread(this);
2504 public boolean isShowMemoryUsage()
2506 return showMemoryUsage;
2512 df = java.text.NumberFormat.getNumberInstance();
2513 df.setMaximumFractionDigits(2);
2514 runtime = Runtime.getRuntime();
2516 while (showMemoryUsage)
2520 maxMemory = runtime.maxMemory() / ONE_MB;
2521 allocatedMemory = runtime.totalMemory() / ONE_MB;
2522 freeMemory = runtime.freeMemory() / ONE_MB;
2523 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2525 percentUsage = (totalFreeMemory / maxMemory) * 100;
2527 // if (percentUsage < 20)
2529 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2531 // instance.set.setBorder(border1);
2534 // sleep after showing usage
2536 } catch (Exception ex)
2538 ex.printStackTrace();
2544 public void paintComponent(Graphics g)
2546 if (showMemoryUsage && g != null && df != null)
2548 if (percentUsage < 20)
2550 g.setColor(Color.red);
2552 FontMetrics fm = g.getFontMetrics();
2555 g.drawString(MessageManager.formatMessage("label.memory_stats",
2557 { df.format(totalFreeMemory), df.format(maxMemory),
2558 df.format(percentUsage) }),
2559 10, getHeight() - fm.getHeight());
2567 * Accessor method to quickly get all the AlignmentFrames loaded.
2569 * @return an array of AlignFrame, or null if none found
2571 public static AlignFrame[] getAlignFrames()
2573 if (Jalview.isHeadlessMode())
2575 // Desktop.desktop is null in headless mode
2576 return new AlignFrame[] { Jalview.currentAlignFrame };
2579 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2585 List<AlignFrame> avp = new ArrayList<>();
2587 for (int i = frames.length - 1; i > -1; i--)
2589 if (frames[i] instanceof AlignFrame)
2591 avp.add((AlignFrame) frames[i]);
2593 else if (frames[i] instanceof SplitFrame)
2596 * Also check for a split frame containing an AlignFrame
2598 GSplitFrame sf = (GSplitFrame) frames[i];
2599 if (sf.getTopFrame() instanceof AlignFrame)
2601 avp.add((AlignFrame) sf.getTopFrame());
2603 if (sf.getBottomFrame() instanceof AlignFrame)
2605 avp.add((AlignFrame) sf.getBottomFrame());
2609 if (avp.size() == 0)
2613 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2618 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2622 public GStructureViewer[] getJmols()
2624 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2630 List<GStructureViewer> avp = new ArrayList<>();
2632 for (int i = frames.length - 1; i > -1; i--)
2634 if (frames[i] instanceof AppJmol)
2636 GStructureViewer af = (GStructureViewer) frames[i];
2640 if (avp.size() == 0)
2644 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2649 * Add Groovy Support to Jalview
2652 public void groovyShell_actionPerformed()
2656 openGroovyConsole();
2657 } catch (Exception ex)
2659 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2660 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2662 MessageManager.getString("label.couldnt_create_groovy_shell"),
2663 MessageManager.getString("label.groovy_support_failed"),
2664 JvOptionPane.ERROR_MESSAGE);
2669 * Open the Groovy console
2671 void openGroovyConsole()
2673 if (groovyConsole == null)
2675 groovyConsole = new groovy.ui.Console();
2676 groovyConsole.setVariable("Jalview", this);
2677 groovyConsole.run();
2680 * We allow only one console at a time, so that AlignFrame menu option
2681 * 'Calculate | Run Groovy script' is unambiguous.
2682 * Disable 'Groovy Console', and enable 'Run script', when the console is
2683 * opened, and the reverse when it is closed
2685 Window window = (Window) groovyConsole.getFrame();
2686 window.addWindowListener(new WindowAdapter()
2689 public void windowClosed(WindowEvent e)
2692 * rebind CMD-Q from Groovy Console to Jalview Quit
2695 enableExecuteGroovy(false);
2701 * show Groovy console window (after close and reopen)
2703 ((Window) groovyConsole.getFrame()).setVisible(true);
2706 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2707 * and disable opening a second console
2709 enableExecuteGroovy(true);
2713 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2714 * binding when opened
2716 protected void addQuitHandler()
2718 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2719 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2720 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2722 getRootPane().getActionMap().put("Quit", new AbstractAction()
2725 public void actionPerformed(ActionEvent e)
2733 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2736 * true if Groovy console is open
2738 public void enableExecuteGroovy(boolean enabled)
2741 * disable opening a second Groovy console
2742 * (or re-enable when the console is closed)
2744 groovyShell.setEnabled(!enabled);
2746 AlignFrame[] alignFrames = getAlignFrames();
2747 if (alignFrames != null)
2749 for (AlignFrame af : alignFrames)
2751 af.setGroovyEnabled(enabled);
2757 * Progress bars managed by the IProgressIndicator method.
2759 private Hashtable<Long, JPanel> progressBars;
2761 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2766 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2769 public void setProgressBar(String message, long id)
2771 if (progressBars == null)
2773 progressBars = new Hashtable<>();
2774 progressBarHandlers = new Hashtable<>();
2777 if (progressBars.get(new Long(id)) != null)
2779 JPanel panel = progressBars.remove(new Long(id));
2780 if (progressBarHandlers.contains(new Long(id)))
2782 progressBarHandlers.remove(new Long(id));
2784 removeProgressPanel(panel);
2788 progressBars.put(new Long(id), addProgressPanel(message));
2795 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2796 * jalview.gui.IProgressIndicatorHandler)
2799 public void registerHandler(final long id,
2800 final IProgressIndicatorHandler handler)
2802 if (progressBarHandlers == null
2803 || !progressBars.containsKey(new Long(id)))
2805 throw new Error(MessageManager.getString(
2806 "error.call_setprogressbar_before_registering_handler"));
2808 progressBarHandlers.put(new Long(id), handler);
2809 final JPanel progressPanel = progressBars.get(new Long(id));
2810 if (handler.canCancel())
2812 JButton cancel = new JButton(
2813 MessageManager.getString("action.cancel"));
2814 final IProgressIndicator us = this;
2815 cancel.addActionListener(new ActionListener()
2819 public void actionPerformed(ActionEvent e)
2821 handler.cancelActivity(id);
2822 us.setProgressBar(MessageManager
2823 .formatMessage("label.cancelled_params", new Object[]
2824 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2828 progressPanel.add(cancel, BorderLayout.EAST);
2834 * @return true if any progress bars are still active
2837 public boolean operationInProgress()
2839 if (progressBars != null && progressBars.size() > 0)
2847 * This will return the first AlignFrame holding the given viewport instance.
2848 * It will break if there are more than one AlignFrames viewing a particular
2852 * @return alignFrame for viewport
2854 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2856 if (desktop != null)
2858 AlignmentPanel[] aps = getAlignmentPanels(
2859 viewport.getSequenceSetId());
2860 for (int panel = 0; aps != null && panel < aps.length; panel++)
2862 if (aps[panel] != null && aps[panel].av == viewport)
2864 return aps[panel].alignFrame;
2871 public VamsasApplication getVamsasApplication()
2878 * flag set if jalview GUI is being operated programmatically
2880 private boolean inBatchMode = false;
2883 * check if jalview GUI is being operated programmatically
2885 * @return inBatchMode
2887 public boolean isInBatchMode()
2893 * set flag if jalview GUI is being operated programmatically
2895 * @param inBatchMode
2897 public void setInBatchMode(boolean inBatchMode)
2899 this.inBatchMode = inBatchMode;
2902 public void startServiceDiscovery()
2904 startServiceDiscovery(false);
2907 public void startServiceDiscovery(boolean blocking)
2909 boolean alive = true;
2910 Thread t0 = null, t1 = null, t2 = null;
2911 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2914 // todo: changesupport handlers need to be transferred
2915 if (discoverer == null)
2917 discoverer = new jalview.ws.jws1.Discoverer();
2918 // register PCS handler for desktop.
2919 discoverer.addPropertyChangeListener(changeSupport);
2921 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2922 // until we phase out completely
2923 (t0 = new Thread(discoverer)).start();
2926 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2928 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2929 .startDiscoverer(changeSupport);
2933 // TODO: do rest service discovery
2942 } catch (Exception e)
2945 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2946 || (t3 != null && t3.isAlive())
2947 || (t0 != null && t0.isAlive());
2953 * called to check if the service discovery process completed successfully.
2957 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2959 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2961 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2962 .getErrorMessages();
2965 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
2967 if (serviceChangedDialog == null)
2969 // only run if we aren't already displaying one of these.
2970 addDialogThread(serviceChangedDialog = new Runnable()
2977 * JalviewDialog jd =new JalviewDialog() {
2979 * @Override protected void cancelPressed() { // TODO
2980 * Auto-generated method stub
2982 * }@Override protected void okPressed() { // TODO
2983 * Auto-generated method stub
2985 * }@Override protected void raiseClosed() { // TODO
2986 * Auto-generated method stub
2988 * } }; jd.initDialogFrame(new
2989 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
2990 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
2991 * + " or mis-configured HTTP proxy settings.<br/>" +
2992 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
2994 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
2995 * ), true, true, "Web Service Configuration Problem", 450,
2998 * jd.waitForInput();
3000 JvOptionPane.showConfirmDialog(Desktop.desktop,
3001 new JLabel("<html><table width=\"450\"><tr><td>"
3002 + ermsg + "</td></tr></table>"
3003 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3004 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3005 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3006 + " Tools->Preferences dialog box to change them.</p></html>"),
3007 "Web Service Configuration Problem",
3008 JvOptionPane.DEFAULT_OPTION,
3009 JvOptionPane.ERROR_MESSAGE);
3010 serviceChangedDialog = null;
3019 "Errors reported by JABA discovery service. Check web services preferences.\n"
3026 private Runnable serviceChangedDialog = null;
3029 * start a thread to open a URL in the configured browser. Pops up a warning
3030 * dialog to the user if there is an exception when calling out to the browser
3035 public static void showUrl(final String url)
3037 showUrl(url, Desktop.instance);
3041 * Like showUrl but allows progress handler to be specified
3045 * (null) or object implementing IProgressIndicator
3047 public static void showUrl(final String url,
3048 final IProgressIndicator progress)
3050 new Thread(new Runnable()
3057 if (progress != null)
3059 progress.setProgressBar(MessageManager
3060 .formatMessage("status.opening_params", new Object[]
3061 { url }), this.hashCode());
3063 jalview.util.BrowserLauncher.openURL(url);
3064 } catch (Exception ex)
3066 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3068 .getString("label.web_browser_not_found_unix"),
3069 MessageManager.getString("label.web_browser_not_found"),
3070 JvOptionPane.WARNING_MESSAGE);
3072 ex.printStackTrace();
3074 if (progress != null)
3076 progress.setProgressBar(null, this.hashCode());
3082 public static WsParamSetManager wsparamManager = null;
3084 public static ParamManager getUserParameterStore()
3086 if (wsparamManager == null)
3088 wsparamManager = new WsParamSetManager();
3090 return wsparamManager;
3094 * static hyperlink handler proxy method for use by Jalview's internal windows
3098 public static void hyperlinkUpdate(HyperlinkEvent e)
3100 if (e.getEventType() == EventType.ACTIVATED)
3105 url = e.getURL().toString();
3106 Desktop.showUrl(url);
3107 } catch (Exception x)
3111 if (Cache.log != null)
3113 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3118 "Couldn't handle string " + url + " as a URL.");
3121 // ignore any exceptions due to dud links.
3128 * single thread that handles display of dialogs to user.
3130 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3133 * flag indicating if dialogExecutor should try to acquire a permit
3135 private volatile boolean dialogPause = true;
3140 private java.util.concurrent.Semaphore block = new Semaphore(0);
3142 private static groovy.ui.Console groovyConsole;
3145 * add another dialog thread to the queue
3149 public void addDialogThread(final Runnable prompter)
3151 dialogExecutor.submit(new Runnable()
3161 } catch (InterruptedException x)
3166 if (instance == null)
3172 SwingUtilities.invokeAndWait(prompter);
3173 } catch (Exception q)
3175 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3181 public void startDialogQueue()
3183 // set the flag so we don't pause waiting for another permit and semaphore
3184 // the current task to begin
3185 dialogPause = false;
3190 protected void snapShotWindow_actionPerformed(ActionEvent e)
3194 ImageMaker im = new jalview.util.ImageMaker(
3195 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3196 getHeight(), of = new File("Jalview_snapshot"
3197 + System.currentTimeMillis() + ".eps"),
3198 "View of desktop", null, 0, false);
3201 paintAll(im.getGraphics());
3203 } catch (Exception q)
3205 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3209 Cache.log.info("Successfully written snapshot to file "
3210 + of.getAbsolutePath());
3214 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3215 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3216 * and location last time the view was expanded (if any). However it does not
3217 * remember the split pane divider location - this is set to match the
3218 * 'exploding' frame.
3222 public void explodeViews(SplitFrame sf)
3224 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3225 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3226 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3228 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3230 int viewCount = topPanels.size();
3237 * Processing in reverse order works, forwards order leaves the first panels
3238 * not visible. I don't know why!
3240 for (int i = viewCount - 1; i >= 0; i--)
3243 * Make new top and bottom frames. These take over the respective
3244 * AlignmentPanel objects, including their AlignmentViewports, so the
3245 * cdna/protein relationships between the viewports is carried over to the
3248 * explodedGeometry holds the (x, y) position of the previously exploded
3249 * SplitFrame, and the (width, height) of the AlignFrame component
3251 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3252 AlignFrame newTopFrame = new AlignFrame(topPanel);
3253 newTopFrame.setSize(oldTopFrame.getSize());
3254 newTopFrame.setVisible(true);
3255 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3256 .getExplodedGeometry();
3257 if (geometry != null)
3259 newTopFrame.setSize(geometry.getSize());
3262 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3263 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3264 newBottomFrame.setSize(oldBottomFrame.getSize());
3265 newBottomFrame.setVisible(true);
3266 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3267 .getExplodedGeometry();
3268 if (geometry != null)
3270 newBottomFrame.setSize(geometry.getSize());
3273 topPanel.av.setGatherViewsHere(false);
3274 bottomPanel.av.setGatherViewsHere(false);
3275 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3277 if (geometry != null)
3279 splitFrame.setLocation(geometry.getLocation());
3281 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3285 * Clear references to the panels (now relocated in the new SplitFrames)
3286 * before closing the old SplitFrame.
3289 bottomPanels.clear();
3294 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3295 * back into the given SplitFrame as additional views. Note that the gathered
3296 * frames may themselves have multiple views.
3300 public void gatherViews(GSplitFrame source)
3303 * special handling of explodedGeometry for a view within a SplitFrame: - it
3304 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3305 * height) of the AlignFrame component
3307 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3308 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3309 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3310 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3311 myBottomFrame.viewport
3312 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3313 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3314 myTopFrame.viewport.setGatherViewsHere(true);
3315 myBottomFrame.viewport.setGatherViewsHere(true);
3316 String topViewId = myTopFrame.viewport.getSequenceSetId();
3317 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3319 JInternalFrame[] frames = desktop.getAllFrames();
3320 for (JInternalFrame frame : frames)
3322 if (frame instanceof SplitFrame && frame != source)
3324 SplitFrame sf = (SplitFrame) frame;
3325 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3326 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3327 boolean gatherThis = false;
3328 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3330 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3331 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3332 if (topViewId.equals(topPanel.av.getSequenceSetId())
3333 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3336 topPanel.av.setGatherViewsHere(false);
3337 bottomPanel.av.setGatherViewsHere(false);
3338 topPanel.av.setExplodedGeometry(
3339 new Rectangle(sf.getLocation(), topFrame.getSize()));
3340 bottomPanel.av.setExplodedGeometry(
3341 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3342 myTopFrame.addAlignmentPanel(topPanel, false);
3343 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3349 topFrame.getAlignPanels().clear();
3350 bottomFrame.getAlignPanels().clear();
3357 * The dust settles...give focus to the tab we did this from.
3359 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3362 public static groovy.ui.Console getGroovyConsole()
3364 return groovyConsole;
3368 * handles the payload of a drag and drop event.
3370 * TODO refactor to desktop utilities class
3373 * - Data source strings extracted from the drop event
3375 * - protocol for each data source extracted from the drop event
3379 * - the payload from the drop event
3382 public static void transferFromDropTarget(List<String> files,
3383 List<DataSourceType> protocols, DropTargetDropEvent evt,
3384 Transferable t) throws Exception
3387 DataFlavor uriListFlavor = new DataFlavor(
3388 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3391 urlFlavour = new DataFlavor(
3392 "application/x-java-url; class=java.net.URL");
3393 } catch (ClassNotFoundException cfe)
3395 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3398 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3403 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3404 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3405 // means url may be null.
3408 protocols.add(DataSourceType.URL);
3409 files.add(url.toString());
3410 Cache.log.debug("Drop handled as URL dataflavor "
3411 + files.get(files.size() - 1));
3416 if (Platform.isAMac())
3419 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3423 } catch (Throwable ex)
3425 Cache.log.debug("URL drop handler failed.", ex);
3428 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3430 // Works on Windows and MacOSX
3431 Cache.log.debug("Drop handled as javaFileListFlavor");
3432 for (Object file : (List) t
3433 .getTransferData(DataFlavor.javaFileListFlavor))
3435 files.add(((File) file).toString());
3436 protocols.add(DataSourceType.FILE);
3441 // Unix like behaviour
3442 boolean added = false;
3444 if (t.isDataFlavorSupported(uriListFlavor))
3446 Cache.log.debug("Drop handled as uriListFlavor");
3447 // This is used by Unix drag system
3448 data = (String) t.getTransferData(uriListFlavor);
3452 // fallback to text: workaround - on OSX where there's a JVM bug
3453 Cache.log.debug("standard URIListFlavor failed. Trying text");
3454 // try text fallback
3455 DataFlavor textDf = new DataFlavor(
3456 "text/plain;class=java.lang.String");
3457 if (t.isDataFlavorSupported(textDf))
3459 data = (String) t.getTransferData(textDf);
3462 Cache.log.debug("Plain text drop content returned "
3463 + (data == null ? "Null - failed" : data));
3468 while (protocols.size() < files.size())
3470 Cache.log.debug("Adding missing FILE protocol for "
3471 + files.get(protocols.size()));
3472 protocols.add(DataSourceType.FILE);
3474 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3475 data, "\r\n"); st.hasMoreTokens();)
3478 String s = st.nextToken();
3479 if (s.startsWith("#"))
3481 // the line is a comment (as per the RFC 2483)
3484 java.net.URI uri = new java.net.URI(s);
3485 if (uri.getScheme().toLowerCase().startsWith("http"))
3487 protocols.add(DataSourceType.URL);
3488 files.add(uri.toString());
3492 // otherwise preserve old behaviour: catch all for file objects
3493 java.io.File file = new java.io.File(uri);
3494 protocols.add(DataSourceType.FILE);
3495 files.add(file.toString());
3500 if (Cache.log.isDebugEnabled())
3502 if (data == null || !added)
3505 if (t.getTransferDataFlavors() != null
3506 && t.getTransferDataFlavors().length > 0)
3509 "Couldn't resolve drop data. Here are the supported flavors:");
3510 for (DataFlavor fl : t.getTransferDataFlavors())
3513 "Supported transfer dataflavor: " + fl.toString());
3514 Object df = t.getTransferData(fl);
3517 Cache.log.debug("Retrieves: " + df);
3521 Cache.log.debug("Retrieved nothing");
3527 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3533 if (Platform.isWindows())
3536 Cache.log.debug("Scanning dropped content for Windows Link Files");
3538 // resolve any .lnk files in the file drop
3539 for (int f = 0; f < files.size(); f++)
3541 String source = files.get(f).toLowerCase();
3542 if (protocols.get(f).equals(DataSourceType.FILE)
3543 && (source.endsWith(".lnk") || source.endsWith(".url")
3544 || source.endsWith(".site")))
3547 File lf = new File(files.get(f));
3548 // process link file to get a URL
3549 Cache.log.debug("Found potential link file: " + lf);
3550 WindowsShortcut wscfile = new WindowsShortcut(lf);
3551 String fullname = wscfile.getRealFilename();
3552 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3553 files.set(f, fullname);
3554 Cache.log.debug("Parsed real filename " + fullname
3555 + " to extract protocol: " + protocols.get(f));
3557 catch (Exception ex)
3559 Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
3567 * Sets the Preferences property for experimental features to True or False
3568 * depending on the state of the controlling menu item
3571 protected void showExperimental_actionPerformed(boolean selected)
3573 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3577 * Answers a (possibly empty) list of any structure viewer frames (currently
3578 * for either Jmol or Chimera) which are currently open. This may optionally
3579 * be restricted to viewers of a specified class, or viewers linked to a
3580 * specified alignment panel.
3583 * if not null, only return viewers linked to this panel
3584 * @param structureViewerClass
3585 * if not null, only return viewers of this class
3588 public List<StructureViewerBase> getStructureViewers(
3589 AlignmentPanel apanel,
3590 Class<? extends StructureViewerBase> structureViewerClass)
3592 List<StructureViewerBase> result = new ArrayList<>();
3593 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3595 for (JInternalFrame frame : frames)
3597 if (frame instanceof StructureViewerBase)
3599 if (structureViewerClass == null
3600 || structureViewerClass.isInstance(frame))
3603 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3605 result.add((StructureViewerBase) frame);