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.gui.ImageExporter.ImageWriterI;
30 import jalview.io.DataSourceType;
31 import jalview.io.FileFormat;
32 import jalview.io.FileFormatException;
33 import jalview.io.FileFormatI;
34 import jalview.io.FileFormats;
35 import jalview.io.FileLoader;
36 import jalview.io.FormatAdapter;
37 import jalview.io.IdentifyFile;
38 import jalview.io.JalviewFileChooser;
39 import jalview.io.JalviewFileView;
40 import jalview.jbgui.GSplitFrame;
41 import jalview.jbgui.GStructureViewer;
42 import jalview.structure.StructureSelectionManager;
43 import jalview.urls.IdOrgSettings;
44 import jalview.util.BrowserLauncher;
45 import jalview.util.ImageMaker.TYPE;
46 import jalview.util.MessageManager;
47 import jalview.util.Platform;
48 import jalview.util.UrlConstants;
49 import jalview.viewmodel.AlignmentViewport;
50 import jalview.ws.params.ParamManager;
51 import jalview.ws.utils.UrlDownloadClient;
53 import java.awt.BorderLayout;
54 import java.awt.Color;
55 import java.awt.Dimension;
56 import java.awt.FontMetrics;
57 import java.awt.Graphics;
58 import java.awt.GridLayout;
59 import java.awt.Point;
60 import java.awt.Rectangle;
61 import java.awt.Toolkit;
62 import java.awt.Window;
63 import java.awt.datatransfer.Clipboard;
64 import java.awt.datatransfer.ClipboardOwner;
65 import java.awt.datatransfer.DataFlavor;
66 import java.awt.datatransfer.Transferable;
67 import java.awt.dnd.DnDConstants;
68 import java.awt.dnd.DropTargetDragEvent;
69 import java.awt.dnd.DropTargetDropEvent;
70 import java.awt.dnd.DropTargetEvent;
71 import java.awt.dnd.DropTargetListener;
72 import java.awt.event.ActionEvent;
73 import java.awt.event.ActionListener;
74 import java.awt.event.InputEvent;
75 import java.awt.event.KeyEvent;
76 import java.awt.event.MouseAdapter;
77 import java.awt.event.MouseEvent;
78 import java.awt.event.WindowAdapter;
79 import java.awt.event.WindowEvent;
80 import java.beans.PropertyChangeEvent;
81 import java.beans.PropertyChangeListener;
82 import java.io.BufferedInputStream;
84 import java.io.FileOutputStream;
85 import java.io.IOException;
87 import java.util.ArrayList;
88 import java.util.Hashtable;
89 import java.util.List;
90 import java.util.ListIterator;
91 import java.util.Vector;
92 import java.util.concurrent.ExecutorService;
93 import java.util.concurrent.Executors;
94 import java.util.concurrent.Semaphore;
96 import javax.swing.AbstractAction;
97 import javax.swing.Action;
98 import javax.swing.ActionMap;
99 import javax.swing.Box;
100 import javax.swing.BoxLayout;
101 import javax.swing.DefaultDesktopManager;
102 import javax.swing.DesktopManager;
103 import javax.swing.InputMap;
104 import javax.swing.JButton;
105 import javax.swing.JCheckBox;
106 import javax.swing.JComboBox;
107 import javax.swing.JComponent;
108 import javax.swing.JDesktopPane;
109 import javax.swing.JFrame;
110 import javax.swing.JInternalFrame;
111 import javax.swing.JLabel;
112 import javax.swing.JMenuItem;
113 import javax.swing.JPanel;
114 import javax.swing.JPopupMenu;
115 import javax.swing.JProgressBar;
116 import javax.swing.JTextField;
117 import javax.swing.KeyStroke;
118 import javax.swing.SwingUtilities;
119 import javax.swing.event.HyperlinkEvent;
120 import javax.swing.event.HyperlinkEvent.EventType;
121 import javax.swing.event.InternalFrameAdapter;
122 import javax.swing.event.InternalFrameEvent;
123 import javax.swing.event.MenuEvent;
124 import javax.swing.event.MenuListener;
126 import org.stackoverflowusers.file.WindowsShortcut;
133 * @version $Revision: 1.155 $
135 public class Desktop extends jalview.jbgui.GDesktop
136 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
137 jalview.api.StructureSelectionManagerProvider
139 private static int DEFAULT_MIN_WIDTH = 300;
141 private static int DEFAULT_MIN_HEIGHT = 250;
143 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
145 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
147 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
149 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
152 * news reader - null if it was never started.
154 private BlogReader jvnews = null;
156 private File projectFile;
160 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
162 public void addJalviewPropertyChangeListener(
163 PropertyChangeListener listener)
165 changeSupport.addJalviewPropertyChangeListener(listener);
169 * @param propertyName
171 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
172 * java.beans.PropertyChangeListener)
174 public void addJalviewPropertyChangeListener(String propertyName,
175 PropertyChangeListener listener)
177 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
181 * @param propertyName
183 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
184 * java.beans.PropertyChangeListener)
186 public void removeJalviewPropertyChangeListener(String propertyName,
187 PropertyChangeListener listener)
189 changeSupport.removeJalviewPropertyChangeListener(propertyName,
193 /** Singleton Desktop instance */
194 public static Desktop instance;
196 public static MyDesktopPane desktop;
198 public static MyDesktopPane getDesktop()
200 // BH 2018 could use currentThread() here as a reference to a
201 // Hashtable<Thread, MyDesktopPane> in JavaScript
205 static int openFrameCount = 0;
207 static final int xOffset = 30;
209 static final int yOffset = 30;
211 public static jalview.ws.jws1.Discoverer discoverer;
213 public static Object[] jalviewClipboard;
215 public static boolean internalCopy = false;
217 static int fileLoadingCount = 0;
219 class MyDesktopManager implements DesktopManager
222 private DesktopManager delegate;
224 public MyDesktopManager(DesktopManager delegate)
226 this.delegate = delegate;
230 public void activateFrame(JInternalFrame f)
234 delegate.activateFrame(f);
235 } catch (NullPointerException npe)
237 Point p = getMousePosition();
238 instance.showPasteMenu(p.x, p.y);
243 public void beginDraggingFrame(JComponent f)
245 delegate.beginDraggingFrame(f);
249 public void beginResizingFrame(JComponent f, int direction)
251 delegate.beginResizingFrame(f, direction);
255 public void closeFrame(JInternalFrame f)
257 delegate.closeFrame(f);
261 public void deactivateFrame(JInternalFrame f)
263 delegate.deactivateFrame(f);
267 public void deiconifyFrame(JInternalFrame f)
269 delegate.deiconifyFrame(f);
273 public void dragFrame(JComponent f, int newX, int newY)
279 delegate.dragFrame(f, newX, newY);
283 public void endDraggingFrame(JComponent f)
285 delegate.endDraggingFrame(f);
290 public void endResizingFrame(JComponent f)
292 delegate.endResizingFrame(f);
297 public void iconifyFrame(JInternalFrame f)
299 delegate.iconifyFrame(f);
303 public void maximizeFrame(JInternalFrame f)
305 delegate.maximizeFrame(f);
309 public void minimizeFrame(JInternalFrame f)
311 delegate.minimizeFrame(f);
315 public void openFrame(JInternalFrame f)
317 delegate.openFrame(f);
321 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
328 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
332 public void setBoundsForFrame(JComponent f, int newX, int newY,
333 int newWidth, int newHeight)
335 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
338 // All other methods, simply delegate
343 * Creates a new Desktop object.
349 * A note to implementors. It is ESSENTIAL that any activities that might block
350 * are spawned off as threads rather than waited for during this constructor.
355 doVamsasClientCheck();
358 doConfigureStructurePrefs();
359 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
360 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
361 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
363 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
365 desktop = new MyDesktopPane(selmemusage);
368 showMemusage.setSelected(selmemusage);
369 desktop.setBackground(Color.white);
370 getContentPane().setLayout(new BorderLayout());
371 // alternate config - have scrollbars - see notes in JAL-153
372 // JScrollPane sp = new JScrollPane();
373 // sp.getViewport().setView(desktop);
374 // getContentPane().add(sp, BorderLayout.CENTER);
376 // BH 2018 - just an experiment to try unclipped JInternalFrames.
377 // Must set for all three to be active:
380 getRootPane().putClientProperty("swingjs.overflow.hidden", "false");
381 ((JComponent) getContentPane()).putClientProperty("swingjs.overflow.hidden", "false");
382 desktop.putClientProperty("swingjs.overflow.hidden", "false");
385 getContentPane().add(desktop, BorderLayout.CENTER);
386 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
388 // This line prevents Windows Look&Feel resizing all new windows to maximum
389 // if previous window was maximised
390 desktop.setDesktopManager(new MyDesktopManager(
391 (Platform.isWindows() ? new DefaultDesktopManager()
393 ? new AquaInternalFrameManager(
394 desktop.getDesktopManager())
395 : desktop.getDesktopManager())));
397 Rectangle dims = getLastKnownDimensions("");
404 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
405 int xPos = Math.max(5, (screenSize.width - 900) / 2);
406 int yPos = Math.max(5, (screenSize.height - 650) / 2);
407 setBounds(xPos, yPos, 900, 650);
410 boolean doFullLoad = /** @j2sNative ! */true;
414 jconsole = new Console(this, showjconsole);
415 // add essential build information
416 jconsole.setHeader("Jalview Version: "
417 + jalview.bin.Cache.getProperty("VERSION") + "\n"
418 + "Jalview Installation: "
419 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
420 + "\n" + "Build Date: "
421 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
422 + "Java version: " + System.getProperty("java.version") + "\n"
423 + System.getProperty("os.arch") + " "
424 + System.getProperty("os.name") + " "
425 + System.getProperty("os.version"));
427 showConsole(showjconsole);
429 showNews.setVisible(false);
431 experimentalFeatures.setSelected(showExperimental());
433 getIdentifiersOrgData();
437 // Spawn a thread that shows the splashscreen
439 SwingUtilities.invokeLater(new Runnable()
448 // Thread off a new instance of the file chooser - this reduces the time it
449 // takes to open it later on.
450 new Thread(new Runnable()
455 Cache.log.debug("Filechooser init thread started.");
456 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
457 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
459 Cache.log.debug("Filechooser init thread finished.");
462 // Add the service change listener
463 changeSupport.addJalviewPropertyChangeListener("services",
464 new PropertyChangeListener()
468 public void propertyChange(PropertyChangeEvent evt)
470 Cache.log.debug("Firing service changed event for "
471 + evt.getNewValue());
472 JalviewServicesChanged(evt);
479 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
481 this.addWindowListener(new WindowAdapter()
484 public void windowClosing(WindowEvent evt)
491 this.addMouseListener(ma = new MouseAdapter()
494 public void mousePressed(MouseEvent evt)
496 if (evt.isPopupTrigger()) // Mac
498 showPasteMenu(evt.getX(), evt.getY());
503 public void mouseReleased(MouseEvent evt)
505 if (evt.isPopupTrigger()) // Windows
507 showPasteMenu(evt.getX(), evt.getY());
511 desktop.addMouseListener(ma);
516 * Answers true if user preferences to enable experimental features is True
521 public boolean showExperimental()
523 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
524 Boolean.FALSE.toString());
525 return Boolean.valueOf(experimental).booleanValue();
528 public void doConfigureStructurePrefs()
530 // configure services
531 StructureSelectionManager ssm = StructureSelectionManager
532 .getStructureSelectionManager(this);
533 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
535 ssm.setAddTempFacAnnot(jalview.bin.Cache
536 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
537 ssm.setProcessSecondaryStructure(jalview.bin.Cache
538 .getDefault(Preferences.STRUCT_FROM_PDB, true));
539 ssm.setSecStructServices(
540 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
544 ssm.setAddTempFacAnnot(false);
545 ssm.setProcessSecondaryStructure(false);
546 ssm.setSecStructServices(false);
550 public void checkForNews()
552 final Desktop me = this;
553 // Thread off the news reader, in case there are connection problems.
554 new Thread(new Runnable()
559 Cache.log.debug("Starting news thread.");
560 jvnews = new BlogReader(me);
561 showNews.setVisible(true);
562 Cache.log.debug("Completed news thread.");
567 public void getIdentifiersOrgData()
569 // Thread off the identifiers fetcher
570 new Thread(new Runnable()
575 Cache.log.debug("Downloading data from identifiers.org");
576 UrlDownloadClient client = new UrlDownloadClient();
579 client.download(IdOrgSettings.getUrl(),
580 IdOrgSettings.getDownloadLocation());
581 } catch (IOException e)
583 Cache.log.debug("Exception downloading identifiers.org data"
592 protected void showNews_actionPerformed(ActionEvent e)
594 showNews(showNews.isSelected());
597 void showNews(boolean visible)
599 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
600 showNews.setSelected(visible);
601 if (visible && !jvnews.isVisible())
603 new Thread(new Runnable()
608 long now = System.currentTimeMillis();
609 Desktop.instance.setProgressBar(
610 MessageManager.getString("status.refreshing_news"), now);
611 jvnews.refreshNews();
612 Desktop.instance.setProgressBar(null, now);
620 * recover the last known dimensions for a jalview window
623 * - empty string is desktop, all other windows have unique prefix
624 * @return null or last known dimensions scaled to current geometry (if last
625 * window geom was known)
627 Rectangle getLastKnownDimensions(String windowName)
629 // TODO: lock aspect ratio for scaling desktop Bug #0058199
630 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
631 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
632 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
633 String width = jalview.bin.Cache
634 .getProperty(windowName + "SCREEN_WIDTH");
635 String height = jalview.bin.Cache
636 .getProperty(windowName + "SCREEN_HEIGHT");
637 if ((x != null) && (y != null) && (width != null) && (height != null))
639 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
640 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
641 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
643 // attempt #1 - try to cope with change in screen geometry - this
644 // version doesn't preserve original jv aspect ratio.
645 // take ratio of current screen size vs original screen size.
646 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
647 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
648 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
649 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
650 // rescale the bounds depending upon the current screen geometry.
651 ix = (int) (ix * sw);
652 iw = (int) (iw * sw);
653 iy = (int) (iy * sh);
654 ih = (int) (ih * sh);
655 while (ix >= screenSize.width)
657 jalview.bin.Cache.log.debug(
658 "Window geometry location recall error: shifting horizontal to within screenbounds.");
659 ix -= screenSize.width;
661 while (iy >= screenSize.height)
663 jalview.bin.Cache.log.debug(
664 "Window geometry location recall error: shifting vertical to within screenbounds.");
665 iy -= screenSize.height;
667 jalview.bin.Cache.log.debug(
668 "Got last known dimensions for " + windowName + ": x:" + ix
669 + " y:" + iy + " width:" + iw + " height:" + ih);
671 // return dimensions for new instance
672 return new Rectangle(ix, iy, iw, ih);
677 private void doVamsasClientCheck()
679 if (Cache.vamsasJarsPresent())
681 setupVamsasDisconnectedGui();
682 VamsasMenu.setVisible(true);
683 final Desktop us = this;
684 VamsasMenu.addMenuListener(new MenuListener()
686 // this listener remembers when the menu was first selected, and
687 // doesn't rebuild the session list until it has been cleared and
689 boolean refresh = true;
692 public void menuCanceled(MenuEvent e)
698 public void menuDeselected(MenuEvent e)
704 public void menuSelected(MenuEvent e)
708 us.buildVamsasStMenu();
713 vamsasStart.setVisible(true);
717 void showPasteMenu(int x, int y)
719 JPopupMenu popup = new JPopupMenu();
720 JMenuItem item = new JMenuItem(
721 MessageManager.getString("label.paste_new_window"));
722 item.addActionListener(new ActionListener()
725 public void actionPerformed(ActionEvent evt)
732 popup.show(this, x, y);
739 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
740 Transferable contents = c.getContents(this);
742 if (contents != null)
744 String file = (String) contents
745 .getTransferData(DataFlavor.stringFlavor);
747 FileFormatI format = new IdentifyFile().identify(file,
748 DataSourceType.PASTE);
750 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
753 } catch (Exception ex)
756 "Unable to paste alignment from system clipboard:\n" + ex);
761 * Adds and opens the given frame to the desktop
772 public static synchronized void addInternalFrame(
773 final JInternalFrame frame, String title, int w, int h)
775 addInternalFrame(frame, title, true, w, h, true, false);
779 * Add an internal frame to the Jalview desktop
786 * When true, display frame immediately, otherwise, caller must call
787 * setVisible themselves.
793 public static synchronized void addInternalFrame(
794 final JInternalFrame frame, String title, boolean makeVisible,
797 addInternalFrame(frame, title, makeVisible, w, h, true, false);
801 * Add an internal frame to the Jalview desktop and make it visible
814 public static synchronized void addInternalFrame(
815 final JInternalFrame frame, String title, int w, int h,
818 addInternalFrame(frame, title, true, w, h, resizable, false);
822 * Add an internal frame to the Jalview desktop
829 * When true, display frame immediately, otherwise, caller must call
830 * setVisible themselves.
837 * @param ignoreMinSize
838 * Do not set the default minimum size for frame
840 public static synchronized void addInternalFrame(
841 final JInternalFrame frame, String title, boolean makeVisible,
842 int w, int h, boolean resizable, boolean ignoreMinSize)
845 // TODO: allow callers to determine X and Y position of frame (eg. via
847 // TODO: consider fixing method to update entries in the window submenu with
848 // the current window title
850 frame.setTitle(title);
851 if (frame.getWidth() < 1 || frame.getHeight() < 1)
855 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
856 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
857 // IF JALVIEW IS RUNNING HEADLESS
858 // ///////////////////////////////////////////////
859 if (instance == null || (System.getProperty("java.awt.headless") != null
860 && System.getProperty("java.awt.headless").equals("true")))
869 frame.setMinimumSize(
870 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
872 // Set default dimension for Alignment Frame window.
873 // The Alignment Frame window could be added from a number of places,
875 // I did this here in order not to miss out on any Alignment frame.
876 if (frame instanceof AlignFrame)
878 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
879 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
883 frame.setVisible(makeVisible);
884 frame.setClosable(true);
885 frame.setResizable(resizable);
886 frame.setMaximizable(resizable);
887 frame.setIconifiable(resizable);
888 frame.setOpaque(/** @j2sNative true || */
891 if (frame.getX() < 1 && frame.getY() < 1)
893 frame.setLocation(xOffset * openFrameCount,
894 yOffset * ((openFrameCount - 1) % 10) + yOffset);
898 * add an entry for the new frame in the Window menu
899 * (and remove it when the frame is closed)
901 final JMenuItem menuItem = new JMenuItem(title);
902 frame.addInternalFrameListener(new InternalFrameAdapter()
905 public void internalFrameActivated(InternalFrameEvent evt)
907 JInternalFrame itf = desktop.getSelectedFrame();
910 if (itf instanceof AlignFrame)
912 Jalview.setCurrentAlignFrame((AlignFrame) itf);
919 public void internalFrameClosed(InternalFrameEvent evt)
921 PaintRefresher.RemoveComponent(frame);
924 * defensive check to prevent frames being
925 * added half off the window
927 if (openFrameCount > 0)
933 * ensure no reference to alignFrame retained by menu item listener
935 if (menuItem.getActionListeners().length > 0)
937 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
939 windowMenu.remove(menuItem);
943 menuItem.addActionListener(new ActionListener()
946 public void actionPerformed(ActionEvent e)
950 frame.setSelected(true);
951 frame.setIcon(false);
952 } catch (java.beans.PropertyVetoException ex)
954 // System.err.println(ex.toString());
959 setKeyBindings(frame);
963 windowMenu.add(menuItem);
968 frame.setSelected(true);
969 frame.requestFocus();
970 } catch (java.beans.PropertyVetoException ve)
972 } catch (java.lang.ClassCastException cex)
975 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
981 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
986 private static void setKeyBindings(JInternalFrame frame)
988 @SuppressWarnings("serial")
989 final Action closeAction = new AbstractAction()
992 public void actionPerformed(ActionEvent e)
999 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1001 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1002 InputEvent.CTRL_DOWN_MASK);
1003 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1004 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1006 InputMap inputMap = frame
1007 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1008 String ctrlW = ctrlWKey.toString();
1009 inputMap.put(ctrlWKey, ctrlW);
1010 inputMap.put(cmdWKey, ctrlW);
1012 ActionMap actionMap = frame.getActionMap();
1013 actionMap.put(ctrlW, closeAction);
1017 public void lostOwnership(Clipboard clipboard, Transferable contents)
1021 Desktop.jalviewClipboard = null;
1024 internalCopy = false;
1028 public void dragEnter(DropTargetDragEvent evt)
1033 public void dragExit(DropTargetEvent evt)
1038 public void dragOver(DropTargetDragEvent evt)
1043 public void dropActionChanged(DropTargetDragEvent evt)
1054 public void drop(DropTargetDropEvent evt)
1056 boolean success = true;
1057 // JAL-1552 - acceptDrop required before getTransferable call for
1058 // Java's Transferable for native dnd
1059 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1060 Transferable t = evt.getTransferable();
1061 List<Object> files = new ArrayList<>();
1062 List<DataSourceType> protocols = new ArrayList<>();
1066 Desktop.transferFromDropTarget(files, protocols, evt, t);
1067 } catch (Exception e)
1069 e.printStackTrace();
1077 for (int i = 0; i < files.size(); i++)
1079 // BH 2018 File or String
1080 Object file = files.get(i);
1081 String fileName = file.toString();
1082 DataSourceType protocol = (protocols == null)
1083 ? DataSourceType.FILE
1085 FileFormatI format = null;
1087 if (fileName.endsWith(".jar"))
1089 format = FileFormat.Jalview;
1094 format = new IdentifyFile().identify(file, protocol);
1097 new FileLoader().LoadFile(null, file, protocol, format);
1100 } catch (Exception ex)
1105 evt.dropComplete(success); // need this to ensure input focus is properly
1106 // transfered to any new windows created
1116 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1118 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1119 JalviewFileChooser chooser = JalviewFileChooser
1120 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1122 chooser.setFileView(new JalviewFileView());
1123 chooser.setDialogTitle(
1124 MessageManager.getString("label.open_local_file"));
1125 chooser.setToolTipText(MessageManager.getString("action.open"));
1127 chooser.setResponseHandler(0, new Runnable()
1132 File selectedFile = chooser.getSelectedFile();
1133 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1135 FileFormatI format = chooser.getSelectedFormat();
1138 * Call IdentifyFile to verify the file contains what its extension implies.
1139 * Skip this step for dynamically added file formats, because
1140 * IdentifyFile does not know how to recognise them.
1142 if (FileFormats.getInstance().isIdentifiable(format))
1146 format = new IdentifyFile().identify(selectedFile,
1147 DataSourceType.FILE);
1148 } catch (FileFormatException e)
1150 // format = null; //??
1154 new FileLoader().LoadFile(viewport, selectedFile,
1155 DataSourceType.FILE, format);
1158 chooser.showOpenDialog(this);
1162 * Shows a dialog for input of a URL at which to retrieve alignment data
1167 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1169 // This construct allows us to have a wider textfield
1171 JLabel label = new JLabel(
1172 MessageManager.getString("label.input_file_url"));
1174 JPanel panel = new JPanel(new GridLayout(2, 1));
1178 * the URL to fetch is
1179 * Java: an editable combobox with history
1180 * JS: (pending JAL-3038) a plain text field
1183 String urlBase = "http://www.";
1186 history = new JTextField(urlBase, 35);
1190 JComboBox<String> asCombo = new JComboBox<>();
1191 asCombo.setPreferredSize(new Dimension(400, 20));
1192 asCombo.setEditable(true);
1193 asCombo.addItem(urlBase);
1194 String historyItems = Cache.getProperty("RECENT_URL");
1195 if (historyItems != null)
1197 for (String token : historyItems.split("\\t"))
1199 asCombo.addItem(token);
1206 Object[] options = new Object[] { MessageManager.getString("action.ok"),
1207 MessageManager.getString("action.cancel") };
1208 Runnable action = new Runnable() {
1212 String url = Jalview.isJS() ? ((JTextField) history).getText()
1213 : ((JComboBox<String>) history).getSelectedItem()
1216 if (url.toLowerCase().endsWith(".jar"))
1218 if (viewport != null)
1220 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1221 FileFormat.Jalview);
1225 new FileLoader().LoadFile(url, DataSourceType.URL,
1226 FileFormat.Jalview);
1231 FileFormatI format = null;
1234 format = new IdentifyFile().identify(url, DataSourceType.URL);
1235 } catch (FileFormatException e)
1237 // TODO revise error handling, distinguish between
1238 // URL not found and response not valid
1243 String msg = MessageManager.formatMessage("label.couldnt_locate", url);
1244 JvOptionPane.showInternalMessageDialog(Desktop.desktop, msg,
1245 MessageManager.getString("label.url_not_found"),
1246 JvOptionPane.WARNING_MESSAGE);
1251 if (viewport != null)
1253 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1258 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1262 String dialogOption = MessageManager
1263 .getString("label.input_alignment_from_url");
1264 JvOptionPane.newOptionDialog(desktop).setResponseHandler(0, action)
1265 .showInternalDialog(panel, dialogOption,
1266 JvOptionPane.YES_NO_CANCEL_OPTION,
1267 JvOptionPane.PLAIN_MESSAGE, null, options,
1268 MessageManager.getString("action.ok"));
1272 * Opens the CutAndPaste window for the user to paste an alignment in to
1275 * - if not null, the pasted alignment is added to the current
1276 * alignment; if null, to a new alignment window
1279 public void inputTextboxMenuItem_actionPerformed(
1280 AlignmentViewPanel viewPanel)
1282 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1283 cap.setForInput(viewPanel);
1284 Desktop.addInternalFrame(cap,
1285 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1295 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1296 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1298 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1299 screen.height + "");
1300 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1301 getWidth(), getHeight()));
1303 if (jconsole != null)
1305 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1306 jconsole.stopConsole();
1310 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1313 if (dialogExecutor != null)
1315 dialogExecutor.shutdownNow();
1317 closeAll_actionPerformed(null);
1319 if (groovyConsole != null)
1321 // suppress a possible repeat prompt to save script
1322 groovyConsole.setDirty(false);
1323 groovyConsole.exit();
1328 private void storeLastKnownDimensions(String string, Rectangle jc)
1330 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1331 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1332 + " height:" + jc.height);
1334 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1335 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1336 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1337 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1347 public void aboutMenuItem_actionPerformed(ActionEvent e)
1349 // StringBuffer message = getAboutMessage(false);
1350 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1352 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1353 new Thread(new Runnable()
1358 new SplashScreen(true);
1363 public StringBuffer getAboutMessage(boolean shortv)
1365 StringBuffer message = new StringBuffer();
1366 message.append("<html>");
1369 message.append("<h1><strong>Version: "
1370 + jalview.bin.Cache.getProperty("VERSION")
1371 + "</strong></h1>");
1372 message.append("<strong>Last Updated: <em>"
1373 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1374 + "</em></strong>");
1380 message.append("<strong>Version "
1381 + jalview.bin.Cache.getProperty("VERSION")
1382 + "; last updated: "
1383 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1386 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1387 .equals("Checking"))
1389 message.append("<br>...Checking latest version...</br>");
1391 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1392 .equals(jalview.bin.Cache.getProperty("VERSION")))
1394 boolean red = false;
1395 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1396 .indexOf("automated build") == -1)
1399 // Displayed when code version and jnlp version do not match and code
1400 // version is not a development build
1401 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1404 message.append("<br>!! Version "
1405 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1407 + " is available for download from "
1408 + jalview.bin.Cache.getDefault("www.jalview.org",
1409 "http://www.jalview.org")
1413 message.append("</div>");
1416 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1418 "The Jalview Authors (See AUTHORS file for current list)")
1419 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1420 + "<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"
1421 + "<br><br>If you use Jalview, please cite:"
1422 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1423 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1424 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1430 * Action on requesting Help documentation
1433 public void documentationMenuItem_actionPerformed()
1439 BrowserLauncher.openURL("http://www.jalview.org/help.html");
1443 Help.showHelpWindow();
1445 } catch (Exception ex)
1447 System.err.println("Error opening help: " + ex.getMessage());
1452 public void closeAll_actionPerformed(ActionEvent e)
1454 // TODO show a progress bar while closing?
1455 JInternalFrame[] frames = desktop.getAllFrames();
1456 for (int i = 0; i < frames.length; i++)
1460 frames[i].setClosed(true);
1461 } catch (java.beans.PropertyVetoException ex)
1465 Jalview.setCurrentAlignFrame(null);
1466 System.out.println("ALL CLOSED");
1467 if (v_client != null)
1469 // TODO clear binding to vamsas document objects on close_all
1473 * reset state of singleton objects as appropriate (clear down session state
1474 * when all windows are closed)
1476 StructureSelectionManager ssm = StructureSelectionManager
1477 .getStructureSelectionManager(this);
1485 public void raiseRelated_actionPerformed(ActionEvent e)
1487 reorderAssociatedWindows(false, false);
1491 public void minimizeAssociated_actionPerformed(ActionEvent e)
1493 reorderAssociatedWindows(true, false);
1496 void closeAssociatedWindows()
1498 reorderAssociatedWindows(false, true);
1504 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1508 protected void garbageCollect_actionPerformed(ActionEvent e)
1510 // We simply collect the garbage
1511 jalview.bin.Cache.log.debug("Collecting garbage...");
1513 jalview.bin.Cache.log.debug("Finished garbage collection.");
1520 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1524 protected void showMemusage_actionPerformed(ActionEvent e)
1526 desktop.showMemoryUsage(showMemusage.isSelected());
1533 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1537 protected void showConsole_actionPerformed(ActionEvent e)
1539 showConsole(showConsole.isSelected());
1542 Console jconsole = null;
1545 * control whether the java console is visible or not
1549 void showConsole(boolean selected)
1551 // TODO: decide if we should update properties file
1552 if (jconsole != null) // BH 2018
1554 showConsole.setSelected(selected);
1555 Cache.setProperty("SHOW_JAVA_CONSOLE",
1556 Boolean.valueOf(selected).toString());
1557 jconsole.setVisible(selected);
1561 void reorderAssociatedWindows(boolean minimize, boolean close)
1563 JInternalFrame[] frames = desktop.getAllFrames();
1564 if (frames == null || frames.length < 1)
1569 AlignmentViewport source = null, target = null;
1570 if (frames[0] instanceof AlignFrame)
1572 source = ((AlignFrame) frames[0]).getCurrentView();
1574 else if (frames[0] instanceof TreePanel)
1576 source = ((TreePanel) frames[0]).getViewPort();
1578 else if (frames[0] instanceof PCAPanel)
1580 source = ((PCAPanel) frames[0]).av;
1582 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1584 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1589 for (int i = 0; i < frames.length; i++)
1592 if (frames[i] == null)
1596 if (frames[i] instanceof AlignFrame)
1598 target = ((AlignFrame) frames[i]).getCurrentView();
1600 else if (frames[i] instanceof TreePanel)
1602 target = ((TreePanel) frames[i]).getViewPort();
1604 else if (frames[i] instanceof PCAPanel)
1606 target = ((PCAPanel) frames[i]).av;
1608 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1610 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1613 if (source == target)
1619 frames[i].setClosed(true);
1623 frames[i].setIcon(minimize);
1626 frames[i].toFront();
1630 } catch (java.beans.PropertyVetoException ex)
1645 protected void preferences_actionPerformed(ActionEvent e)
1651 * Prompts the user to choose a file and then saves the Jalview state as a
1652 * Jalview project file
1655 public void saveState_actionPerformed(boolean asCastor)
1657 JalviewFileChooser chooser = new JalviewFileChooser(
1658 asCastor ? "jvp" : "jvx",
1661 chooser.setFileView(new JalviewFileView());
1662 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1663 int option = chooser.showSaveDialog(this);
1664 if (option == JalviewFileChooser.APPROVE_OPTION)
1666 File choice = chooser.getSelectedFile();
1667 setProjectFile(choice);
1669 new Thread(new Runnable()
1674 // TODO: refactor to Jalview desktop session controller action.
1675 setProgressBar(MessageManager.formatMessage(
1676 "label.saving_jalview_project", new Object[]
1677 { choice.getName() }), choice.hashCode());
1678 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1679 choice.getParent());
1680 // TODO catch and handle errors for savestate
1681 // TODO prevent user from messing with the Desktop whilst we're saving
1686 new Jalview2XML().saveState(choice);
1690 new jalview.project.Jalview2XML().saveState(choice);
1692 } catch (OutOfMemoryError oom)
1695 "Whilst saving current state to " + choice.getName(),
1697 } catch (Exception ex)
1700 "Problems whilst trying to save to " + choice.getName(),
1702 JvOptionPane.showMessageDialog(Desktop.this,
1703 MessageManager.formatMessage(
1704 "label.error_whilst_saving_current_state_to",
1706 { choice.getName() }),
1707 MessageManager.getString("label.couldnt_save_project"),
1708 JvOptionPane.WARNING_MESSAGE);
1710 setProgressBar(null, choice.hashCode());
1716 void setProjectFile(File choice)
1718 this.projectFile = choice;
1721 public File getProjectFile()
1723 return this.projectFile;
1727 * Prompts the user to choose a file and loads in as a Jalview project file
1730 public void loadState_actionPerformed(boolean asCastor)
1732 // TODO: GET RID OF .JVX BEFORE RELEASE JIM!
1733 final String[] suffix = asCastor ? new String[] { "jvp", "jar" }
1736 final String[] desc = asCastor
1738 { "Jalview Project", "Jalview Project (old)" }
1740 { "Jalview Project" };
1741 JalviewFileChooser chooser = new JalviewFileChooser(
1742 Cache.getProperty("LAST_DIRECTORY"), suffix,
1745 chooser.setFileView(new JalviewFileView());
1746 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1747 chooser.setResponseHandler(0, new Runnable()
1752 File selectedFile = chooser.getSelectedFile();
1753 setProjectFile(selectedFile);
1754 final String choice = selectedFile.getAbsolutePath();
1755 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1756 new Thread(new Runnable()
1764 new Jalview2XML().loadJalviewAlign(choice);
1768 new jalview.project.Jalview2XML().loadJalviewAlign(choice);
1770 } catch (OutOfMemoryError oom)
1772 new OOMWarning("Whilst loading project from " + choice, oom);
1773 } catch (Exception ex)
1776 "Problems whilst loading project from " + choice, ex);
1777 JvOptionPane.showMessageDialog(Desktop.desktop,
1778 MessageManager.formatMessage(
1779 "label.error_whilst_loading_project_from",
1782 MessageManager.getString("label.couldnt_load_project"),
1783 JvOptionPane.WARNING_MESSAGE);
1790 chooser.showOpenDialog(this);
1794 public void inputSequence_actionPerformed(ActionEvent e)
1796 new SequenceFetcher(this);
1799 JPanel progressPanel;
1801 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1803 public void startLoading(final Object fileName)
1805 if (fileLoadingCount == 0)
1807 fileLoadingPanels.add(addProgressPanel(MessageManager
1808 .formatMessage("label.loading_file", new Object[]
1814 private JPanel addProgressPanel(String string)
1816 if (progressPanel == null)
1818 progressPanel = new JPanel(new GridLayout(1, 1));
1819 totalProgressCount = 0;
1820 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1822 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1823 JProgressBar progressBar = new JProgressBar();
1824 progressBar.setIndeterminate(true);
1826 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1828 thisprogress.add(progressBar, BorderLayout.CENTER);
1829 progressPanel.add(thisprogress);
1830 ((GridLayout) progressPanel.getLayout()).setRows(
1831 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1832 ++totalProgressCount;
1833 instance.validate();
1834 return thisprogress;
1837 int totalProgressCount = 0;
1839 private void removeProgressPanel(JPanel progbar)
1841 if (progressPanel != null)
1843 synchronized (progressPanel)
1845 progressPanel.remove(progbar);
1846 GridLayout gl = (GridLayout) progressPanel.getLayout();
1847 gl.setRows(gl.getRows() - 1);
1848 if (--totalProgressCount < 1)
1850 this.getContentPane().remove(progressPanel);
1851 progressPanel = null;
1858 public void stopLoading()
1861 if (fileLoadingCount < 1)
1863 while (fileLoadingPanels.size() > 0)
1865 removeProgressPanel(fileLoadingPanels.remove(0));
1867 fileLoadingPanels.clear();
1868 fileLoadingCount = 0;
1873 public static int getViewCount(String alignmentId)
1875 AlignmentViewport[] aps = getViewports(alignmentId);
1876 return (aps == null) ? 0 : aps.length;
1881 * @param alignmentId
1882 * - if null, all sets are returned
1883 * @return all AlignmentPanels concerning the alignmentId sequence set
1885 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1887 if (Desktop.desktop == null)
1889 // no frames created and in headless mode
1890 // TODO: verify that frames are recoverable when in headless mode
1893 List<AlignmentPanel> aps = new ArrayList<>();
1894 AlignFrame[] frames = getAlignFrames();
1899 for (AlignFrame af : frames)
1901 for (AlignmentPanel ap : af.alignPanels)
1903 if (alignmentId == null
1904 || alignmentId.equals(ap.av.getSequenceSetId()))
1910 if (aps.size() == 0)
1914 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1919 * get all the viewports on an alignment.
1921 * @param sequenceSetId
1922 * unique alignment id (may be null - all viewports returned in that
1924 * @return all viewports on the alignment bound to sequenceSetId
1926 public static AlignmentViewport[] getViewports(String sequenceSetId)
1928 List<AlignmentViewport> viewp = new ArrayList<>();
1929 if (desktop != null)
1931 AlignFrame[] frames = Desktop.getAlignFrames();
1933 for (AlignFrame afr : frames)
1935 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1936 .equals(sequenceSetId))
1938 if (afr.alignPanels != null)
1940 for (AlignmentPanel ap : afr.alignPanels)
1942 if (sequenceSetId == null
1943 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1951 viewp.add(afr.getViewport());
1955 if (viewp.size() > 0)
1957 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1964 * Explode the views in the given frame into separate AlignFrame
1968 public static void explodeViews(AlignFrame af)
1970 int size = af.alignPanels.size();
1976 for (int i = 0; i < size; i++)
1978 AlignmentPanel ap = af.alignPanels.get(i);
1979 AlignFrame newaf = new AlignFrame(ap);
1982 * Restore the view's last exploded frame geometry if known. Multiple
1983 * views from one exploded frame share and restore the same (frame)
1984 * position and size.
1986 Rectangle geometry = ap.av.getExplodedGeometry();
1987 if (geometry != null)
1989 newaf.setBounds(geometry);
1992 ap.av.setGatherViewsHere(false);
1994 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1995 AlignFrame.DEFAULT_HEIGHT);
1998 af.alignPanels.clear();
1999 af.closeMenuItem_actionPerformed(true);
2004 * Gather expanded views (separate AlignFrame's) with the same sequence set
2005 * identifier back in to this frame as additional views, and close the expanded
2006 * views. Note the expanded frames may themselves have multiple views. We take
2011 public void gatherViews(AlignFrame source)
2013 source.viewport.setGatherViewsHere(true);
2014 source.viewport.setExplodedGeometry(source.getBounds());
2015 JInternalFrame[] frames = desktop.getAllFrames();
2016 String viewId = source.viewport.getSequenceSetId();
2018 for (int t = 0; t < frames.length; t++)
2020 if (frames[t] instanceof AlignFrame && frames[t] != source)
2022 AlignFrame af = (AlignFrame) frames[t];
2023 boolean gatherThis = false;
2024 for (int a = 0; a < af.alignPanels.size(); a++)
2026 AlignmentPanel ap = af.alignPanels.get(a);
2027 if (viewId.equals(ap.av.getSequenceSetId()))
2030 ap.av.setGatherViewsHere(false);
2031 ap.av.setExplodedGeometry(af.getBounds());
2032 source.addAlignmentPanel(ap, false);
2038 af.alignPanels.clear();
2039 af.closeMenuItem_actionPerformed(true);
2046 jalview.gui.VamsasApplication v_client = null;
2049 public void vamsasImport_actionPerformed(ActionEvent e)
2051 // TODO: JAL-3048 not needed for Jalview-JS
2053 if (v_client == null)
2055 // Load and try to start a session.
2056 JalviewFileChooser chooser = new JalviewFileChooser(
2057 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2059 chooser.setFileView(new JalviewFileView());
2060 chooser.setDialogTitle(
2061 MessageManager.getString("label.open_saved_vamsas_session"));
2062 chooser.setToolTipText(MessageManager.getString(
2063 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2065 int value = chooser.showOpenDialog(this);
2067 if (value == JalviewFileChooser.APPROVE_OPTION)
2069 String fle = chooser.getSelectedFile().toString();
2070 if (!vamsasImport(chooser.getSelectedFile()))
2072 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2073 MessageManager.formatMessage(
2074 "label.couldnt_import_as_vamsas_session",
2078 .getString("label.vamsas_document_import_failed"),
2079 JvOptionPane.ERROR_MESSAGE);
2085 jalview.bin.Cache.log.error(
2086 "Implementation error - load session from a running session is not supported.");
2091 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2094 * @return true if import was a success and a session was started.
2096 public boolean vamsasImport(URL url)
2098 // TODO: create progress bar
2099 if (v_client != null)
2102 jalview.bin.Cache.log.error(
2103 "Implementation error - load session from a running session is not supported.");
2109 // copy the URL content to a temporary local file
2110 // TODO: be a bit cleverer here with nio (?!)
2111 File file = File.createTempFile("vdocfromurl", ".vdj");
2112 FileOutputStream fos = new FileOutputStream(file);
2113 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2114 byte[] buffer = new byte[2048];
2116 while ((ln = bis.read(buffer)) > -1)
2118 fos.write(buffer, 0, ln);
2122 v_client = new jalview.gui.VamsasApplication(this, file,
2123 url.toExternalForm());
2124 } catch (Exception ex)
2126 jalview.bin.Cache.log.error(
2127 "Failed to create new vamsas session from contents of URL "
2132 setupVamsasConnectedGui();
2133 v_client.initial_update(); // TODO: thread ?
2134 return v_client.inSession();
2138 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2141 * @return true if import was a success and a session was started.
2143 public boolean vamsasImport(File file)
2145 if (v_client != null)
2148 jalview.bin.Cache.log.error(
2149 "Implementation error - load session from a running session is not supported.");
2153 setProgressBar(MessageManager.formatMessage(
2154 "status.importing_vamsas_session_from", new Object[]
2155 { file.getName() }), file.hashCode());
2158 v_client = new jalview.gui.VamsasApplication(this, file, null);
2159 } catch (Exception ex)
2161 setProgressBar(MessageManager.formatMessage(
2162 "status.importing_vamsas_session_from", new Object[]
2163 { file.getName() }), file.hashCode());
2164 jalview.bin.Cache.log.error(
2165 "New vamsas session from existing session file failed:", ex);
2168 setupVamsasConnectedGui();
2169 v_client.initial_update(); // TODO: thread ?
2170 setProgressBar(MessageManager.formatMessage(
2171 "status.importing_vamsas_session_from", new Object[]
2172 { file.getName() }), file.hashCode());
2173 return v_client.inSession();
2176 public boolean joinVamsasSession(String mysesid)
2178 if (v_client != null)
2180 throw new Error(MessageManager
2181 .getString("error.try_join_vamsas_session_another"));
2183 if (mysesid == null)
2186 MessageManager.getString("error.invalid_vamsas_session_id"));
2188 v_client = new VamsasApplication(this, mysesid);
2189 setupVamsasConnectedGui();
2190 v_client.initial_update();
2191 return (v_client.inSession());
2195 public void vamsasStart_actionPerformed(ActionEvent e)
2197 if (v_client == null)
2200 // we just start a default session for moment.
2202 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2203 * getProperty("LAST_DIRECTORY"));
2205 * chooser.setFileView(new JalviewFileView());
2206 * chooser.setDialogTitle("Load Vamsas file");
2207 * chooser.setToolTipText("Import");
2209 * int value = chooser.showOpenDialog(this);
2211 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2212 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2214 v_client = new VamsasApplication(this);
2215 setupVamsasConnectedGui();
2216 v_client.initial_update(); // TODO: thread ?
2220 // store current data in session.
2221 v_client.push_update(); // TODO: thread
2225 protected void setupVamsasConnectedGui()
2227 vamsasStart.setText(MessageManager.getString("label.session_update"));
2228 vamsasSave.setVisible(true);
2229 vamsasStop.setVisible(true);
2230 vamsasImport.setVisible(false); // Document import to existing session is
2231 // not possible for vamsas-client-1.0.
2234 protected void setupVamsasDisconnectedGui()
2236 vamsasSave.setVisible(false);
2237 vamsasStop.setVisible(false);
2238 vamsasImport.setVisible(true);
2240 .setText(MessageManager.getString("label.new_vamsas_session"));
2244 public void vamsasStop_actionPerformed(ActionEvent e)
2246 if (v_client != null)
2248 v_client.end_session();
2250 setupVamsasDisconnectedGui();
2254 protected void buildVamsasStMenu()
2256 if (v_client == null)
2258 String[] sess = null;
2261 sess = VamsasApplication.getSessionList();
2262 } catch (Exception e)
2264 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2270 jalview.bin.Cache.log.debug(
2271 "Got current sessions list: " + sess.length + " entries.");
2272 VamsasStMenu.removeAll();
2273 for (int i = 0; i < sess.length; i++)
2275 JMenuItem sessit = new JMenuItem();
2276 sessit.setText(sess[i]);
2277 sessit.setToolTipText(MessageManager
2278 .formatMessage("label.connect_to_session", new Object[]
2280 final Desktop dsktp = this;
2281 final String mysesid = sess[i];
2282 sessit.addActionListener(new ActionListener()
2286 public void actionPerformed(ActionEvent e)
2288 if (dsktp.v_client == null)
2290 Thread rthr = new Thread(new Runnable()
2296 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2297 dsktp.setupVamsasConnectedGui();
2298 dsktp.v_client.initial_update();
2306 VamsasStMenu.add(sessit);
2308 // don't show an empty menu.
2309 VamsasStMenu.setVisible(sess.length > 0);
2314 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2315 VamsasStMenu.removeAll();
2316 VamsasStMenu.setVisible(false);
2321 // Not interested in the content. Just hide ourselves.
2322 VamsasStMenu.setVisible(false);
2327 public void vamsasSave_actionPerformed(ActionEvent e)
2329 // TODO: JAL-3048 not needed for Jalview-JS
2331 if (v_client != null)
2333 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2334 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2337 chooser.setFileView(new JalviewFileView());
2338 chooser.setDialogTitle(MessageManager
2339 .getString("label.save_vamsas_document_archive"));
2341 int value = chooser.showSaveDialog(this);
2343 if (value == JalviewFileChooser.APPROVE_OPTION)
2345 java.io.File choice = chooser.getSelectedFile();
2346 JPanel progpanel = addProgressPanel(MessageManager
2347 .formatMessage("label.saving_vamsas_doc", new Object[]
2348 { choice.getName() }));
2349 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2350 String warnmsg = null;
2351 String warnttl = null;
2354 v_client.vclient.storeDocument(choice);
2357 warnttl = "Serious Problem saving Vamsas Document";
2358 warnmsg = ex.toString();
2359 jalview.bin.Cache.log
2360 .error("Error Whilst saving document to " + choice, ex);
2362 } catch (Exception ex)
2364 warnttl = "Problem saving Vamsas Document.";
2365 warnmsg = ex.toString();
2366 jalview.bin.Cache.log.warn(
2367 "Exception Whilst saving document to " + choice, ex);
2370 removeProgressPanel(progpanel);
2371 if (warnmsg != null)
2373 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2375 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2381 JPanel vamUpdate = null;
2384 * hide vamsas user gui bits when a vamsas document event is being handled.
2387 * true to hide gui, false to reveal gui
2389 public void setVamsasUpdate(boolean b)
2391 Cache.log.debug("Setting gui for Vamsas update "
2392 + (b ? "in progress" : "finished"));
2394 if (vamUpdate != null)
2396 this.removeProgressPanel(vamUpdate);
2400 vamUpdate = this.addProgressPanel(
2401 MessageManager.getString("label.updating_vamsas_session"));
2403 vamsasStart.setVisible(!b);
2404 vamsasStop.setVisible(!b);
2405 vamsasSave.setVisible(!b);
2408 public JInternalFrame[] getAllFrames()
2410 return desktop.getAllFrames();
2414 * Checks the given url to see if it gives a response indicating that the user
2415 * should be informed of a new questionnaire.
2419 public void checkForQuestionnaire(String url)
2421 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2422 // javax.swing.SwingUtilities.invokeLater(jvq);
2423 new Thread(jvq).start();
2426 public void checkURLLinks()
2428 // Thread off the URL link checker
2429 addDialogThread(new Runnable()
2434 if (Cache.getDefault("CHECKURLLINKS", true))
2436 // check what the actual links are - if it's just the default don't
2437 // bother with the warning
2438 List<String> links = Preferences.sequenceUrlLinks
2441 // only need to check links if there is one with a
2442 // SEQUENCE_ID which is not the default EMBL_EBI link
2443 ListIterator<String> li = links.listIterator();
2444 boolean check = false;
2445 List<JLabel> urls = new ArrayList<>();
2446 while (li.hasNext())
2448 String link = li.next();
2449 if (link.contains(SEQUENCE_ID)
2450 && !UrlConstants.isDefaultString(link))
2453 int barPos = link.indexOf("|");
2454 String urlMsg = barPos == -1 ? link
2455 : link.substring(0, barPos) + ": "
2456 + link.substring(barPos + 1);
2457 urls.add(new JLabel(urlMsg));
2465 // ask user to check in case URL links use old style tokens
2466 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2467 JPanel msgPanel = new JPanel();
2468 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2469 msgPanel.add(Box.createVerticalGlue());
2470 JLabel msg = new JLabel(MessageManager
2471 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2472 JLabel msg2 = new JLabel(MessageManager
2473 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2475 for (JLabel url : urls)
2481 final JCheckBox jcb = new JCheckBox(
2482 MessageManager.getString("label.do_not_display_again"));
2483 jcb.addActionListener(new ActionListener()
2486 public void actionPerformed(ActionEvent e)
2488 // update Cache settings for "don't show this again"
2489 boolean showWarningAgain = !jcb.isSelected();
2490 Cache.setProperty("CHECKURLLINKS",
2491 Boolean.valueOf(showWarningAgain).toString());
2496 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2498 .getString("label.SEQUENCE_ID_no_longer_used"),
2499 JvOptionPane.WARNING_MESSAGE);
2506 * Proxy class for JDesktopPane which optionally displays the current memory
2507 * usage and highlights the desktop area with a red bar if free memory runs low.
2511 public class MyDesktopPane extends JDesktopPane
2514 private static final float ONE_MB = 1048576f;
2516 boolean showMemoryUsage = false;
2520 java.text.NumberFormat df;
2522 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2525 public MyDesktopPane(boolean showMemoryUsage)
2527 showMemoryUsage(showMemoryUsage);
2530 public void showMemoryUsage(boolean showMemory)
2532 this.showMemoryUsage = showMemory;
2535 Thread worker = new Thread(this);
2541 public boolean isShowMemoryUsage()
2543 return showMemoryUsage;
2549 df = java.text.NumberFormat.getNumberInstance();
2550 df.setMaximumFractionDigits(2);
2551 runtime = Runtime.getRuntime();
2553 while (showMemoryUsage)
2557 maxMemory = runtime.maxMemory() / ONE_MB;
2558 allocatedMemory = runtime.totalMemory() / ONE_MB;
2559 freeMemory = runtime.freeMemory() / ONE_MB;
2560 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2562 percentUsage = (totalFreeMemory / maxMemory) * 100;
2564 // if (percentUsage < 20)
2566 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2568 // instance.set.setBorder(border1);
2571 // sleep after showing usage
2573 } catch (Exception ex)
2575 ex.printStackTrace();
2581 public void paintComponent(Graphics g)
2583 if (showMemoryUsage && g != null && df != null)
2585 if (percentUsage < 20)
2587 g.setColor(Color.red);
2589 FontMetrics fm = g.getFontMetrics();
2592 g.drawString(MessageManager.formatMessage("label.memory_stats",
2594 { df.format(totalFreeMemory), df.format(maxMemory),
2595 df.format(percentUsage) }),
2596 10, getHeight() - fm.getHeight());
2603 * Accessor method to quickly get all the AlignmentFrames loaded.
2605 * @return an array of AlignFrame, or null if none found
2607 public static AlignFrame[] getAlignFrames()
2609 if (Jalview.isHeadlessMode())
2611 // Desktop.desktop is null in headless mode
2612 return new AlignFrame[] { Jalview.currentAlignFrame };
2615 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2621 List<AlignFrame> avp = new ArrayList<>();
2623 for (int i = frames.length - 1; i > -1; i--)
2625 if (frames[i] instanceof AlignFrame)
2627 avp.add((AlignFrame) frames[i]);
2629 else if (frames[i] instanceof SplitFrame)
2632 * Also check for a split frame containing an AlignFrame
2634 GSplitFrame sf = (GSplitFrame) frames[i];
2635 if (sf.getTopFrame() instanceof AlignFrame)
2637 avp.add((AlignFrame) sf.getTopFrame());
2639 if (sf.getBottomFrame() instanceof AlignFrame)
2641 avp.add((AlignFrame) sf.getBottomFrame());
2645 if (avp.size() == 0)
2649 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2654 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2658 public GStructureViewer[] getJmols()
2660 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2666 List<GStructureViewer> avp = new ArrayList<>();
2668 for (int i = frames.length - 1; i > -1; i--)
2670 if (frames[i] instanceof AppJmol)
2672 GStructureViewer af = (GStructureViewer) frames[i];
2676 if (avp.size() == 0)
2680 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2685 * Add Groovy Support to Jalview
2688 public void groovyShell_actionPerformed()
2692 openGroovyConsole();
2693 } catch (Exception ex)
2695 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2696 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2698 MessageManager.getString("label.couldnt_create_groovy_shell"),
2699 MessageManager.getString("label.groovy_support_failed"),
2700 JvOptionPane.ERROR_MESSAGE);
2705 * Open the Groovy console
2707 void openGroovyConsole()
2709 if (groovyConsole == null)
2711 groovyConsole = new groovy.ui.Console();
2712 groovyConsole.setVariable("Jalview", this);
2713 groovyConsole.run();
2716 * We allow only one console at a time, so that AlignFrame menu option
2717 * 'Calculate | Run Groovy script' is unambiguous.
2718 * Disable 'Groovy Console', and enable 'Run script', when the console is
2719 * opened, and the reverse when it is closed
2721 Window window = (Window) groovyConsole.getFrame();
2722 window.addWindowListener(new WindowAdapter()
2725 public void windowClosed(WindowEvent e)
2728 * rebind CMD-Q from Groovy Console to Jalview Quit
2731 enableExecuteGroovy(false);
2737 * show Groovy console window (after close and reopen)
2739 ((Window) groovyConsole.getFrame()).setVisible(true);
2742 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2743 * and disable opening a second console
2745 enableExecuteGroovy(true);
2749 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
2752 protected void addQuitHandler()
2754 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2755 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2756 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2758 getRootPane().getActionMap().put("Quit", new AbstractAction()
2761 public void actionPerformed(ActionEvent e)
2769 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2772 * true if Groovy console is open
2774 public void enableExecuteGroovy(boolean enabled)
2777 * disable opening a second Groovy console
2778 * (or re-enable when the console is closed)
2780 groovyShell.setEnabled(!enabled);
2782 AlignFrame[] alignFrames = getAlignFrames();
2783 if (alignFrames != null)
2785 for (AlignFrame af : alignFrames)
2787 af.setGroovyEnabled(enabled);
2793 * Progress bars managed by the IProgressIndicator method.
2795 private Hashtable<Long, JPanel> progressBars;
2797 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2802 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2805 public void setProgressBar(String message, long id)
2807 if (progressBars == null)
2809 progressBars = new Hashtable<>();
2810 progressBarHandlers = new Hashtable<>();
2813 if (progressBars.get(new Long(id)) != null)
2815 JPanel panel = progressBars.remove(new Long(id));
2816 if (progressBarHandlers.contains(new Long(id)))
2818 progressBarHandlers.remove(new Long(id));
2820 removeProgressPanel(panel);
2824 progressBars.put(new Long(id), addProgressPanel(message));
2831 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2832 * jalview.gui.IProgressIndicatorHandler)
2835 public void registerHandler(final long id,
2836 final IProgressIndicatorHandler handler)
2838 if (progressBarHandlers == null
2839 || !progressBars.containsKey(new Long(id)))
2841 throw new Error(MessageManager.getString(
2842 "error.call_setprogressbar_before_registering_handler"));
2844 progressBarHandlers.put(new Long(id), handler);
2845 final JPanel progressPanel = progressBars.get(new Long(id));
2846 if (handler.canCancel())
2848 JButton cancel = new JButton(
2849 MessageManager.getString("action.cancel"));
2850 final IProgressIndicator us = this;
2851 cancel.addActionListener(new ActionListener()
2855 public void actionPerformed(ActionEvent e)
2857 handler.cancelActivity(id);
2858 us.setProgressBar(MessageManager
2859 .formatMessage("label.cancelled_params", new Object[]
2860 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2864 progressPanel.add(cancel, BorderLayout.EAST);
2870 * @return true if any progress bars are still active
2873 public boolean operationInProgress()
2875 if (progressBars != null && progressBars.size() > 0)
2883 * This will return the first AlignFrame holding the given viewport instance. It
2884 * will break if there are more than one AlignFrames viewing a particular av.
2887 * @return alignFrame for viewport
2889 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2891 if (desktop != null)
2893 AlignmentPanel[] aps = getAlignmentPanels(
2894 viewport.getSequenceSetId());
2895 for (int panel = 0; aps != null && panel < aps.length; panel++)
2897 if (aps[panel] != null && aps[panel].av == viewport)
2899 return aps[panel].alignFrame;
2906 public VamsasApplication getVamsasApplication()
2913 * flag set if jalview GUI is being operated programmatically
2915 private boolean inBatchMode = false;
2918 * check if jalview GUI is being operated programmatically
2920 * @return inBatchMode
2922 public boolean isInBatchMode()
2928 * set flag if jalview GUI is being operated programmatically
2930 * @param inBatchMode
2932 public void setInBatchMode(boolean inBatchMode)
2934 this.inBatchMode = inBatchMode;
2937 public void startServiceDiscovery()
2939 startServiceDiscovery(false);
2942 public void startServiceDiscovery(boolean blocking)
2944 boolean alive = true;
2945 Thread t0 = null, t1 = null, t2 = null;
2946 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2949 // todo: changesupport handlers need to be transferred
2950 if (discoverer == null)
2952 discoverer = new jalview.ws.jws1.Discoverer();
2953 // register PCS handler for desktop.
2954 discoverer.addPropertyChangeListener(changeSupport);
2956 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2957 // until we phase out completely
2958 (t0 = new Thread(discoverer)).start();
2961 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2963 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2964 .startDiscoverer(changeSupport);
2968 // TODO: do rest service discovery
2977 } catch (Exception e)
2980 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2981 || (t3 != null && t3.isAlive())
2982 || (t0 != null && t0.isAlive());
2988 * called to check if the service discovery process completed successfully.
2992 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2994 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2996 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2997 .getErrorMessages();
3000 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3002 if (serviceChangedDialog == null)
3004 // only run if we aren't already displaying one of these.
3005 addDialogThread(serviceChangedDialog = new Runnable()
3012 * JalviewDialog jd =new JalviewDialog() {
3014 * @Override protected void cancelPressed() { // TODO
3015 * Auto-generated method stub
3017 * }@Override protected void okPressed() { // TODO
3018 * Auto-generated method stub
3020 * }@Override protected void raiseClosed() { // TODO
3021 * Auto-generated method stub
3023 * } }; jd.initDialogFrame(new
3024 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3025 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3026 * + " or mis-configured HTTP proxy settings.<br/>" +
3027 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3029 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3030 * ), true, true, "Web Service Configuration Problem", 450,
3033 * jd.waitForInput();
3035 JvOptionPane.showConfirmDialog(Desktop.desktop,
3036 new JLabel("<html><table width=\"450\"><tr><td>"
3037 + ermsg + "</td></tr></table>"
3038 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3039 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3040 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3041 + " Tools->Preferences dialog box to change them.</p></html>"),
3042 "Web Service Configuration Problem",
3043 JvOptionPane.DEFAULT_OPTION,
3044 JvOptionPane.ERROR_MESSAGE);
3045 serviceChangedDialog = null;
3054 "Errors reported by JABA discovery service. Check web services preferences.\n"
3061 private Runnable serviceChangedDialog = null;
3064 * start a thread to open a URL in the configured browser. Pops up a warning
3065 * dialog to the user if there is an exception when calling out to the browser
3070 public static void showUrl(final String url)
3072 showUrl(url, Desktop.instance);
3076 * Like showUrl but allows progress handler to be specified
3080 * (null) or object implementing IProgressIndicator
3082 public static void showUrl(final String url,
3083 final IProgressIndicator progress)
3085 new Thread(new Runnable()
3092 if (progress != null)
3094 progress.setProgressBar(MessageManager
3095 .formatMessage("status.opening_params", new Object[]
3096 { url }), this.hashCode());
3098 jalview.util.BrowserLauncher.openURL(url);
3099 } catch (Exception ex)
3101 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3103 .getString("label.web_browser_not_found_unix"),
3104 MessageManager.getString("label.web_browser_not_found"),
3105 JvOptionPane.WARNING_MESSAGE);
3107 ex.printStackTrace();
3109 if (progress != null)
3111 progress.setProgressBar(null, this.hashCode());
3117 public static WsParamSetManager wsparamManager = null;
3119 public static ParamManager getUserParameterStore()
3121 if (wsparamManager == null)
3123 wsparamManager = new WsParamSetManager();
3125 return wsparamManager;
3129 * static hyperlink handler proxy method for use by Jalview's internal windows
3133 public static void hyperlinkUpdate(HyperlinkEvent e)
3135 if (e.getEventType() == EventType.ACTIVATED)
3140 url = e.getURL().toString();
3141 Desktop.showUrl(url);
3142 } catch (Exception x)
3146 if (Cache.log != null)
3148 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3153 "Couldn't handle string " + url + " as a URL.");
3156 // ignore any exceptions due to dud links.
3163 * single thread that handles display of dialogs to user.
3165 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3168 * flag indicating if dialogExecutor should try to acquire a permit
3170 private volatile boolean dialogPause = true;
3175 private java.util.concurrent.Semaphore block = new Semaphore(0);
3177 private static groovy.ui.Console groovyConsole;
3180 * add another dialog thread to the queue
3184 public void addDialogThread(final Runnable prompter)
3186 dialogExecutor.submit(new Runnable()
3196 } catch (InterruptedException x)
3201 if (instance == null)
3207 SwingUtilities.invokeAndWait(prompter);
3208 } catch (Exception q)
3210 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3216 public void startDialogQueue()
3218 // set the flag so we don't pause waiting for another permit and semaphore
3219 // the current task to begin
3220 dialogPause = false;
3225 * Outputs an image of the desktop to file in EPS format, after prompting the
3226 * user for choice of Text or Lineart character rendering (unless a preference
3227 * has been set). The file name is generated as
3230 * Jalview_snapshot_nnnnn.eps where nnnnn is the current timestamp in milliseconds
3234 protected void snapShotWindow_actionPerformed(ActionEvent e)
3236 // currently the menu option to do this is not shown
3239 int width = getWidth();
3240 int height = getHeight();
3242 "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
3243 ImageWriterI writer = new ImageWriterI()
3246 public void exportImage(Graphics g) throws Exception
3249 Cache.log.info("Successfully written snapshot to file "
3250 + of.getAbsolutePath());
3253 String title = "View of desktop";
3254 ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
3256 exporter.doExport(of, this, width, height, title);
3260 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3261 * This respects (remembers) any previous 'exploded geometry' i.e. the size and
3262 * location last time the view was expanded (if any). However it does not
3263 * remember the split pane divider location - this is set to match the
3264 * 'exploding' frame.
3268 public void explodeViews(SplitFrame sf)
3270 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3271 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3272 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3274 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3276 int viewCount = topPanels.size();
3283 * Processing in reverse order works, forwards order leaves the first panels
3284 * not visible. I don't know why!
3286 for (int i = viewCount - 1; i >= 0; i--)
3289 * Make new top and bottom frames. These take over the respective
3290 * AlignmentPanel objects, including their AlignmentViewports, so the
3291 * cdna/protein relationships between the viewports is carried over to the
3294 * explodedGeometry holds the (x, y) position of the previously exploded
3295 * SplitFrame, and the (width, height) of the AlignFrame component
3297 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3298 AlignFrame newTopFrame = new AlignFrame(topPanel);
3299 newTopFrame.setSize(oldTopFrame.getSize());
3300 newTopFrame.setVisible(true);
3301 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3302 .getExplodedGeometry();
3303 if (geometry != null)
3305 newTopFrame.setSize(geometry.getSize());
3308 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3309 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3310 newBottomFrame.setSize(oldBottomFrame.getSize());
3311 newBottomFrame.setVisible(true);
3312 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3313 .getExplodedGeometry();
3314 if (geometry != null)
3316 newBottomFrame.setSize(geometry.getSize());
3319 topPanel.av.setGatherViewsHere(false);
3320 bottomPanel.av.setGatherViewsHere(false);
3321 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3323 if (geometry != null)
3325 splitFrame.setLocation(geometry.getLocation());
3327 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3331 * Clear references to the panels (now relocated in the new SplitFrames)
3332 * before closing the old SplitFrame.
3335 bottomPanels.clear();
3340 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3341 * back into the given SplitFrame as additional views. Note that the gathered
3342 * frames may themselves have multiple views.
3346 public void gatherViews(GSplitFrame source)
3349 * special handling of explodedGeometry for a view within a SplitFrame: - it
3350 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3351 * height) of the AlignFrame component
3353 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3354 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3355 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3356 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3357 myBottomFrame.viewport
3358 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3359 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3360 myTopFrame.viewport.setGatherViewsHere(true);
3361 myBottomFrame.viewport.setGatherViewsHere(true);
3362 String topViewId = myTopFrame.viewport.getSequenceSetId();
3363 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3365 JInternalFrame[] frames = desktop.getAllFrames();
3366 for (JInternalFrame frame : frames)
3368 if (frame instanceof SplitFrame && frame != source)
3370 SplitFrame sf = (SplitFrame) frame;
3371 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3372 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3373 boolean gatherThis = false;
3374 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3376 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3377 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3378 if (topViewId.equals(topPanel.av.getSequenceSetId())
3379 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3382 topPanel.av.setGatherViewsHere(false);
3383 bottomPanel.av.setGatherViewsHere(false);
3384 topPanel.av.setExplodedGeometry(
3385 new Rectangle(sf.getLocation(), topFrame.getSize()));
3386 bottomPanel.av.setExplodedGeometry(
3387 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3388 myTopFrame.addAlignmentPanel(topPanel, false);
3389 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3395 topFrame.getAlignPanels().clear();
3396 bottomFrame.getAlignPanels().clear();
3403 * The dust settles...give focus to the tab we did this from.
3405 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3408 public static groovy.ui.Console getGroovyConsole()
3410 return groovyConsole;
3414 * handles the payload of a drag and drop event.
3416 * TODO refactor to desktop utilities class
3419 * - Data source strings extracted from the drop event
3421 * - protocol for each data source extracted from the drop event
3425 * - the payload from the drop event
3428 public static void transferFromDropTarget(List<Object> files,
3429 List<DataSourceType> protocols, DropTargetDropEvent evt,
3430 Transferable t) throws Exception
3433 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3435 // DataFlavor[] flavors = t.getTransferDataFlavors();
3436 // for (int i = 0; i < flavors.length; i++) {
3437 // if (flavors[i].isFlavorJavaFileListType()) {
3438 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3439 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3440 // for (int j = 0; j < list.size(); j++) {
3441 // File file = (File) list.get(j);
3442 // byte[] data = getDroppedFileBytes(file);
3443 // fileName.setText(file.getName() + " - " + data.length + " " +
3444 // evt.getLocation());
3445 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3446 // target.setText(new String(data));
3448 // dtde.dropComplete(true);
3453 DataFlavor uriListFlavor = new DataFlavor(
3454 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3457 urlFlavour = new DataFlavor(
3458 "application/x-java-url; class=java.net.URL");
3459 } catch (ClassNotFoundException cfe)
3461 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3464 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3469 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3470 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3471 // means url may be null.
3474 protocols.add(DataSourceType.URL);
3475 files.add(url.toString());
3476 Cache.log.debug("Drop handled as URL dataflavor "
3477 + files.get(files.size() - 1));
3482 if (Platform.isAMac())
3485 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3489 } catch (Throwable ex)
3491 Cache.log.debug("URL drop handler failed.", ex);
3494 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3496 // Works on Windows and MacOSX
3497 Cache.log.debug("Drop handled as javaFileListFlavor");
3498 for (Object file : (List) t
3499 .getTransferData(DataFlavor.javaFileListFlavor))
3502 protocols.add(DataSourceType.FILE);
3507 // Unix like behaviour
3508 boolean added = false;
3510 if (t.isDataFlavorSupported(uriListFlavor))
3512 Cache.log.debug("Drop handled as uriListFlavor");
3513 // This is used by Unix drag system
3514 data = (String) t.getTransferData(uriListFlavor);
3518 // fallback to text: workaround - on OSX where there's a JVM bug
3519 Cache.log.debug("standard URIListFlavor failed. Trying text");
3520 // try text fallback
3521 DataFlavor textDf = new DataFlavor(
3522 "text/plain;class=java.lang.String");
3523 if (t.isDataFlavorSupported(textDf))
3525 data = (String) t.getTransferData(textDf);
3528 Cache.log.debug("Plain text drop content returned "
3529 + (data == null ? "Null - failed" : data));
3534 while (protocols.size() < files.size())
3536 Cache.log.debug("Adding missing FILE protocol for "
3537 + files.get(protocols.size()));
3538 protocols.add(DataSourceType.FILE);
3540 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3541 data, "\r\n"); st.hasMoreTokens();)
3544 String s = st.nextToken();
3545 if (s.startsWith("#"))
3547 // the line is a comment (as per the RFC 2483)
3550 java.net.URI uri = new java.net.URI(s);
3551 if (uri.getScheme().toLowerCase().startsWith("http"))
3553 protocols.add(DataSourceType.URL);
3554 files.add(uri.toString());
3558 // otherwise preserve old behaviour: catch all for file objects
3559 java.io.File file = new java.io.File(uri);
3560 protocols.add(DataSourceType.FILE);
3561 files.add(file.toString());
3566 if (Cache.log.isDebugEnabled())
3568 if (data == null || !added)
3571 if (t.getTransferDataFlavors() != null
3572 && t.getTransferDataFlavors().length > 0)
3575 "Couldn't resolve drop data. Here are the supported flavors:");
3576 for (DataFlavor fl : t.getTransferDataFlavors())
3579 "Supported transfer dataflavor: " + fl.toString());
3580 Object df = t.getTransferData(fl);
3583 Cache.log.debug("Retrieves: " + df);
3587 Cache.log.debug("Retrieved nothing");
3593 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3599 if (Platform.isWindows())
3602 Cache.log.debug("Scanning dropped content for Windows Link Files");
3604 // resolve any .lnk files in the file drop
3605 for (int f = 0; f < files.size(); f++)
3607 String source = files.get(f).toString().toLowerCase();
3608 if (protocols.get(f).equals(DataSourceType.FILE)
3609 && (source.endsWith(".lnk") || source.endsWith(".url")
3610 || source.endsWith(".site")))
3614 Object obj = files.get(f);
3615 File lf = (obj instanceof File ? (File) obj
3616 : new File((String) obj));
3617 // process link file to get a URL
3618 Cache.log.debug("Found potential link file: " + lf);
3619 WindowsShortcut wscfile = new WindowsShortcut(lf);
3620 String fullname = wscfile.getRealFilename();
3621 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3622 files.set(f, fullname);
3623 Cache.log.debug("Parsed real filename " + fullname
3624 + " to extract protocol: " + protocols.get(f));
3625 } catch (Exception ex)
3628 "Couldn't parse " + files.get(f) + " as a link file.",
3637 * Sets the Preferences property for experimental features to True or False
3638 * depending on the state of the controlling menu item
3641 protected void showExperimental_actionPerformed(boolean selected)
3643 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3647 * Answers a (possibly empty) list of any structure viewer frames (currently for
3648 * either Jmol or Chimera) which are currently open. This may optionally be
3649 * restricted to viewers of a specified class, or viewers linked to a specified
3653 * if not null, only return viewers linked to this panel
3654 * @param structureViewerClass
3655 * if not null, only return viewers of this class
3658 public List<StructureViewerBase> getStructureViewers(
3659 AlignmentPanel apanel,
3660 Class<? extends StructureViewerBase> structureViewerClass)
3662 List<StructureViewerBase> result = new ArrayList<>();
3663 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3665 for (JInternalFrame frame : frames)
3667 if (frame instanceof StructureViewerBase)
3669 if (structureViewerClass == null
3670 || structureViewerClass.isInstance(frame))
3673 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3675 result.add((StructureViewerBase) frame);