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 jalview.api.AlignViewportI;
24 import jalview.api.AlignmentViewPanel;
25 import jalview.api.StructureSelectionManagerProvider;
26 import jalview.bin.ApplicationSingletonProvider;
27 import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI;
28 import jalview.bin.Cache;
29 import jalview.bin.Jalview;
30 import jalview.gui.ImageExporter.ImageWriterI;
31 import jalview.io.BackupFiles;
32 import jalview.io.DataSourceType;
33 import jalview.io.FileFormat;
34 import jalview.io.FileFormatException;
35 import jalview.io.FileFormatI;
36 import jalview.io.FileFormats;
37 import jalview.io.FileLoader;
38 import jalview.io.FormatAdapter;
39 import jalview.io.IdentifyFile;
40 import jalview.io.JalviewFileChooser;
41 import jalview.io.JalviewFileView;
42 import jalview.jbgui.GDesktop;
43 import jalview.jbgui.GSplitFrame;
44 import jalview.jbgui.GStructureViewer;
45 import jalview.project.Jalview2XML;
46 import jalview.structure.StructureSelectionManager;
47 import jalview.urls.IdOrgSettings;
48 import jalview.util.BrowserLauncher;
49 import jalview.util.ImageMaker.TYPE;
50 import jalview.util.MessageManager;
51 import jalview.util.Platform;
52 import jalview.util.UrlConstants;
53 import jalview.viewmodel.AlignmentViewport;
54 import jalview.ws.jws1.Discoverer;
55 import jalview.ws.params.ParamManager;
56 import jalview.ws.utils.UrlDownloadClient;
58 import java.awt.BorderLayout;
59 import java.awt.Color;
60 import java.awt.Dimension;
61 import java.awt.FontMetrics;
62 import java.awt.Graphics;
63 import java.awt.GridLayout;
64 import java.awt.Point;
65 import java.awt.Rectangle;
66 import java.awt.Toolkit;
67 import java.awt.Window;
68 import java.awt.datatransfer.Clipboard;
69 import java.awt.datatransfer.ClipboardOwner;
70 import java.awt.datatransfer.DataFlavor;
71 import java.awt.datatransfer.Transferable;
72 import java.awt.dnd.DnDConstants;
73 import java.awt.dnd.DropTargetDragEvent;
74 import java.awt.dnd.DropTargetDropEvent;
75 import java.awt.dnd.DropTargetEvent;
76 import java.awt.dnd.DropTargetListener;
77 import java.awt.event.ActionEvent;
78 import java.awt.event.ActionListener;
79 import java.awt.event.InputEvent;
80 import java.awt.event.KeyEvent;
81 import java.awt.event.MouseAdapter;
82 import java.awt.event.MouseEvent;
83 import java.awt.event.WindowAdapter;
84 import java.awt.event.WindowEvent;
85 import java.beans.PropertyChangeEvent;
86 import java.beans.PropertyChangeListener;
87 import java.io.BufferedInputStream;
89 import java.io.FileOutputStream;
90 import java.io.IOException;
92 import java.util.ArrayList;
93 import java.util.Hashtable;
94 import java.util.List;
95 import java.util.ListIterator;
96 import java.util.Vector;
97 import java.util.concurrent.ExecutorService;
98 import java.util.concurrent.Executors;
99 import java.util.concurrent.Semaphore;
101 import javax.swing.AbstractAction;
102 import javax.swing.Action;
103 import javax.swing.ActionMap;
104 import javax.swing.Box;
105 import javax.swing.BoxLayout;
106 import javax.swing.DefaultDesktopManager;
107 import javax.swing.DesktopManager;
108 import javax.swing.InputMap;
109 import javax.swing.JButton;
110 import javax.swing.JCheckBox;
111 import javax.swing.JComboBox;
112 import javax.swing.JComponent;
113 import javax.swing.JDesktopPane;
114 import javax.swing.JFrame;
115 import javax.swing.JInternalFrame;
116 import javax.swing.JLabel;
117 import javax.swing.JMenuItem;
118 import javax.swing.JPanel;
119 import javax.swing.JPopupMenu;
120 import javax.swing.JProgressBar;
121 import javax.swing.JTextField;
122 import javax.swing.KeyStroke;
123 import javax.swing.SwingUtilities;
124 import javax.swing.event.HyperlinkEvent;
125 import javax.swing.event.HyperlinkEvent.EventType;
126 import javax.swing.event.InternalFrameAdapter;
127 import javax.swing.event.InternalFrameEvent;
128 import javax.swing.event.MenuEvent;
129 import javax.swing.event.MenuListener;
131 import org.stackoverflowusers.file.WindowsShortcut;
138 * @version $Revision: 1.155 $
140 @SuppressWarnings("serial")
141 public class Desktop extends GDesktop
142 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
143 StructureSelectionManagerProvider, ApplicationSingletonI
146 private final static int DEFAULT_MIN_WIDTH = 300;
148 private final static int DEFAULT_MIN_HEIGHT = 250;
150 private final static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
152 private final static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
154 private final static String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
156 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
159 * news reader - null if it was never started.
161 BlogReader jvnews = null;
163 private File projectFile;
167 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
169 public void addJalviewPropertyChangeListener(
170 PropertyChangeListener listener)
172 changeSupport.addJalviewPropertyChangeListener(listener);
176 * @param propertyName
178 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
179 * java.beans.PropertyChangeListener)
181 public void addJalviewPropertyChangeListener(String propertyName,
182 PropertyChangeListener listener)
184 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
188 * @param propertyName
190 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
191 * java.beans.PropertyChangeListener)
193 public void removeJalviewPropertyChangeListener(String propertyName,
194 PropertyChangeListener listener)
196 changeSupport.removeJalviewPropertyChangeListener(propertyName,
200 public static MyDesktopPane getDesktopPane()
202 Desktop desktop = Desktop.getInstance();
203 return desktop == null ? null : desktop.desktopPane;
206 public static StructureSelectionManager getStructureSelectionManager()
208 return StructureSelectionManager
209 .getStructureSelectionManager(getInstance());
212 static int openFrameCount = 0;
214 static final int xOffset = 30;
216 static final int yOffset = 30;
218 public Discoverer discoverer;
220 public Object[] jalviewClipboard;
222 public boolean internalCopy = false;
224 private static int fileLoadingCount = 0;
226 public JInternalFrame conservationSlider;
228 public JInternalFrame PIDSlider;
231 * just an instance (for testng, probably); no actual frames
233 * This flag, when set true, allows a headless-like operation, with a Desktop
234 * object but no actual frames. The issue has to do with the mess-up of the
235 * Windows JInternalFrame implementation, which surreptitiously and
236 * unforgivingly accesses a native peer class, preventing headless operation.
238 * It is set by invoking the Desktop(true) constructor.
240 * It is possible that we can remove this option now, since headless mode is
241 * finally working on Windows through careful attention to not creating any
242 * JInternalFrame objects when in that mode.
245 private boolean instanceOnly;
247 class MyDesktopManager implements DesktopManager
250 private DesktopManager delegate;
252 public MyDesktopManager(DesktopManager delegate)
254 this.delegate = delegate;
258 public void activateFrame(JInternalFrame f)
262 delegate.activateFrame(f);
263 } catch (NullPointerException npe)
265 Point p = getMousePosition();
266 showPasteMenu(p.x, p.y);
271 public void beginDraggingFrame(JComponent f)
273 delegate.beginDraggingFrame(f);
277 public void beginResizingFrame(JComponent f, int direction)
279 delegate.beginResizingFrame(f, direction);
283 public void closeFrame(JInternalFrame f)
285 delegate.closeFrame(f);
289 public void deactivateFrame(JInternalFrame f)
291 delegate.deactivateFrame(f);
295 public void deiconifyFrame(JInternalFrame f)
297 delegate.deiconifyFrame(f);
301 public void dragFrame(JComponent f, int newX, int newY)
307 delegate.dragFrame(f, newX, newY);
311 public void endDraggingFrame(JComponent f)
313 delegate.endDraggingFrame(f);
314 desktopPane.repaint();
318 public void endResizingFrame(JComponent f)
320 delegate.endResizingFrame(f);
321 desktopPane.repaint();
325 public void iconifyFrame(JInternalFrame f)
327 delegate.iconifyFrame(f);
331 public void maximizeFrame(JInternalFrame f)
333 delegate.maximizeFrame(f);
337 public void minimizeFrame(JInternalFrame f)
339 delegate.minimizeFrame(f);
343 public void openFrame(JInternalFrame f)
345 delegate.openFrame(f);
349 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
356 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
360 public void setBoundsForFrame(JComponent f, int newX, int newY,
361 int newWidth, int newHeight)
363 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
366 // All other methods, simply delegate
370 public MyDesktopPane desktopPane;
373 * Answers an 'application scope' singleton instance of this class. Separate
374 * SwingJS 'applets' running in the same browser page will each have a
375 * distinct instance of Desktop.
379 public static Desktop getInstance()
381 return Jalview.isHeadlessMode() ? null
382 : (Desktop) ApplicationSingletonProvider
383 .getInstance(Desktop.class);
387 * For testing purposes, this constructor can be utilized to allow the creation
388 * of a singleton Desktop instance without the formation of frames. The Cache is
389 * initialized, but that is all.
391 * It is not currently used.
395 public Desktop(boolean forInstance)
403 * Private constructor enforces singleton pattern. It is called by reflection
404 * from ApplicationSingletonProvider.getInstance().
406 @SuppressWarnings("unused")
413 * A note to implementors. It is ESSENTIAL that any activities that might
414 * block are spawned off as threads rather than waited for during this
417 if (!Platform.isJS())
419 doVamsasClientCheck();
422 doConfigureStructurePrefs();
423 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
424 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
425 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
427 boolean showjconsole = jalview.bin.Cache
428 .getDefault("SHOW_JAVA_CONSOLE", false);
429 desktopPane = new MyDesktopPane(selmemusage);
431 showMemusage.setSelected(selmemusage);
432 desktopPane.setBackground(Color.white);
433 getContentPane().setLayout(new BorderLayout());
434 // alternate config - have scrollbars - see notes in JAL-153
435 // JScrollPane sp = new JScrollPane();
436 // sp.getViewport().setView(desktop);
437 // getContentPane().add(sp, BorderLayout.CENTER);
439 // BH 2018 - just an experiment to try unclipped JInternalFrames.
442 getRootPane().putClientProperty("swingjs.overflow.hidden", "false");
445 getContentPane().add(desktopPane, BorderLayout.CENTER);
446 desktopPane.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
448 // This line prevents Windows Look&Feel resizing all new windows to
450 // if previous window was maximised
451 desktopPane.setDesktopManager(new MyDesktopManager(
452 (Platform.isWindowsAndNotJS() ? new DefaultDesktopManager()
453 : Platform.isAMacAndNotJS()
454 ? new AquaInternalFrameManager(
455 desktopPane.getDesktopManager())
456 : desktopPane.getDesktopManager())));
458 Rectangle dims = getLastKnownDimensions("");
465 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
466 int xPos = Math.max(5, (screenSize.width - 900) / 2);
467 int yPos = Math.max(5, (screenSize.height - 650) / 2);
468 setBounds(xPos, yPos, 900, 650);
471 // Note that this next syntax, checking for Platform.isJS and also
472 // escaping the code using @j2sIgnore, serves two purposes. It gives
473 // us an easily findable tag, Platform.isJS(), to places in the code where
474 // there is something different about the SwingJS implementation. Second,
475 // it deletes the unneeded Java-only code form the JavaScript version
476 // completely (@j2sIgnore), since it will never be used there.
478 if (!Platform.isJS())
486 jconsole = new Console(this, showjconsole);
487 // add essential build information
488 jconsole.setHeader("Jalview Version: "
489 + jalview.bin.Cache.getProperty("VERSION") + "\n"
490 + "Jalview Installation: "
491 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
492 + "\n" + "Build Date: "
493 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
494 + "\n" + "Java version: "
495 + System.getProperty("java.version") + "\n"
496 + System.getProperty("os.arch") + " "
497 + System.getProperty("os.name") + " "
498 + System.getProperty("os.version"));
500 showConsole(showjconsole);
502 showNews.setVisible(false);
504 experimentalFeatures.setSelected(showExperimental());
506 getIdentifiersOrgData();
510 // Spawn a thread that shows the splashscreen
512 SwingUtilities.invokeLater(new Runnable()
521 // Thread off a new instance of the file chooser - this reduces the time
523 // takes to open it later on.
524 new Thread(new Runnable()
529 Cache.log.debug("Filechooser init thread started.");
530 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
531 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
533 Cache.log.debug("Filechooser init thread finished.");
536 // Add the service change listener
537 changeSupport.addJalviewPropertyChangeListener("services",
538 new PropertyChangeListener()
542 public void propertyChange(PropertyChangeEvent evt)
544 Cache.log.debug("Firing service changed event for "
545 + evt.getNewValue());
546 JalviewServicesChanged(evt);
553 this.setDropTarget(new java.awt.dnd.DropTarget(desktopPane, this));
555 this.addWindowListener(new WindowAdapter()
558 public void windowClosing(WindowEvent evt)
565 this.addMouseListener(ma = new MouseAdapter()
568 public void mousePressed(MouseEvent evt)
570 if (evt.isPopupTrigger()) // Mac
572 showPasteMenu(evt.getX(), evt.getY());
577 public void mouseReleased(MouseEvent evt)
579 if (evt.isPopupTrigger()) // Windows
581 showPasteMenu(evt.getX(), evt.getY());
585 desktopPane.addMouseListener(ma);
586 } catch (Throwable t)
593 * Answers true if user preferences to enable experimental features is True
598 public boolean showExperimental()
600 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
601 Boolean.FALSE.toString());
602 return Boolean.valueOf(experimental).booleanValue();
605 public void doConfigureStructurePrefs()
607 // configure services
608 StructureSelectionManager ssm = StructureSelectionManager
609 .getStructureSelectionManager(this);
610 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
612 ssm.setAddTempFacAnnot(jalview.bin.Cache
613 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
614 ssm.setProcessSecondaryStructure(jalview.bin.Cache
615 .getDefault(Preferences.STRUCT_FROM_PDB, true));
616 ssm.setSecStructServices(
617 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
621 ssm.setAddTempFacAnnot(false);
622 ssm.setProcessSecondaryStructure(false);
623 ssm.setSecStructServices(false);
627 public void checkForNews()
629 final Desktop me = this;
630 // Thread off the news reader, in case there are connection problems.
631 new Thread(new Runnable()
636 Cache.log.debug("Starting news thread.");
637 jvnews = new BlogReader(me);
638 showNews.setVisible(true);
639 Cache.log.debug("Completed news thread.");
644 public void getIdentifiersOrgData()
646 // Thread off the identifiers fetcher
647 new Thread(new Runnable()
652 Cache.log.debug("Downloading data from identifiers.org");
653 // UrlDownloadClient client = new UrlDownloadClient();
656 UrlDownloadClient.download(IdOrgSettings.getUrl(),
657 IdOrgSettings.getDownloadLocation());
658 } catch (IOException e)
660 Cache.log.debug("Exception downloading identifiers.org data"
669 protected void showNews_actionPerformed(ActionEvent e)
671 showNews(showNews.isSelected());
674 protected void showNews(boolean visible)
676 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
677 showNews.setSelected(visible);
678 if (visible && !jvnews.isVisible())
680 new Thread(new Runnable()
685 long now = System.currentTimeMillis();
687 MessageManager.getString("status.refreshing_news"), now);
688 jvnews.refreshNews();
689 setProgressBar(null, now);
697 * recover the last known dimensions for a jalview window
700 * - empty string is desktop, all other windows have unique prefix
701 * @return null or last known dimensions scaled to current geometry (if last
702 * window geom was known)
704 Rectangle getLastKnownDimensions(String windowName)
706 // TODO: lock aspect ratio for scaling desktop Bug #0058199
707 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
708 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
709 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
710 String width = jalview.bin.Cache
711 .getProperty(windowName + "SCREEN_WIDTH");
712 String height = jalview.bin.Cache
713 .getProperty(windowName + "SCREEN_HEIGHT");
714 if ((x != null) && (y != null) && (width != null) && (height != null))
716 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
717 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
718 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
720 // attempt #1 - try to cope with change in screen geometry - this
721 // version doesn't preserve original jv aspect ratio.
722 // take ratio of current screen size vs original screen size.
723 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
724 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
725 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
726 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
727 // rescale the bounds depending upon the current screen geometry.
728 ix = (int) (ix * sw);
729 iw = (int) (iw * sw);
730 iy = (int) (iy * sh);
731 ih = (int) (ih * sh);
732 while (ix >= screenSize.width)
734 jalview.bin.Cache.log.debug(
735 "Window geometry location recall error: shifting horizontal to within screenbounds.");
736 ix -= screenSize.width;
738 while (iy >= screenSize.height)
740 jalview.bin.Cache.log.debug(
741 "Window geometry location recall error: shifting vertical to within screenbounds.");
742 iy -= screenSize.height;
744 jalview.bin.Cache.log.debug(
745 "Got last known dimensions for " + windowName + ": x:" + ix
746 + " y:" + iy + " width:" + iw + " height:" + ih);
748 // return dimensions for new instance
749 return new Rectangle(ix, iy, iw, ih);
754 private void doVamsasClientCheck()
756 if (Cache.vamsasJarsPresent())
758 setupVamsasDisconnectedGui();
759 VamsasMenu.setVisible(true);
760 final Desktop us = this;
761 VamsasMenu.addMenuListener(new MenuListener()
763 // this listener remembers when the menu was first selected, and
764 // doesn't rebuild the session list until it has been cleared and
766 boolean refresh = true;
769 public void menuCanceled(MenuEvent e)
775 public void menuDeselected(MenuEvent e)
781 public void menuSelected(MenuEvent e)
785 us.buildVamsasStMenu();
790 vamsasStart.setVisible(true);
794 protected void showPasteMenu(int x, int y)
796 JPopupMenu popup = new JPopupMenu();
797 JMenuItem item = new JMenuItem(
798 MessageManager.getString("label.paste_new_window"));
799 item.addActionListener(new ActionListener()
802 public void actionPerformed(ActionEvent evt)
809 popup.show(this, x, y);
816 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
817 Transferable contents = c.getContents(this);
819 if (contents != null)
821 String file = (String) contents
822 .getTransferData(DataFlavor.stringFlavor);
824 FileFormatI format = new IdentifyFile().identify(file,
825 DataSourceType.PASTE);
827 new FileLoader().loadFile(file, DataSourceType.PASTE, format);
830 } catch (Exception ex)
833 "Unable to paste alignment from system clipboard:\n" + ex);
838 * Adds and opens the given frame to the desktop
849 public static synchronized void addInternalFrame(
850 final JInternalFrame frame, String title, int w, int h)
852 addInternalFrame(frame, title, true, w, h, true, false);
856 * Add an internal frame to the Jalview desktop
863 * When true, display frame immediately, otherwise, caller must call
864 * setVisible themselves.
870 public static synchronized void addInternalFrame(
871 final JInternalFrame frame, String title, boolean makeVisible,
874 addInternalFrame(frame, title, makeVisible, w, h, true, false);
878 * Add an internal frame to the Jalview desktop and make it visible
891 public static synchronized void addInternalFrame(
892 final JInternalFrame frame, String title, int w, int h,
895 addInternalFrame(frame, title, true, w, h, resizable, false);
899 * Add an internal frame to the Jalview desktop
906 * When true, display frame immediately, otherwise, caller must call
907 * setVisible themselves.
914 * @param ignoreMinSize
915 * Do not set the default minimum size for frame
917 public static synchronized void addInternalFrame(
918 final JInternalFrame frame, String title, boolean makeVisible,
919 int w, int h, boolean resizable, boolean ignoreMinSize)
923 // TODO: allow callers to determine X and Y position of frame (eg. via
925 // TODO: consider fixing method to update entries in the window submenu with
926 // the current window title
928 frame.setTitle(title);
929 if (w > 0 && (frame.getWidth() < 1 || frame.getHeight() < 1))
933 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
934 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
935 // IF JALVIEW IS RUNNING HEADLESS
936 // ///////////////////////////////////////////////
937 if (Jalview.isHeadlessMode() || Desktop.getInstance().instanceOnly)
946 frame.setMinimumSize(
947 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
949 // Set default dimension for Alignment Frame window.
950 // The Alignment Frame window could be added from a number of places,
952 // I did this here in order not to miss out on any Alignment frame.
953 if (frame instanceof AlignFrame)
955 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
956 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
960 frame.setVisible(makeVisible);
961 frame.setClosable(true);
962 frame.setResizable(resizable);
963 frame.setMaximizable(resizable);
964 frame.setIconifiable(resizable);
965 frame.setOpaque(Platform.isJS());
967 if (frame.getX() < 1 && frame.getY() < 1)
969 frame.setLocation(xOffset * openFrameCount,
970 yOffset * ((openFrameCount - 1) % 10) + yOffset);
974 * add an entry for the new frame in the Window menu
975 * (and remove it when the frame is closed)
977 JMenuItem menuItem = new JMenuItem(title);
978 frame.addInternalFrameListener(new InternalFrameAdapter()
981 public void internalFrameActivated(InternalFrameEvent evt)
983 JInternalFrame itf = getDesktopPane().getSelectedFrame();
986 if (itf instanceof AlignFrame)
988 Jalview.setCurrentAlignFrame((AlignFrame) itf);
995 public void internalFrameClosed(InternalFrameEvent evt)
997 PaintRefresher.RemoveComponent(frame);
1000 * defensive check to prevent frames being
1001 * added half off the window
1003 if (openFrameCount > 0)
1009 * ensure no reference to alignFrame retained by menu item listener
1011 if (menuItem.getActionListeners().length > 0)
1013 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
1015 Desktop.getInstance().windowMenu.remove(menuItem);
1019 menuItem.addActionListener(new ActionListener()
1022 public void actionPerformed(ActionEvent e)
1026 frame.setSelected(true);
1027 frame.setIcon(false);
1028 } catch (java.beans.PropertyVetoException ex)
1030 // System.err.println(ex.toString());
1035 setKeyBindings(frame);
1037 getDesktopPane().add(frame);
1039 Desktop.getInstance().windowMenu.add(menuItem);
1044 frame.setSelected(true);
1045 frame.requestFocus();
1046 } catch (java.beans.PropertyVetoException ve)
1048 } catch (java.lang.ClassCastException cex)
1051 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
1057 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
1062 private static void setKeyBindings(JInternalFrame frame)
1064 final Action closeAction = new AbstractAction()
1067 public void actionPerformed(ActionEvent e)
1074 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1076 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1077 InputEvent.CTRL_DOWN_MASK);
1078 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1079 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1081 InputMap inputMap = frame
1082 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1083 String ctrlW = ctrlWKey.toString();
1084 inputMap.put(ctrlWKey, ctrlW);
1085 inputMap.put(cmdWKey, ctrlW);
1087 ActionMap actionMap = frame.getActionMap();
1088 actionMap.put(ctrlW, closeAction);
1092 public void lostOwnership(Clipboard clipboard, Transferable contents)
1096 Desktop.getInstance().jalviewClipboard = null;
1099 internalCopy = false;
1103 public void dragEnter(DropTargetDragEvent evt)
1108 public void dragExit(DropTargetEvent evt)
1113 public void dragOver(DropTargetDragEvent evt)
1118 public void dropActionChanged(DropTargetDragEvent evt)
1129 public void drop(DropTargetDropEvent evt)
1131 boolean success = true;
1132 // JAL-1552 - acceptDrop required before getTransferable call for
1133 // Java's Transferable for native dnd
1134 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1135 Transferable t = evt.getTransferable();
1136 List<Object> files = new ArrayList<>();
1137 List<DataSourceType> protocols = new ArrayList<>();
1141 Desktop.transferFromDropTarget(files, protocols, evt, t);
1142 } catch (Exception e)
1144 e.printStackTrace();
1152 for (int i = 0; i < files.size(); i++)
1154 // BH 2018 File or String
1155 Object file = files.get(i);
1156 String fileName = file.toString();
1157 DataSourceType protocol = (protocols == null)
1158 ? DataSourceType.FILE
1160 FileFormatI format = null;
1162 if (fileName.endsWith(".jar"))
1164 format = FileFormat.Jalview;
1169 format = new IdentifyFile().identify(file, protocol);
1171 if (file instanceof File)
1173 Platform.cacheFileData((File) file);
1175 new FileLoader().loadFile(null, file, protocol, format);
1178 } catch (Exception ex)
1183 evt.dropComplete(success); // need this to ensure input focus is properly
1184 // transfered to any new windows created
1194 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1196 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1197 JalviewFileChooser chooser = JalviewFileChooser
1198 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, true);
1200 chooser.setFileView(new JalviewFileView());
1201 chooser.setDialogTitle(
1202 MessageManager.getString("label.open_local_file"));
1203 chooser.setToolTipText(MessageManager.getString("action.open"));
1205 chooser.setResponseHandler(0, new Runnable()
1210 File selectedFile = chooser.getSelectedFile();
1211 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1213 FileFormatI format = chooser.getSelectedFormat();
1216 * Call IdentifyFile to verify the file contains what its extension implies.
1217 * Skip this step for dynamically added file formats, because
1218 * IdentifyFile does not know how to recognise them.
1220 if (FileFormats.getInstance().isIdentifiable(format))
1224 format = new IdentifyFile().identify(selectedFile,
1225 DataSourceType.FILE);
1226 } catch (FileFormatException e)
1228 // format = null; //??
1232 new FileLoader().loadFile(viewport, selectedFile,
1233 DataSourceType.FILE, format);
1236 chooser.showOpenDialog(this);
1240 * Shows a dialog for input of a URL at which to retrieve alignment data
1245 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1247 // This construct allows us to have a wider textfield
1249 JLabel label = new JLabel(
1250 MessageManager.getString("label.input_file_url"));
1252 JPanel panel = new JPanel(new GridLayout(2, 1));
1256 * the URL to fetch is
1257 * Java: an editable combobox with history
1258 * JS: (pending JAL-3038) a plain text field
1261 String urlBase = "http://www.";
1262 if (Platform.isJS())
1264 history = new JTextField(urlBase, 35);
1273 JComboBox<String> asCombo = new JComboBox<>();
1274 asCombo.setPreferredSize(new Dimension(400, 20));
1275 asCombo.setEditable(true);
1276 asCombo.addItem(urlBase);
1277 String historyItems = Cache.getProperty("RECENT_URL");
1278 if (historyItems != null)
1280 for (String token : historyItems.split("\\t"))
1282 asCombo.addItem(token);
1289 Object[] options = new Object[] { MessageManager.getString("action.ok"),
1290 MessageManager.getString("action.cancel") };
1291 Runnable action = new Runnable()
1296 @SuppressWarnings("unchecked")
1297 String url = (history instanceof JTextField
1298 ? ((JTextField) history).getText()
1299 : ((JComboBox<String>) history).getSelectedItem()
1302 if (url.toLowerCase().endsWith(".jar"))
1304 if (viewport != null)
1306 new FileLoader().loadFile(viewport, url, DataSourceType.URL,
1307 FileFormat.Jalview);
1311 new FileLoader().loadFile(url, DataSourceType.URL,
1312 FileFormat.Jalview);
1317 FileFormatI format = null;
1320 format = new IdentifyFile().identify(url, DataSourceType.URL);
1321 } catch (FileFormatException e)
1323 // TODO revise error handling, distinguish between
1324 // URL not found and response not valid
1329 String msg = MessageManager
1330 .formatMessage("label.couldnt_locate", url);
1331 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
1333 MessageManager.getString("label.url_not_found"),
1334 JvOptionPane.WARNING_MESSAGE);
1339 if (viewport != null)
1341 new FileLoader().loadFile(viewport, url, DataSourceType.URL,
1346 new FileLoader().loadFile(url, DataSourceType.URL, format);
1351 String dialogOption = MessageManager
1352 .getString("label.input_alignment_from_url");
1353 JvOptionPane.newOptionDialog(getDesktopPane())
1354 .setResponseHandler(0, action)
1355 .showInternalDialog(panel, dialogOption,
1356 JvOptionPane.YES_NO_CANCEL_OPTION,
1357 JvOptionPane.PLAIN_MESSAGE, null, options,
1358 MessageManager.getString("action.ok"));
1362 * Opens the CutAndPaste window for the user to paste an alignment in to
1365 * - if not null, the pasted alignment is added to the current
1366 * alignment; if null, to a new alignment window
1369 public void inputTextboxMenuItem_actionPerformed(
1370 AlignmentViewPanel viewPanel)
1372 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1373 cap.setForInput(viewPanel);
1374 Desktop.addInternalFrame(cap,
1375 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1385 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1386 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1388 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1389 screen.height + "");
1390 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1391 getWidth(), getHeight()));
1393 if (jconsole != null)
1395 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1396 jconsole.stopConsole();
1400 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1403 if (dialogExecutor != null)
1405 dialogExecutor.shutdownNow();
1407 closeAll_actionPerformed(null);
1409 if (groovyConsole != null)
1411 // suppress a possible repeat prompt to save script
1412 groovyConsole.setDirty(false);
1413 groovyConsole.exit();
1418 private void storeLastKnownDimensions(String string, Rectangle jc)
1420 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1421 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1422 + " height:" + jc.height);
1424 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1425 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1426 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1427 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1437 public void aboutMenuItem_actionPerformed(ActionEvent e)
1439 // StringBuffer message = getAboutMessage(false);
1440 // JvOptionPane.showInternalMessageDialog(Desktop.getDesktop(),
1442 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1443 new Thread(new Runnable()
1448 new SplashScreen(true);
1453 public StringBuffer getAboutMessage(boolean shortv)
1455 StringBuffer message = new StringBuffer();
1456 message.append("<html>");
1459 message.append("<h1><strong>Version: "
1460 + jalview.bin.Cache.getProperty("VERSION")
1461 + "</strong></h1>");
1462 message.append("<strong>Last Updated: <em>"
1463 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1464 + "</em></strong>");
1470 message.append("<strong>Version "
1471 + jalview.bin.Cache.getProperty("VERSION")
1472 + "; last updated: "
1473 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1476 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1477 .equals("Checking"))
1479 message.append("<br>...Checking latest version...</br>");
1481 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1482 .equals(jalview.bin.Cache.getProperty("VERSION")))
1484 boolean red = false;
1485 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1486 .indexOf("automated build") == -1)
1489 // Displayed when code version and jnlp version do not match and code
1490 // version is not a development build
1491 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1494 message.append("<br>!! Version "
1495 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1497 + " is available for download from "
1498 + jalview.bin.Cache.getDefault("www.jalview.org",
1499 "http://www.jalview.org")
1503 message.append("</div>");
1506 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1508 "The Jalview Authors (See AUTHORS file for current list)")
1509 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1510 + "<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"
1511 + "<br><br>If you use Jalview, please cite:"
1512 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1513 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1514 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1520 * Action on requesting Help documentation
1523 public void documentationMenuItem_actionPerformed()
1527 if (Platform.isJS())
1529 BrowserLauncher.openURL("http://www.jalview.org/help.html");
1538 Help.showHelpWindow();
1540 } catch (Exception ex)
1542 System.err.println("Error opening help: " + ex.getMessage());
1547 public void closeAll_actionPerformed(ActionEvent e)
1549 if (desktopPane == null)
1553 // TODO show a progress bar while closing?
1554 JInternalFrame[] frames = desktopPane.getAllFrames();
1555 for (int i = 0; i < frames.length; i++)
1559 frames[i].setClosed(true);
1560 } catch (java.beans.PropertyVetoException ex)
1564 Jalview.setCurrentAlignFrame(null);
1565 System.out.println("ALL CLOSED");
1566 if (v_client != null)
1568 // TODO clear binding to vamsas document objects on close_all
1572 * reset state of singleton objects as appropriate (clear down session state
1573 * when all windows are closed)
1575 getStructureSelectionManager().resetAll();
1579 public void raiseRelated_actionPerformed(ActionEvent e)
1581 reorderAssociatedWindows(false, false);
1585 public void minimizeAssociated_actionPerformed(ActionEvent e)
1587 reorderAssociatedWindows(true, false);
1590 void closeAssociatedWindows()
1592 reorderAssociatedWindows(false, true);
1598 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1602 protected void garbageCollect_actionPerformed(ActionEvent e)
1604 // We simply collect the garbage
1605 jalview.bin.Cache.log.debug("Collecting garbage...");
1607 jalview.bin.Cache.log.debug("Finished garbage collection.");
1614 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1618 protected void showMemusage_actionPerformed(ActionEvent e)
1620 getDesktopPane().showMemoryUsage(showMemusage.isSelected());
1627 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1631 protected void showConsole_actionPerformed(ActionEvent e)
1633 showConsole(showConsole.isSelected());
1636 Console jconsole = null;
1639 * control whether the java console is visible or not
1643 void showConsole(boolean selected)
1645 // TODO: decide if we should update properties file
1646 if (jconsole != null) // BH 2018
1648 showConsole.setSelected(selected);
1649 Cache.setProperty("SHOW_JAVA_CONSOLE",
1650 Boolean.valueOf(selected).toString());
1651 jconsole.setVisible(selected);
1655 void reorderAssociatedWindows(boolean minimize, boolean close)
1657 JInternalFrame[] frames = getDesktopPane().getAllFrames();
1658 if (frames == null || frames.length < 1)
1663 AlignmentViewport source = null, target = null;
1664 if (frames[0] instanceof AlignFrame)
1666 source = ((AlignFrame) frames[0]).getCurrentView();
1668 else if (frames[0] instanceof TreePanel)
1670 source = ((TreePanel) frames[0]).getViewPort();
1672 else if (frames[0] instanceof PCAPanel)
1674 source = ((PCAPanel) frames[0]).av;
1676 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1678 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1683 for (int i = 0; i < frames.length; i++)
1686 if (frames[i] == null)
1690 if (frames[i] instanceof AlignFrame)
1692 target = ((AlignFrame) frames[i]).getCurrentView();
1694 else if (frames[i] instanceof TreePanel)
1696 target = ((TreePanel) frames[i]).getViewPort();
1698 else if (frames[i] instanceof PCAPanel)
1700 target = ((PCAPanel) frames[i]).av;
1702 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1704 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1707 if (source == target)
1713 frames[i].setClosed(true);
1717 frames[i].setIcon(minimize);
1720 frames[i].toFront();
1724 } catch (java.beans.PropertyVetoException ex)
1739 protected void preferences_actionPerformed(ActionEvent e)
1745 * Prompts the user to choose a file and then saves the Jalview state as a
1746 * Jalview project file
1749 public void saveState_actionPerformed()
1751 saveState_actionPerformed(false);
1754 public void saveState_actionPerformed(boolean saveAs)
1756 java.io.File projectFile = getProjectFile();
1757 // autoSave indicates we already have a file and don't need to ask
1758 boolean autoSave = projectFile != null && !saveAs
1759 && BackupFiles.getEnabled();
1761 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1762 // saveAs="+saveAs+", Backups
1763 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1765 boolean approveSave = false;
1768 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1771 chooser.setFileView(new JalviewFileView());
1772 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1774 int value = chooser.showSaveDialog(this);
1776 if (value == JalviewFileChooser.APPROVE_OPTION)
1778 projectFile = chooser.getSelectedFile();
1779 setProjectFile(projectFile);
1784 if (approveSave || autoSave)
1786 final Desktop me = this;
1787 final java.io.File chosenFile = projectFile;
1788 new Thread(new Runnable()
1793 // TODO: refactor to Jalview desktop session controller action.
1794 setProgressBar(MessageManager.formatMessage(
1795 "label.saving_jalview_project", new Object[]
1796 { chosenFile.getName() }), chosenFile.hashCode());
1797 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1798 chosenFile.getParent());
1799 // TODO catch and handle errors for savestate
1800 // TODO prevent user from messing with the Desktop whilst we're saving
1803 boolean doBackup = BackupFiles.getEnabled();
1804 BackupFiles backupfiles = doBackup ? new BackupFiles(chosenFile) : null;
1806 new Jalview2XML().saveState(doBackup ? backupfiles.getTempFile() : chosenFile);
1810 backupfiles.setWriteSuccess(true);
1811 backupfiles.rollBackupsAndRenameTempFile();
1813 } catch (OutOfMemoryError oom)
1815 new OOMWarning("Whilst saving current state to "
1816 + chosenFile.getName(), oom);
1817 } catch (Exception ex)
1819 Cache.log.error("Problems whilst trying to save to "
1820 + chosenFile.getName(), ex);
1821 JvOptionPane.showMessageDialog(me,
1822 MessageManager.formatMessage(
1823 "label.error_whilst_saving_current_state_to",
1825 { chosenFile.getName() }),
1826 MessageManager.getString("label.couldnt_save_project"),
1827 JvOptionPane.WARNING_MESSAGE);
1829 setProgressBar(null, chosenFile.hashCode());
1836 public void saveAsState_actionPerformed(ActionEvent e)
1838 saveState_actionPerformed(true);
1841 protected void setProjectFile(File choice)
1843 this.projectFile = choice;
1846 public File getProjectFile()
1848 return this.projectFile;
1852 * Shows a file chooser dialog and tries to read in the selected file as a
1856 public void loadState_actionPerformed()
1858 final String[] suffix = new String[] { "jvp", "jar" };
1859 final String[] desc = new String[] { "Jalview Project",
1860 "Jalview Project (old)" };
1861 JalviewFileChooser chooser = new JalviewFileChooser(
1862 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1863 "Jalview Project", true, true); // last two booleans: allFiles,
1865 chooser.setFileView(new JalviewFileView());
1866 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1867 chooser.setResponseHandler(0, new Runnable()
1872 File selectedFile = chooser.getSelectedFile();
1873 setProjectFile(selectedFile);
1874 String choice = selectedFile.getAbsolutePath();
1875 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1876 new Thread(new Runnable()
1883 new Jalview2XML().loadJalviewAlign(choice);
1884 } catch (OutOfMemoryError oom)
1886 new OOMWarning("Whilst loading project from " + choice, oom);
1887 } catch (Exception ex)
1890 "Problems whilst loading project from " + choice, ex);
1891 JvOptionPane.showMessageDialog(Desktop.getDesktopPane(),
1892 MessageManager.formatMessage(
1893 "label.error_whilst_loading_project_from",
1896 MessageManager.getString("label.couldnt_load_project"),
1897 JvOptionPane.WARNING_MESSAGE);
1904 chooser.showOpenDialog(this);
1908 public void inputSequence_actionPerformed(ActionEvent e)
1910 new SequenceFetcher(this);
1913 JPanel progressPanel;
1915 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1917 public void startLoading(final Object fileName)
1919 if (fileLoadingCount == 0)
1921 fileLoadingPanels.add(addProgressPanel(MessageManager
1922 .formatMessage("label.loading_file", new Object[]
1928 private JPanel addProgressPanel(String string)
1930 if (progressPanel == null)
1932 progressPanel = new JPanel(new GridLayout(1, 1));
1933 totalProgressCount = 0;
1934 getContentPane().add(progressPanel, BorderLayout.SOUTH);
1936 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1937 JProgressBar progressBar = new JProgressBar();
1938 progressBar.setIndeterminate(true);
1940 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1942 thisprogress.add(progressBar, BorderLayout.CENTER);
1943 progressPanel.add(thisprogress);
1944 ((GridLayout) progressPanel.getLayout()).setRows(
1945 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1946 ++totalProgressCount;
1948 return thisprogress;
1951 int totalProgressCount = 0;
1953 private void removeProgressPanel(JPanel progbar)
1955 if (progressPanel != null)
1957 synchronized (progressPanel)
1959 progressPanel.remove(progbar);
1960 GridLayout gl = (GridLayout) progressPanel.getLayout();
1961 gl.setRows(gl.getRows() - 1);
1962 if (--totalProgressCount < 1)
1964 this.getContentPane().remove(progressPanel);
1965 progressPanel = null;
1972 public void stopLoading()
1975 if (fileLoadingCount < 1)
1977 while (fileLoadingPanels.size() > 0)
1979 removeProgressPanel(fileLoadingPanels.remove(0));
1981 fileLoadingPanels.clear();
1982 fileLoadingCount = 0;
1987 public static int getViewCount(String alignmentId)
1989 AlignmentViewport[] aps = getViewports(alignmentId);
1990 return (aps == null) ? 0 : aps.length;
1995 * @param alignmentId
1996 * - if null, all sets are returned
1997 * @return all AlignmentPanels concerning the alignmentId sequence set
1999 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
2001 if (Desktop.getDesktopPane() == null)
2003 // no frames created and in headless mode
2004 // TODO: verify that frames are recoverable when in headless mode
2007 List<AlignmentPanel> aps = new ArrayList<>();
2008 AlignFrame[] frames = getAlignFrames();
2013 for (AlignFrame af : frames)
2015 for (AlignmentPanel ap : af.alignPanels)
2017 if (alignmentId == null
2018 || alignmentId.equals(ap.av.getSequenceSetId()))
2024 if (aps.size() == 0)
2028 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
2033 * get all the viewports on an alignment.
2035 * @param sequenceSetId
2036 * unique alignment id (may be null - all viewports returned in that
2038 * @return all viewports on the alignment bound to sequenceSetId
2040 public static AlignmentViewport[] getViewports(String sequenceSetId)
2042 List<AlignmentViewport> viewp = new ArrayList<>();
2043 if (getDesktopPane() != null)
2045 AlignFrame[] frames = Desktop.getAlignFrames();
2047 for (AlignFrame afr : frames)
2049 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
2050 .equals(sequenceSetId))
2052 if (afr.alignPanels != null)
2054 for (AlignmentPanel ap : afr.alignPanels)
2056 if (sequenceSetId == null
2057 || sequenceSetId.equals(ap.av.getSequenceSetId()))
2065 viewp.add(afr.getViewport());
2069 if (viewp.size() > 0)
2071 return viewp.toArray(new AlignmentViewport[viewp.size()]);
2078 * Explode the views in the given frame into separate AlignFrame
2082 public static void explodeViews(AlignFrame af)
2084 int size = af.alignPanels.size();
2090 for (int i = 0; i < size; i++)
2092 AlignmentPanel ap = af.alignPanels.get(i);
2093 AlignFrame newaf = new AlignFrame(ap);
2096 * Restore the view's last exploded frame geometry if known. Multiple
2097 * views from one exploded frame share and restore the same (frame)
2098 * position and size.
2100 Rectangle geometry = ap.av.getExplodedGeometry();
2101 if (geometry != null)
2103 newaf.setBounds(geometry);
2106 ap.av.setGatherViewsHere(false);
2108 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2109 AlignFrame.DEFAULT_HEIGHT);
2112 af.alignPanels.clear();
2113 af.closeMenuItem_actionPerformed(true);
2118 * Gather expanded views (separate AlignFrame's) with the same sequence set
2119 * identifier back in to this frame as additional views, and close the expanded
2120 * views. Note the expanded frames may themselves have multiple views. We take
2125 public void gatherViews(AlignFrame source)
2127 source.viewport.setGatherViewsHere(true);
2128 source.viewport.setExplodedGeometry(source.getBounds());
2129 JInternalFrame[] frames = getAllFrames();
2130 String viewId = source.viewport.getSequenceSetId();
2132 for (int t = 0; t < frames.length; t++)
2134 if (frames[t] instanceof AlignFrame && frames[t] != source)
2136 AlignFrame af = (AlignFrame) frames[t];
2137 boolean gatherThis = false;
2138 for (int a = 0; a < af.alignPanels.size(); a++)
2140 AlignmentPanel ap = af.alignPanels.get(a);
2141 if (viewId.equals(ap.av.getSequenceSetId()))
2144 ap.av.setGatherViewsHere(false);
2145 ap.av.setExplodedGeometry(af.getBounds());
2146 source.addAlignmentPanel(ap, false);
2152 af.alignPanels.clear();
2153 af.closeMenuItem_actionPerformed(true);
2160 jalview.gui.VamsasApplication v_client = null;
2163 public void vamsasImport_actionPerformed(ActionEvent e)
2165 // TODO: JAL-3048 not needed for Jalview-JS
2167 if (v_client == null)
2169 // Load and try to start a session.
2170 JalviewFileChooser chooser = new JalviewFileChooser(
2171 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2173 chooser.setFileView(new JalviewFileView());
2174 chooser.setDialogTitle(
2175 MessageManager.getString("label.open_saved_vamsas_session"));
2176 chooser.setToolTipText(MessageManager.getString(
2177 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2179 int value = chooser.showOpenDialog(this);
2181 if (value == JalviewFileChooser.APPROVE_OPTION)
2183 String fle = chooser.getSelectedFile().toString();
2184 if (!vamsasImport(chooser.getSelectedFile()))
2186 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
2187 MessageManager.formatMessage(
2188 "label.couldnt_import_as_vamsas_session",
2192 .getString("label.vamsas_document_import_failed"),
2193 JvOptionPane.ERROR_MESSAGE);
2199 jalview.bin.Cache.log.error(
2200 "Implementation error - load session from a running session is not supported.");
2205 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2208 * @return true if import was a success and a session was started.
2210 public boolean vamsasImport(URL url)
2212 // TODO: create progress bar
2213 if (v_client != null)
2216 jalview.bin.Cache.log.error(
2217 "Implementation error - load session from a running session is not supported.");
2223 // copy the URL content to a temporary local file
2224 // TODO: be a bit cleverer here with nio (?!)
2225 File file = File.createTempFile("vdocfromurl", ".vdj");
2226 FileOutputStream fos = new FileOutputStream(file);
2227 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2228 byte[] buffer = new byte[2048];
2230 while ((ln = bis.read(buffer)) > -1)
2232 fos.write(buffer, 0, ln);
2236 v_client = new jalview.gui.VamsasApplication(this, file,
2237 url.toExternalForm());
2238 } catch (Exception ex)
2240 jalview.bin.Cache.log.error(
2241 "Failed to create new vamsas session from contents of URL "
2246 setupVamsasConnectedGui();
2247 v_client.initial_update(); // TODO: thread ?
2248 return v_client.inSession();
2252 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2255 * @return true if import was a success and a session was started.
2257 public boolean vamsasImport(File file)
2259 if (v_client != null)
2262 jalview.bin.Cache.log.error(
2263 "Implementation error - load session from a running session is not supported.");
2267 setProgressBar(MessageManager.formatMessage(
2268 "status.importing_vamsas_session_from", new Object[]
2269 { file.getName() }), file.hashCode());
2272 v_client = new jalview.gui.VamsasApplication(this, file, null);
2273 } catch (Exception ex)
2275 setProgressBar(MessageManager.formatMessage(
2276 "status.importing_vamsas_session_from", new Object[]
2277 { file.getName() }), file.hashCode());
2278 jalview.bin.Cache.log.error(
2279 "New vamsas session from existing session file failed:", ex);
2282 setupVamsasConnectedGui();
2283 v_client.initial_update(); // TODO: thread ?
2284 setProgressBar(MessageManager.formatMessage(
2285 "status.importing_vamsas_session_from", new Object[]
2286 { file.getName() }), file.hashCode());
2287 return v_client.inSession();
2290 public boolean joinVamsasSession(String mysesid)
2292 if (v_client != null)
2294 throw new Error(MessageManager
2295 .getString("error.try_join_vamsas_session_another"));
2297 if (mysesid == null)
2300 MessageManager.getString("error.invalid_vamsas_session_id"));
2302 v_client = new VamsasApplication(this, mysesid);
2303 setupVamsasConnectedGui();
2304 v_client.initial_update();
2305 return (v_client.inSession());
2309 public void vamsasStart_actionPerformed(ActionEvent e)
2311 if (v_client == null)
2314 // we just start a default session for moment.
2316 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2317 * getProperty("LAST_DIRECTORY"));
2319 * chooser.setFileView(new JalviewFileView());
2320 * chooser.setDialogTitle("Load Vamsas file");
2321 * chooser.setToolTipText("Import");
2323 * int value = chooser.showOpenDialog(this);
2325 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2326 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2328 v_client = new VamsasApplication(this);
2329 setupVamsasConnectedGui();
2330 v_client.initial_update(); // TODO: thread ?
2334 // store current data in session.
2335 v_client.push_update(); // TODO: thread
2339 protected void setupVamsasConnectedGui()
2341 vamsasStart.setText(MessageManager.getString("label.session_update"));
2342 vamsasSave.setVisible(true);
2343 vamsasStop.setVisible(true);
2344 vamsasImport.setVisible(false); // Document import to existing session is
2345 // not possible for vamsas-client-1.0.
2348 protected void setupVamsasDisconnectedGui()
2350 vamsasSave.setVisible(false);
2351 vamsasStop.setVisible(false);
2352 vamsasImport.setVisible(true);
2354 .setText(MessageManager.getString("label.new_vamsas_session"));
2358 public void vamsasStop_actionPerformed(ActionEvent e)
2360 if (v_client != null)
2362 v_client.end_session();
2364 setupVamsasDisconnectedGui();
2368 protected void buildVamsasStMenu()
2370 if (v_client == null)
2372 String[] sess = null;
2375 sess = VamsasApplication.getSessionList();
2376 } catch (Exception e)
2378 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2384 jalview.bin.Cache.log.debug(
2385 "Got current sessions list: " + sess.length + " entries.");
2386 VamsasStMenu.removeAll();
2387 for (int i = 0; i < sess.length; i++)
2389 JMenuItem sessit = new JMenuItem();
2390 sessit.setText(sess[i]);
2391 sessit.setToolTipText(MessageManager
2392 .formatMessage("label.connect_to_session", new Object[]
2394 final Desktop dsktp = this;
2395 final String mysesid = sess[i];
2396 sessit.addActionListener(new ActionListener()
2400 public void actionPerformed(ActionEvent e)
2402 if (dsktp.v_client == null)
2404 Thread rthr = new Thread(new Runnable()
2410 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2411 dsktp.setupVamsasConnectedGui();
2412 dsktp.v_client.initial_update();
2420 VamsasStMenu.add(sessit);
2422 // don't show an empty menu.
2423 VamsasStMenu.setVisible(sess.length > 0);
2428 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2429 VamsasStMenu.removeAll();
2430 VamsasStMenu.setVisible(false);
2435 // Not interested in the content. Just hide ourselves.
2436 VamsasStMenu.setVisible(false);
2441 public void vamsasSave_actionPerformed(ActionEvent e)
2443 // TODO: JAL-3048 not needed for Jalview-JS
2445 if (v_client != null)
2447 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2448 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2451 chooser.setFileView(new JalviewFileView());
2452 chooser.setDialogTitle(MessageManager
2453 .getString("label.save_vamsas_document_archive"));
2455 int value = chooser.showSaveDialog(this);
2457 if (value == JalviewFileChooser.APPROVE_OPTION)
2459 java.io.File choice = chooser.getSelectedFile();
2460 JPanel progpanel = addProgressPanel(MessageManager
2461 .formatMessage("label.saving_vamsas_doc", new Object[]
2462 { choice.getName() }));
2463 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2464 String warnmsg = null;
2465 String warnttl = null;
2468 v_client.vclient.storeDocument(choice);
2471 warnttl = "Serious Problem saving Vamsas Document";
2472 warnmsg = ex.toString();
2473 jalview.bin.Cache.log
2474 .error("Error Whilst saving document to " + choice, ex);
2476 } catch (Exception ex)
2478 warnttl = "Problem saving Vamsas Document.";
2479 warnmsg = ex.toString();
2480 jalview.bin.Cache.log.warn(
2481 "Exception Whilst saving document to " + choice, ex);
2484 removeProgressPanel(progpanel);
2485 if (warnmsg != null)
2487 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
2489 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2495 JPanel vamUpdate = null;
2498 * hide vamsas user gui bits when a vamsas document event is being handled.
2501 * true to hide gui, false to reveal gui
2503 public void setVamsasUpdate(boolean b)
2505 Cache.log.debug("Setting gui for Vamsas update "
2506 + (b ? "in progress" : "finished"));
2508 if (vamUpdate != null)
2510 this.removeProgressPanel(vamUpdate);
2514 vamUpdate = this.addProgressPanel(
2515 MessageManager.getString("label.updating_vamsas_session"));
2517 vamsasStart.setVisible(!b);
2518 vamsasStop.setVisible(!b);
2519 vamsasSave.setVisible(!b);
2522 public JInternalFrame[] getAllFrames()
2524 return desktopPane.getAllFrames();
2528 * Checks the given url to see if it gives a response indicating that the user
2529 * should be informed of a new questionnaire.
2533 public void checkForQuestionnaire(String url)
2535 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2536 // javax.swing.SwingUtilities.invokeLater(jvq);
2537 new Thread(jvq).start();
2540 public void checkURLLinks()
2542 // Thread off the URL link checker
2543 addDialogThread(new Runnable()
2548 if (Cache.getDefault("CHECKURLLINKS", true))
2550 // check what the actual links are - if it's just the default don't
2551 // bother with the warning
2552 List<String> links = Preferences.sequenceUrlLinks
2555 // only need to check links if there is one with a
2556 // SEQUENCE_ID which is not the default EMBL_EBI link
2557 ListIterator<String> li = links.listIterator();
2558 boolean check = false;
2559 List<JLabel> urls = new ArrayList<>();
2560 while (li.hasNext())
2562 String link = li.next();
2563 if (link.contains(UrlConstants.SEQUENCE_ID)
2564 && !UrlConstants.isDefaultString(link))
2567 int barPos = link.indexOf("|");
2568 String urlMsg = barPos == -1 ? link
2569 : link.substring(0, barPos) + ": "
2570 + link.substring(barPos + 1);
2571 urls.add(new JLabel(urlMsg));
2579 // ask user to check in case URL links use old style tokens
2580 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2581 JPanel msgPanel = new JPanel();
2582 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2583 msgPanel.add(Box.createVerticalGlue());
2584 JLabel msg = new JLabel(MessageManager
2585 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2586 JLabel msg2 = new JLabel(MessageManager
2587 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2589 for (JLabel url : urls)
2595 final JCheckBox jcb = new JCheckBox(
2596 MessageManager.getString("label.do_not_display_again"));
2597 jcb.addActionListener(new ActionListener()
2600 public void actionPerformed(ActionEvent e)
2602 // update Cache settings for "don't show this again"
2603 boolean showWarningAgain = !jcb.isSelected();
2604 Cache.setProperty("CHECKURLLINKS",
2605 Boolean.valueOf(showWarningAgain).toString());
2610 JvOptionPane.showMessageDialog(desktopPane, msgPanel,
2612 .getString("label.SEQUENCE_ID_no_longer_used"),
2613 JvOptionPane.WARNING_MESSAGE);
2620 * Proxy class for JDesktopPane which optionally displays the current memory
2621 * usage and highlights the desktop area with a red bar if free memory runs low.
2625 public class MyDesktopPane extends JDesktopPane
2628 private static final float ONE_MB = 1048576f;
2630 boolean showMemoryUsage = false;
2634 java.text.NumberFormat df;
2636 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2639 public MyDesktopPane(boolean showMemoryUsage)
2641 showMemoryUsage(showMemoryUsage);
2644 public void showMemoryUsage(boolean showMemory)
2646 this.showMemoryUsage = showMemory;
2649 Thread worker = new Thread(this);
2655 public boolean isShowMemoryUsage()
2657 return showMemoryUsage;
2663 df = java.text.NumberFormat.getNumberInstance();
2664 df.setMaximumFractionDigits(2);
2665 runtime = Runtime.getRuntime();
2667 while (showMemoryUsage)
2671 maxMemory = runtime.maxMemory() / ONE_MB;
2672 allocatedMemory = runtime.totalMemory() / ONE_MB;
2673 freeMemory = runtime.freeMemory() / ONE_MB;
2674 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2676 percentUsage = (totalFreeMemory / maxMemory) * 100;
2678 // if (percentUsage < 20)
2680 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2682 // instance.set.setBorder(border1);
2685 // sleep after showing usage
2687 } catch (Exception ex)
2689 ex.printStackTrace();
2695 public void paintComponent(Graphics g)
2697 if (showMemoryUsage && g != null && df != null)
2699 if (percentUsage < 20)
2701 g.setColor(Color.red);
2703 FontMetrics fm = g.getFontMetrics();
2706 g.drawString(MessageManager.formatMessage("label.memory_stats",
2708 { df.format(totalFreeMemory), df.format(maxMemory),
2709 df.format(percentUsage) }),
2710 10, getHeight() - fm.getHeight());
2717 * Accessor method to quickly get all the AlignmentFrames loaded.
2719 * @return an array of AlignFrame, or null if none found
2721 public static AlignFrame[] getAlignFrames()
2723 if (Jalview.isHeadlessMode())
2725 // Desktop.getDesktop() is null in headless mode
2726 return new AlignFrame[] { Jalview.getCurrentAlignFrame() };
2729 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
2735 List<AlignFrame> avp = new ArrayList<>();
2737 for (int i = frames.length - 1; i > -1; i--)
2739 if (frames[i] instanceof AlignFrame)
2741 avp.add((AlignFrame) frames[i]);
2743 else if (frames[i] instanceof SplitFrame)
2746 * Also check for a split frame containing an AlignFrame
2748 GSplitFrame sf = (GSplitFrame) frames[i];
2749 if (sf.getTopFrame() instanceof AlignFrame)
2751 avp.add((AlignFrame) sf.getTopFrame());
2753 if (sf.getBottomFrame() instanceof AlignFrame)
2755 avp.add((AlignFrame) sf.getBottomFrame());
2759 if (avp.size() == 0)
2763 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2768 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2772 public GStructureViewer[] getJmols()
2774 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
2780 List<GStructureViewer> avp = new ArrayList<>();
2782 for (int i = frames.length - 1; i > -1; i--)
2784 if (frames[i] instanceof AppJmol)
2786 GStructureViewer af = (GStructureViewer) frames[i];
2790 if (avp.size() == 0)
2794 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2799 * Add Groovy Support to Jalview
2802 public void groovyShell_actionPerformed()
2806 openGroovyConsole();
2807 } catch (Exception ex)
2809 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2810 JvOptionPane.showInternalMessageDialog(desktopPane,
2812 MessageManager.getString("label.couldnt_create_groovy_shell"),
2813 MessageManager.getString("label.groovy_support_failed"),
2814 JvOptionPane.ERROR_MESSAGE);
2819 * Open the Groovy console
2821 private void openGroovyConsole()
2823 if (groovyConsole == null)
2825 groovyConsole = new groovy.ui.Console();
2826 groovyConsole.setVariable("Jalview", this);
2827 groovyConsole.run();
2830 * We allow only one console at a time, so that AlignFrame menu option
2831 * 'Calculate | Run Groovy script' is unambiguous.
2832 * Disable 'Groovy Console', and enable 'Run script', when the console is
2833 * opened, and the reverse when it is closed
2835 Window window = (Window) groovyConsole.getFrame();
2836 window.addWindowListener(new WindowAdapter()
2839 public void windowClosed(WindowEvent e)
2842 * rebind CMD-Q from Groovy Console to Jalview Quit
2845 enableExecuteGroovy(false);
2851 * show Groovy console window (after close and reopen)
2853 ((Window) groovyConsole.getFrame()).setVisible(true);
2856 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2857 * and disable opening a second console
2859 enableExecuteGroovy(true);
2863 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
2866 protected void addQuitHandler()
2868 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2869 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2870 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2872 getRootPane().getActionMap().put("Quit", new AbstractAction()
2875 public void actionPerformed(ActionEvent e)
2883 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2886 * true if Groovy console is open
2888 public void enableExecuteGroovy(boolean enabled)
2891 * disable opening a second Groovy console
2892 * (or re-enable when the console is closed)
2894 groovyShell.setEnabled(!enabled);
2896 AlignFrame[] alignFrames = getAlignFrames();
2897 if (alignFrames != null)
2899 for (AlignFrame af : alignFrames)
2901 af.setGroovyEnabled(enabled);
2907 * Progress bars managed by the IProgressIndicator method.
2909 private Hashtable<Long, JPanel> progressBars;
2911 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2916 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2919 public void setProgressBar(String message, long id)
2921 Platform.timeCheck("Desktop " + message, Platform.TIME_MARK);
2923 if (progressBars == null)
2925 progressBars = new Hashtable<>();
2926 progressBarHandlers = new Hashtable<>();
2929 if (progressBars.get(new Long(id)) != null)
2931 JPanel panel = progressBars.remove(new Long(id));
2932 if (progressBarHandlers.contains(new Long(id)))
2934 progressBarHandlers.remove(new Long(id));
2936 removeProgressPanel(panel);
2940 progressBars.put(new Long(id), addProgressPanel(message));
2947 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2948 * jalview.gui.IProgressIndicatorHandler)
2951 public void registerHandler(final long id,
2952 final IProgressIndicatorHandler handler)
2954 if (progressBarHandlers == null
2955 || !progressBars.containsKey(new Long(id)))
2957 throw new Error(MessageManager.getString(
2958 "error.call_setprogressbar_before_registering_handler"));
2960 progressBarHandlers.put(new Long(id), handler);
2961 final JPanel progressPanel = progressBars.get(new Long(id));
2962 if (handler.canCancel())
2964 JButton cancel = new JButton(
2965 MessageManager.getString("action.cancel"));
2966 final IProgressIndicator us = this;
2967 cancel.addActionListener(new ActionListener()
2971 public void actionPerformed(ActionEvent e)
2973 handler.cancelActivity(id);
2974 us.setProgressBar(MessageManager
2975 .formatMessage("label.cancelled_params", new Object[]
2976 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2980 progressPanel.add(cancel, BorderLayout.EAST);
2986 * @return true if any progress bars are still active
2989 public boolean operationInProgress()
2991 if (progressBars != null && progressBars.size() > 0)
2999 * This will return the first AlignFrame holding the given viewport instance. It
3000 * will break if there are more than one AlignFrames viewing a particular av.
3003 * @return alignFrame for viewport
3005 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
3007 if (getDesktopPane() != null)
3009 AlignmentPanel[] aps = getAlignmentPanels(
3010 viewport.getSequenceSetId());
3011 for (int panel = 0; aps != null && panel < aps.length; panel++)
3013 if (aps[panel] != null && aps[panel].av == viewport)
3015 return aps[panel].alignFrame;
3022 public VamsasApplication getVamsasApplication()
3029 * flag set if jalview GUI is being operated programmatically
3031 private boolean inBatchMode = false;
3034 * check if jalview GUI is being operated programmatically
3036 * @return inBatchMode
3038 public boolean isInBatchMode()
3044 * set flag if jalview GUI is being operated programmatically
3046 * @param inBatchMode
3048 public void setInBatchMode(boolean inBatchMode)
3050 this.inBatchMode = inBatchMode;
3053 public void startServiceDiscovery()
3055 startServiceDiscovery(false);
3058 public void startServiceDiscovery(boolean blocking)
3060 boolean alive = true;
3061 Thread t0 = null, t1 = null, t2 = null;
3062 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3065 // todo: changesupport handlers need to be transferred
3066 if (discoverer == null)
3068 discoverer = Discoverer.getInstance();
3069 // register PCS handler for getDesktop().
3070 discoverer.addPropertyChangeListener(changeSupport);
3072 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3073 // until we phase out completely
3074 (t0 = new Thread(discoverer)).start();
3077 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3079 t2 = jalview.ws.jws2.Jws2Discoverer.getInstance()
3080 .startDiscoverer(changeSupport);
3084 // TODO: do rest service discovery
3093 } catch (Exception e)
3096 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3097 || (t3 != null && t3.isAlive())
3098 || (t0 != null && t0.isAlive());
3104 * called to check if the service discovery process completed successfully.
3108 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3110 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3112 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getInstance()
3113 .getErrorMessages();
3116 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3118 if (serviceChangedDialog == null)
3120 // only run if we aren't already displaying one of these.
3121 addDialogThread(serviceChangedDialog = new Runnable()
3128 * JalviewDialog jd =new JalviewDialog() {
3130 * @Override protected void cancelPressed() { // TODO
3131 * Auto-generated method stub
3133 * }@Override protected void okPressed() { // TODO
3134 * Auto-generated method stub
3136 * }@Override protected void raiseClosed() { // TODO
3137 * Auto-generated method stub
3139 * } }; jd.initDialogFrame(new
3140 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3141 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3142 * + " or mis-configured HTTP proxy settings.<br/>" +
3143 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3145 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3146 * ), true, true, "Web Service Configuration Problem", 450,
3149 * jd.waitForInput();
3151 JvOptionPane.showConfirmDialog(Desktop.getDesktopPane(),
3152 new JLabel("<html><table width=\"450\"><tr><td>"
3153 + ermsg + "</td></tr></table>"
3154 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3155 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3156 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3157 + " Tools->Preferences dialog box to change them.</p></html>"),
3158 "Web Service Configuration Problem",
3159 JvOptionPane.DEFAULT_OPTION,
3160 JvOptionPane.ERROR_MESSAGE);
3161 serviceChangedDialog = null;
3170 "Errors reported by JABA discovery service. Check web services preferences.\n"
3177 Runnable serviceChangedDialog = null;
3180 * start a thread to open a URL in the configured browser. Pops up a warning
3181 * dialog to the user if there is an exception when calling out to the browser
3186 public static void showUrl(final String url)
3188 showUrl(url, Desktop.getInstance());
3192 * Like showUrl but allows progress handler to be specified
3196 * (null) or object implementing IProgressIndicator
3198 public static void showUrl(final String url,
3199 final IProgressIndicator progress)
3201 new Thread(new Runnable()
3208 if (progress != null)
3210 progress.setProgressBar(MessageManager
3211 .formatMessage("status.opening_params", new Object[]
3212 { url }), this.hashCode());
3214 BrowserLauncher.openURL(url);
3215 } catch (Exception ex)
3217 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
3219 .getString("label.web_browser_not_found_unix"),
3220 MessageManager.getString("label.web_browser_not_found"),
3221 JvOptionPane.WARNING_MESSAGE);
3223 ex.printStackTrace();
3225 if (progress != null)
3227 progress.setProgressBar(null, this.hashCode());
3233 private WsParamSetManager wsparamManager = null;
3235 public static ParamManager getUserParameterStore()
3237 Desktop d = Desktop.getInstance();
3238 if (d.wsparamManager == null)
3240 d.wsparamManager = new WsParamSetManager();
3242 return d.wsparamManager;
3246 * static hyperlink handler proxy method for use by Jalview's internal windows
3250 public static void hyperlinkUpdate(HyperlinkEvent e)
3252 if (e.getEventType() == EventType.ACTIVATED)
3257 url = e.getURL().toString();
3258 Desktop.showUrl(url);
3259 } catch (Exception x)
3263 if (Cache.log != null)
3265 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3270 "Couldn't handle string " + url + " as a URL.");
3273 // ignore any exceptions due to dud links.
3280 * single thread that handles display of dialogs to user.
3282 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3285 * flag indicating if dialogExecutor should try to acquire a permit
3287 volatile boolean dialogPause = true;
3292 java.util.concurrent.Semaphore block = new Semaphore(0);
3294 private groovy.ui.Console groovyConsole;
3296 public StructureViewer lastTargetedView;
3299 * add another dialog thread to the queue
3303 public void addDialogThread(final Runnable prompter)
3305 dialogExecutor.submit(new Runnable()
3315 } catch (InterruptedException x)
3325 SwingUtilities.invokeAndWait(prompter);
3326 } catch (Exception q)
3328 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3334 public void startDialogQueue()
3336 // set the flag so we don't pause waiting for another permit and semaphore
3337 // the current task to begin
3338 dialogPause = false;
3343 * Outputs an image of the desktop to file in EPS format, after prompting the
3344 * user for choice of Text or Lineart character rendering (unless a preference
3345 * has been set). The file name is generated as
3348 * Jalview_snapshot_nnnnn.eps where nnnnn is the current timestamp in milliseconds
3352 protected void snapShotWindow_actionPerformed(ActionEvent e)
3354 // currently the menu option to do this is not shown
3357 int width = getWidth();
3358 int height = getHeight();
3360 "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
3361 ImageWriterI writer = new ImageWriterI()
3364 public void exportImage(Graphics g) throws Exception
3367 Cache.log.info("Successfully written snapshot to file "
3368 + of.getAbsolutePath());
3371 String title = "View of desktop";
3372 ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
3374 exporter.doExport(of, this, width, height, title);
3378 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3379 * This respects (remembers) any previous 'exploded geometry' i.e. the size and
3380 * location last time the view was expanded (if any). However it does not
3381 * remember the split pane divider location - this is set to match the
3382 * 'exploding' frame.
3386 public void explodeViews(SplitFrame sf)
3388 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3389 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3390 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3392 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3394 int viewCount = topPanels.size();
3401 * Processing in reverse order works, forwards order leaves the first panels
3402 * not visible. I don't know why!
3404 for (int i = viewCount - 1; i >= 0; i--)
3407 * Make new top and bottom frames. These take over the respective
3408 * AlignmentPanel objects, including their AlignmentViewports, so the
3409 * cdna/protein relationships between the viewports is carried over to the
3412 * explodedGeometry holds the (x, y) position of the previously exploded
3413 * SplitFrame, and the (width, height) of the AlignFrame component
3415 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3416 AlignFrame newTopFrame = new AlignFrame(topPanel);
3417 newTopFrame.setSize(oldTopFrame.getSize());
3418 newTopFrame.setVisible(true);
3419 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3420 .getExplodedGeometry();
3421 if (geometry != null)
3423 newTopFrame.setSize(geometry.getSize());
3426 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3427 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3428 newBottomFrame.setSize(oldBottomFrame.getSize());
3429 newBottomFrame.setVisible(true);
3430 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3431 .getExplodedGeometry();
3432 if (geometry != null)
3434 newBottomFrame.setSize(geometry.getSize());
3437 topPanel.av.setGatherViewsHere(false);
3438 bottomPanel.av.setGatherViewsHere(false);
3439 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3441 if (geometry != null)
3443 splitFrame.setLocation(geometry.getLocation());
3445 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3449 * Clear references to the panels (now relocated in the new SplitFrames)
3450 * before closing the old SplitFrame.
3453 bottomPanels.clear();
3458 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3459 * back into the given SplitFrame as additional views. Note that the gathered
3460 * frames may themselves have multiple views.
3464 public void gatherViews(GSplitFrame source)
3467 * special handling of explodedGeometry for a view within a SplitFrame: - it
3468 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3469 * height) of the AlignFrame component
3471 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3472 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3473 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3474 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3475 myBottomFrame.viewport
3476 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3477 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3478 myTopFrame.viewport.setGatherViewsHere(true);
3479 myBottomFrame.viewport.setGatherViewsHere(true);
3480 String topViewId = myTopFrame.viewport.getSequenceSetId();
3481 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3483 JInternalFrame[] frames = desktopPane.getAllFrames();
3484 for (JInternalFrame frame : frames)
3486 if (frame instanceof SplitFrame && frame != source)
3488 SplitFrame sf = (SplitFrame) frame;
3489 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3490 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3491 boolean gatherThis = false;
3492 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3494 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3495 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3496 if (topViewId.equals(topPanel.av.getSequenceSetId())
3497 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3500 topPanel.av.setGatherViewsHere(false);
3501 bottomPanel.av.setGatherViewsHere(false);
3502 topPanel.av.setExplodedGeometry(
3503 new Rectangle(sf.getLocation(), topFrame.getSize()));
3504 bottomPanel.av.setExplodedGeometry(
3505 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3506 myTopFrame.addAlignmentPanel(topPanel, false);
3507 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3513 topFrame.getAlignPanels().clear();
3514 bottomFrame.getAlignPanels().clear();
3521 * The dust settles...give focus to the tab we did this from.
3523 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3526 public static groovy.ui.Console getGroovyConsole()
3528 Desktop desktop = Desktop.getInstance();
3529 return desktop == null ? null : desktop.groovyConsole;
3533 * handles the payload of a drag and drop event.
3535 * TODO refactor to desktop utilities class
3538 * - Data source strings extracted from the drop event
3540 * - protocol for each data source extracted from the drop event
3544 * - the payload from the drop event
3547 @SuppressWarnings("unchecked")
3548 public static void transferFromDropTarget(List<Object> files,
3549 List<DataSourceType> protocols, DropTargetDropEvent evt,
3550 Transferable t) throws Exception
3553 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3555 // DataFlavor[] flavors = t.getTransferDataFlavors();
3556 // for (int i = 0; i < flavors.length; i++) {
3557 // if (flavors[i].isFlavorJavaFileListType()) {
3558 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3559 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3560 // for (int j = 0; j < list.size(); j++) {
3561 // File file = (File) list.get(j);
3562 // byte[] data = getDroppedFileBytes(file);
3563 // fileName.setText(file.getName() + " - " + data.length + " " +
3564 // evt.getLocation());
3565 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3566 // target.setText(new String(data));
3568 // dtde.dropComplete(true);
3573 DataFlavor uriListFlavor = new DataFlavor(
3574 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3577 urlFlavour = new DataFlavor(
3578 "application/x-java-url; class=java.net.URL");
3579 } catch (ClassNotFoundException cfe)
3581 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3584 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3589 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3590 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3591 // means url may be null.
3594 protocols.add(DataSourceType.URL);
3595 files.add(url.toString());
3596 Cache.log.debug("Drop handled as URL dataflavor "
3597 + files.get(files.size() - 1));
3602 if (Platform.isAMacAndNotJS())
3605 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3608 } catch (Throwable ex)
3610 Cache.log.debug("URL drop handler failed.", ex);
3613 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3615 // Works on Windows and MacOSX
3616 Cache.log.debug("Drop handled as javaFileListFlavor");
3617 for (Object file : (List<Object>) t
3618 .getTransferData(DataFlavor.javaFileListFlavor))
3621 protocols.add(DataSourceType.FILE);
3626 // Unix like behaviour
3627 boolean added = false;
3629 if (t.isDataFlavorSupported(uriListFlavor))
3631 Cache.log.debug("Drop handled as uriListFlavor");
3632 // This is used by Unix drag system
3633 data = (String) t.getTransferData(uriListFlavor);
3637 // fallback to text: workaround - on OSX where there's a JVM bug
3638 Cache.log.debug("standard URIListFlavor failed. Trying text");
3639 // try text fallback
3640 DataFlavor textDf = new DataFlavor(
3641 "text/plain;class=java.lang.String");
3642 if (t.isDataFlavorSupported(textDf))
3644 data = (String) t.getTransferData(textDf);
3647 Cache.log.debug("Plain text drop content returned "
3648 + (data == null ? "Null - failed" : data));
3653 while (protocols.size() < files.size())
3655 Cache.log.debug("Adding missing FILE protocol for "
3656 + files.get(protocols.size()));
3657 protocols.add(DataSourceType.FILE);
3659 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3660 data, "\r\n"); st.hasMoreTokens();)
3663 String s = st.nextToken();
3664 if (s.startsWith("#"))
3666 // the line is a comment (as per the RFC 2483)
3669 java.net.URI uri = new java.net.URI(s);
3670 if (uri.getScheme().toLowerCase().startsWith("http"))
3672 protocols.add(DataSourceType.URL);
3673 files.add(uri.toString());
3677 // otherwise preserve old behaviour: catch all for file objects
3678 java.io.File file = new java.io.File(uri);
3679 protocols.add(DataSourceType.FILE);
3680 files.add(file.toString());
3685 if (Cache.log.isDebugEnabled())
3687 if (data == null || !added)
3690 if (t.getTransferDataFlavors() != null
3691 && t.getTransferDataFlavors().length > 0)
3694 "Couldn't resolve drop data. Here are the supported flavors:");
3695 for (DataFlavor fl : t.getTransferDataFlavors())
3698 "Supported transfer dataflavor: " + fl.toString());
3699 Object df = t.getTransferData(fl);
3702 Cache.log.debug("Retrieves: " + df);
3706 Cache.log.debug("Retrieved nothing");
3712 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3718 if (Platform.isWindowsAndNotJS())
3720 Cache.log.debug("Scanning dropped content for Windows Link Files");
3722 // resolve any .lnk files in the file drop
3723 for (int f = 0; f < files.size(); f++)
3725 String source = files.get(f).toString().toLowerCase();
3726 if (protocols.get(f).equals(DataSourceType.FILE)
3727 && (source.endsWith(".lnk") || source.endsWith(".url")
3728 || source.endsWith(".site")))
3732 Object obj = files.get(f);
3733 File lf = (obj instanceof File ? (File) obj
3734 : new File((String) obj));
3735 // process link file to get a URL
3736 Cache.log.debug("Found potential link file: " + lf);
3737 WindowsShortcut wscfile = new WindowsShortcut(lf);
3738 String fullname = wscfile.getRealFilename();
3739 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3740 files.set(f, fullname);
3741 Cache.log.debug("Parsed real filename " + fullname
3742 + " to extract protocol: " + protocols.get(f));
3743 } catch (Exception ex)
3746 "Couldn't parse " + files.get(f) + " as a link file.",
3755 * Sets the Preferences property for experimental features to True or False
3756 * depending on the state of the controlling menu item
3759 protected void showExperimental_actionPerformed(boolean selected)
3761 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3765 * Answers a (possibly empty) list of any structure viewer frames (currently for
3766 * either Jmol or Chimera) which are currently open. This may optionally be
3767 * restricted to viewers of a specified class, or viewers linked to a specified
3771 * if not null, only return viewers linked to this panel
3772 * @param structureViewerClass
3773 * if not null, only return viewers of this class
3776 public List<StructureViewerBase> getStructureViewers(
3777 AlignmentPanel apanel,
3778 Class<? extends StructureViewerBase> structureViewerClass)
3780 List<StructureViewerBase> result = new ArrayList<>();
3781 JInternalFrame[] frames = getAllFrames();
3783 for (JInternalFrame frame : frames)
3785 if (frame instanceof StructureViewerBase)
3787 if (structureViewerClass == null
3788 || structureViewerClass.isInstance(frame))
3791 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3793 result.add((StructureViewerBase) frame);