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.
348 * A note to implementors. It is ESSENTIAL that any activities that might block
349 * are spawned off as threads rather than waited for during this constructor.
354 doVamsasClientCheck();
357 doConfigureStructurePrefs();
358 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
359 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
360 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
362 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
364 desktop = new MyDesktopPane(selmemusage);
367 showMemusage.setSelected(selmemusage);
368 desktop.setBackground(Color.white);
369 getContentPane().setLayout(new BorderLayout());
370 // alternate config - have scrollbars - see notes in JAL-153
371 // JScrollPane sp = new JScrollPane();
372 // sp.getViewport().setView(desktop);
373 // getContentPane().add(sp, BorderLayout.CENTER);
375 // BH 2018 - just an experiment to try unclipped JInternalFrames.
376 // Must set for all three to be active:
379 getRootPane().putClientProperty("swingjs.overflow.hidden", "false");
380 ((JComponent) getContentPane()).putClientProperty("swingjs.overflow.hidden", "false");
381 desktop.putClientProperty("swingjs.overflow.hidden", "false");
384 getContentPane().add(desktop, BorderLayout.CENTER);
385 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
387 // This line prevents Windows Look&Feel resizing all new windows to maximum
388 // if previous window was maximised
389 desktop.setDesktopManager(new MyDesktopManager(
390 (Platform.isWindows() ? new DefaultDesktopManager()
392 ? new AquaInternalFrameManager(
393 desktop.getDesktopManager())
394 : desktop.getDesktopManager())));
396 Rectangle dims = getLastKnownDimensions("");
403 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
404 int xPos = Math.max(5, (screenSize.width - 900) / 2);
405 int yPos = Math.max(5, (screenSize.height - 650) / 2);
406 setBounds(xPos, yPos, 900, 650);
409 boolean doFullLoad = /** @j2sNative ! */true;
413 jconsole = new Console(this, showjconsole);
414 // add essential build information
415 jconsole.setHeader("Jalview Version: "
416 + jalview.bin.Cache.getProperty("VERSION") + "\n"
417 + "Jalview Installation: "
418 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
419 + "\n" + "Build Date: "
420 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
421 + "Java version: " + System.getProperty("java.version") + "\n"
422 + System.getProperty("os.arch") + " "
423 + System.getProperty("os.name") + " "
424 + System.getProperty("os.version"));
426 showConsole(showjconsole);
428 showNews.setVisible(false);
430 experimentalFeatures.setSelected(showExperimental());
432 getIdentifiersOrgData();
436 // Spawn a thread that shows the splashscreen
438 SwingUtilities.invokeLater(new Runnable()
447 // Thread off a new instance of the file chooser - this reduces the time it
448 // takes to open it later on.
449 new Thread(new Runnable()
454 Cache.log.debug("Filechooser init thread started.");
455 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
456 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
458 Cache.log.debug("Filechooser init thread finished.");
461 // Add the service change listener
462 changeSupport.addJalviewPropertyChangeListener("services",
463 new PropertyChangeListener()
467 public void propertyChange(PropertyChangeEvent evt)
469 Cache.log.debug("Firing service changed event for "
470 + evt.getNewValue());
471 JalviewServicesChanged(evt);
478 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
480 this.addWindowListener(new WindowAdapter()
483 public void windowClosing(WindowEvent evt)
490 this.addMouseListener(ma = new MouseAdapter()
493 public void mousePressed(MouseEvent evt)
495 if (evt.isPopupTrigger()) // Mac
497 showPasteMenu(evt.getX(), evt.getY());
502 public void mouseReleased(MouseEvent evt)
504 if (evt.isPopupTrigger()) // Windows
506 showPasteMenu(evt.getX(), evt.getY());
510 desktop.addMouseListener(ma);
515 * Answers true if user preferences to enable experimental features is True
520 public boolean showExperimental()
522 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
523 Boolean.FALSE.toString());
524 return Boolean.valueOf(experimental).booleanValue();
527 public void doConfigureStructurePrefs()
529 // configure services
530 StructureSelectionManager ssm = StructureSelectionManager
531 .getStructureSelectionManager(this);
532 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
534 ssm.setAddTempFacAnnot(jalview.bin.Cache
535 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
536 ssm.setProcessSecondaryStructure(jalview.bin.Cache
537 .getDefault(Preferences.STRUCT_FROM_PDB, true));
538 ssm.setSecStructServices(
539 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
543 ssm.setAddTempFacAnnot(false);
544 ssm.setProcessSecondaryStructure(false);
545 ssm.setSecStructServices(false);
549 public void checkForNews()
551 final Desktop me = this;
552 // Thread off the news reader, in case there are connection problems.
553 new Thread(new Runnable()
558 Cache.log.debug("Starting news thread.");
559 jvnews = new BlogReader(me);
560 showNews.setVisible(true);
561 Cache.log.debug("Completed news thread.");
566 public void getIdentifiersOrgData()
568 // Thread off the identifiers fetcher
569 new Thread(new Runnable()
574 Cache.log.debug("Downloading data from identifiers.org");
575 UrlDownloadClient client = new UrlDownloadClient();
578 client.download(IdOrgSettings.getUrl(),
579 IdOrgSettings.getDownloadLocation());
580 } catch (IOException e)
582 Cache.log.debug("Exception downloading identifiers.org data"
591 protected void showNews_actionPerformed(ActionEvent e)
593 showNews(showNews.isSelected());
596 void showNews(boolean visible)
598 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
599 showNews.setSelected(visible);
600 if (visible && !jvnews.isVisible())
602 new Thread(new Runnable()
607 long now = System.currentTimeMillis();
608 Desktop.instance.setProgressBar(
609 MessageManager.getString("status.refreshing_news"), now);
610 jvnews.refreshNews();
611 Desktop.instance.setProgressBar(null, now);
619 * recover the last known dimensions for a jalview window
622 * - empty string is desktop, all other windows have unique prefix
623 * @return null or last known dimensions scaled to current geometry (if last
624 * window geom was known)
626 Rectangle getLastKnownDimensions(String windowName)
628 // TODO: lock aspect ratio for scaling desktop Bug #0058199
629 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
630 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
631 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
632 String width = jalview.bin.Cache
633 .getProperty(windowName + "SCREEN_WIDTH");
634 String height = jalview.bin.Cache
635 .getProperty(windowName + "SCREEN_HEIGHT");
636 if ((x != null) && (y != null) && (width != null) && (height != null))
638 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
639 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
640 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
642 // attempt #1 - try to cope with change in screen geometry - this
643 // version doesn't preserve original jv aspect ratio.
644 // take ratio of current screen size vs original screen size.
645 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
646 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
647 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
648 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
649 // rescale the bounds depending upon the current screen geometry.
650 ix = (int) (ix * sw);
651 iw = (int) (iw * sw);
652 iy = (int) (iy * sh);
653 ih = (int) (ih * sh);
654 while (ix >= screenSize.width)
656 jalview.bin.Cache.log.debug(
657 "Window geometry location recall error: shifting horizontal to within screenbounds.");
658 ix -= screenSize.width;
660 while (iy >= screenSize.height)
662 jalview.bin.Cache.log.debug(
663 "Window geometry location recall error: shifting vertical to within screenbounds.");
664 iy -= screenSize.height;
666 jalview.bin.Cache.log.debug(
667 "Got last known dimensions for " + windowName + ": x:" + ix
668 + " y:" + iy + " width:" + iw + " height:" + ih);
670 // return dimensions for new instance
671 return new Rectangle(ix, iy, iw, ih);
676 private void doVamsasClientCheck()
678 if (Cache.vamsasJarsPresent())
680 setupVamsasDisconnectedGui();
681 VamsasMenu.setVisible(true);
682 final Desktop us = this;
683 VamsasMenu.addMenuListener(new MenuListener()
685 // this listener remembers when the menu was first selected, and
686 // doesn't rebuild the session list until it has been cleared and
688 boolean refresh = true;
691 public void menuCanceled(MenuEvent e)
697 public void menuDeselected(MenuEvent e)
703 public void menuSelected(MenuEvent e)
707 us.buildVamsasStMenu();
712 vamsasStart.setVisible(true);
716 void showPasteMenu(int x, int y)
718 JPopupMenu popup = new JPopupMenu();
719 JMenuItem item = new JMenuItem(
720 MessageManager.getString("label.paste_new_window"));
721 item.addActionListener(new ActionListener()
724 public void actionPerformed(ActionEvent evt)
731 popup.show(this, x, y);
738 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
739 Transferable contents = c.getContents(this);
741 if (contents != null)
743 String file = (String) contents
744 .getTransferData(DataFlavor.stringFlavor);
746 FileFormatI format = new IdentifyFile().identify(file,
747 DataSourceType.PASTE);
749 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
752 } catch (Exception ex)
755 "Unable to paste alignment from system clipboard:\n" + ex);
760 * Adds and opens the given frame to the desktop
771 public static synchronized void addInternalFrame(
772 final JInternalFrame frame, String title, int w, int h)
774 addInternalFrame(frame, title, true, w, h, true, false);
778 * Add an internal frame to the Jalview desktop
785 * When true, display frame immediately, otherwise, caller must call
786 * setVisible themselves.
792 public static synchronized void addInternalFrame(
793 final JInternalFrame frame, String title, boolean makeVisible,
796 addInternalFrame(frame, title, makeVisible, w, h, true, false);
800 * Add an internal frame to the Jalview desktop and make it visible
813 public static synchronized void addInternalFrame(
814 final JInternalFrame frame, String title, int w, int h,
817 addInternalFrame(frame, title, true, w, h, resizable, false);
821 * Add an internal frame to the Jalview desktop
828 * When true, display frame immediately, otherwise, caller must call
829 * setVisible themselves.
836 * @param ignoreMinSize
837 * Do not set the default minimum size for frame
839 public static synchronized void addInternalFrame(
840 final JInternalFrame frame, String title, boolean makeVisible,
841 int w, int h, boolean resizable, boolean ignoreMinSize)
844 // TODO: allow callers to determine X and Y position of frame (eg. via
846 // TODO: consider fixing method to update entries in the window submenu with
847 // the current window title
849 frame.setTitle(title);
850 if (frame.getWidth() < 1 || frame.getHeight() < 1)
854 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
855 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
856 // IF JALVIEW IS RUNNING HEADLESS
857 // ///////////////////////////////////////////////
858 if (instance == null || (System.getProperty("java.awt.headless") != null
859 && System.getProperty("java.awt.headless").equals("true")))
868 frame.setMinimumSize(
869 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
871 // Set default dimension for Alignment Frame window.
872 // The Alignment Frame window could be added from a number of places,
874 // I did this here in order not to miss out on any Alignment frame.
875 if (frame instanceof AlignFrame)
877 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
878 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
882 frame.setVisible(makeVisible);
883 frame.setClosable(true);
884 frame.setResizable(resizable);
885 frame.setMaximizable(resizable);
886 frame.setIconifiable(resizable);
887 frame.setOpaque(/** @j2sNative true || */
890 if (frame.getX() < 1 && frame.getY() < 1)
892 frame.setLocation(xOffset * openFrameCount,
893 yOffset * ((openFrameCount - 1) % 10) + yOffset);
897 * add an entry for the new frame in the Window menu
898 * (and remove it when the frame is closed)
900 final JMenuItem menuItem = new JMenuItem(title);
901 frame.addInternalFrameListener(new InternalFrameAdapter()
904 public void internalFrameActivated(InternalFrameEvent evt)
906 JInternalFrame itf = desktop.getSelectedFrame();
909 if (itf instanceof AlignFrame)
911 Jalview.setCurrentAlignFrame((AlignFrame) itf);
918 public void internalFrameClosed(InternalFrameEvent evt)
920 PaintRefresher.RemoveComponent(frame);
923 * defensive check to prevent frames being
924 * added half off the window
926 if (openFrameCount > 0)
932 * ensure no reference to alignFrame retained by menu item listener
934 if (menuItem.getActionListeners().length > 0)
936 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
938 windowMenu.remove(menuItem);
942 menuItem.addActionListener(new ActionListener()
945 public void actionPerformed(ActionEvent e)
949 frame.setSelected(true);
950 frame.setIcon(false);
951 } catch (java.beans.PropertyVetoException ex)
953 // System.err.println(ex.toString());
958 setKeyBindings(frame);
962 windowMenu.add(menuItem);
967 frame.setSelected(true);
968 frame.requestFocus();
969 } catch (java.beans.PropertyVetoException ve)
971 } catch (java.lang.ClassCastException cex)
974 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
980 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
985 private static void setKeyBindings(JInternalFrame frame)
987 @SuppressWarnings("serial")
988 final Action closeAction = new AbstractAction()
991 public void actionPerformed(ActionEvent e)
998 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1000 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1001 InputEvent.CTRL_DOWN_MASK);
1002 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1003 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1005 InputMap inputMap = frame
1006 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1007 String ctrlW = ctrlWKey.toString();
1008 inputMap.put(ctrlWKey, ctrlW);
1009 inputMap.put(cmdWKey, ctrlW);
1011 ActionMap actionMap = frame.getActionMap();
1012 actionMap.put(ctrlW, closeAction);
1016 public void lostOwnership(Clipboard clipboard, Transferable contents)
1020 Desktop.jalviewClipboard = null;
1023 internalCopy = false;
1027 public void dragEnter(DropTargetDragEvent evt)
1032 public void dragExit(DropTargetEvent evt)
1037 public void dragOver(DropTargetDragEvent evt)
1042 public void dropActionChanged(DropTargetDragEvent evt)
1053 public void drop(DropTargetDropEvent evt)
1055 boolean success = true;
1056 // JAL-1552 - acceptDrop required before getTransferable call for
1057 // Java's Transferable for native dnd
1058 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1059 Transferable t = evt.getTransferable();
1060 List<Object> files = new ArrayList<>();
1061 List<DataSourceType> protocols = new ArrayList<>();
1065 Desktop.transferFromDropTarget(files, protocols, evt, t);
1066 } catch (Exception e)
1068 e.printStackTrace();
1076 for (int i = 0; i < files.size(); i++)
1078 // BH 2018 File or String
1079 Object file = files.get(i);
1080 String fileName = file.toString();
1081 DataSourceType protocol = (protocols == null)
1082 ? DataSourceType.FILE
1084 FileFormatI format = null;
1086 if (fileName.endsWith(".jar"))
1088 format = FileFormat.Jalview;
1093 format = new IdentifyFile().identify(file, protocol);
1096 new FileLoader().LoadFile(null, file, protocol, format);
1099 } catch (Exception ex)
1104 evt.dropComplete(success); // need this to ensure input focus is properly
1105 // transfered to any new windows created
1115 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1117 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1118 JalviewFileChooser chooser = JalviewFileChooser
1119 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1121 chooser.setFileView(new JalviewFileView());
1122 chooser.setDialogTitle(
1123 MessageManager.getString("label.open_local_file"));
1124 chooser.setToolTipText(MessageManager.getString("action.open"));
1126 chooser.setResponseHandler(0, new Runnable()
1131 File selectedFile = chooser.getSelectedFile();
1132 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1134 FileFormatI format = chooser.getSelectedFormat();
1137 * Call IdentifyFile to verify the file contains what its extension implies.
1138 * Skip this step for dynamically added file formats, because
1139 * IdentifyFile does not know how to recognise them.
1141 if (FileFormats.getInstance().isIdentifiable(format))
1145 format = new IdentifyFile().identify(selectedFile,
1146 DataSourceType.FILE);
1147 } catch (FileFormatException e)
1149 // format = null; //??
1153 new FileLoader().LoadFile(viewport, selectedFile,
1154 DataSourceType.FILE, format);
1157 chooser.showOpenDialog(this);
1161 * Shows a dialog for input of a URL at which to retrieve alignment data
1166 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1168 // This construct allows us to have a wider textfield
1170 JLabel label = new JLabel(
1171 MessageManager.getString("label.input_file_url"));
1173 JPanel panel = new JPanel(new GridLayout(2, 1));
1177 * the URL to fetch is
1178 * Java: an editable combobox with history
1179 * JS: (pending JAL-3038) a plain text field
1182 String urlBase = "http://www.";
1185 history = new JTextField(urlBase, 35);
1189 JComboBox<String> asCombo = new JComboBox<>();
1190 asCombo.setPreferredSize(new Dimension(400, 20));
1191 asCombo.setEditable(true);
1192 asCombo.addItem(urlBase);
1193 String historyItems = Cache.getProperty("RECENT_URL");
1194 if (historyItems != null)
1196 for (String token : historyItems.split("\\t"))
1198 asCombo.addItem(token);
1205 Object[] options = new Object[] { MessageManager.getString("action.ok"),
1206 MessageManager.getString("action.cancel") };
1207 Runnable action = new Runnable() {
1211 String url = Jalview.isJS() ? ((JTextField) history).getText()
1212 : ((JComboBox<String>) history).getSelectedItem()
1215 if (url.toLowerCase().endsWith(".jar"))
1217 if (viewport != null)
1219 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1220 FileFormat.Jalview);
1224 new FileLoader().LoadFile(url, DataSourceType.URL,
1225 FileFormat.Jalview);
1230 FileFormatI format = null;
1233 format = new IdentifyFile().identify(url, DataSourceType.URL);
1234 } catch (FileFormatException e)
1236 // TODO revise error handling, distinguish between
1237 // URL not found and response not valid
1242 String msg = MessageManager.formatMessage("label.couldnt_locate", url);
1243 JvOptionPane.showInternalMessageDialog(Desktop.desktop, msg,
1244 MessageManager.getString("label.url_not_found"),
1245 JvOptionPane.WARNING_MESSAGE);
1250 if (viewport != null)
1252 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1257 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1261 String dialogOption = MessageManager
1262 .getString("label.input_alignment_from_url");
1263 JvOptionPane.newOptionDialog(desktop).setResponseHandler(0, action)
1264 .showInternalDialog(panel, dialogOption,
1265 JvOptionPane.YES_NO_CANCEL_OPTION,
1266 JvOptionPane.PLAIN_MESSAGE, null, options,
1267 MessageManager.getString("action.ok"));
1271 * Opens the CutAndPaste window for the user to paste an alignment in to
1274 * - if not null, the pasted alignment is added to the current
1275 * alignment; if null, to a new alignment window
1278 public void inputTextboxMenuItem_actionPerformed(
1279 AlignmentViewPanel viewPanel)
1281 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1282 cap.setForInput(viewPanel);
1283 Desktop.addInternalFrame(cap,
1284 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1294 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1295 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1297 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1298 screen.height + "");
1299 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1300 getWidth(), getHeight()));
1302 if (jconsole != null)
1304 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1305 jconsole.stopConsole();
1309 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1312 if (dialogExecutor != null)
1314 dialogExecutor.shutdownNow();
1316 closeAll_actionPerformed(null);
1318 if (groovyConsole != null)
1320 // suppress a possible repeat prompt to save script
1321 groovyConsole.setDirty(false);
1322 groovyConsole.exit();
1327 private void storeLastKnownDimensions(String string, Rectangle jc)
1329 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1330 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1331 + " height:" + jc.height);
1333 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1334 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1335 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1336 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1346 public void aboutMenuItem_actionPerformed(ActionEvent e)
1348 // StringBuffer message = getAboutMessage(false);
1349 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1351 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1352 new Thread(new Runnable()
1357 new SplashScreen(true);
1362 public StringBuffer getAboutMessage(boolean shortv)
1364 StringBuffer message = new StringBuffer();
1365 message.append("<html>");
1368 message.append("<h1><strong>Version: "
1369 + jalview.bin.Cache.getProperty("VERSION")
1370 + "</strong></h1>");
1371 message.append("<strong>Last Updated: <em>"
1372 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1373 + "</em></strong>");
1379 message.append("<strong>Version "
1380 + jalview.bin.Cache.getProperty("VERSION")
1381 + "; last updated: "
1382 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1385 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1386 .equals("Checking"))
1388 message.append("<br>...Checking latest version...</br>");
1390 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1391 .equals(jalview.bin.Cache.getProperty("VERSION")))
1393 boolean red = false;
1394 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1395 .indexOf("automated build") == -1)
1398 // Displayed when code version and jnlp version do not match and code
1399 // version is not a development build
1400 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1403 message.append("<br>!! Version "
1404 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1406 + " is available for download from "
1407 + jalview.bin.Cache.getDefault("www.jalview.org",
1408 "http://www.jalview.org")
1412 message.append("</div>");
1415 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1417 "The Jalview Authors (See AUTHORS file for current list)")
1418 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1419 + "<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"
1420 + "<br><br>If you use Jalview, please cite:"
1421 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1422 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1423 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1429 * Action on requesting Help documentation
1432 public void documentationMenuItem_actionPerformed()
1438 BrowserLauncher.openURL("http://www.jalview.org/help.html");
1442 Help.showHelpWindow();
1444 } catch (Exception ex)
1446 System.err.println("Error opening help: " + ex.getMessage());
1451 public void closeAll_actionPerformed(ActionEvent e)
1453 // TODO show a progress bar while closing?
1454 JInternalFrame[] frames = desktop.getAllFrames();
1455 for (int i = 0; i < frames.length; i++)
1459 frames[i].setClosed(true);
1460 } catch (java.beans.PropertyVetoException ex)
1464 Jalview.setCurrentAlignFrame(null);
1465 System.out.println("ALL CLOSED");
1466 if (v_client != null)
1468 // TODO clear binding to vamsas document objects on close_all
1472 * reset state of singleton objects as appropriate (clear down session state
1473 * when all windows are closed)
1475 StructureSelectionManager ssm = StructureSelectionManager
1476 .getStructureSelectionManager(this);
1484 public void raiseRelated_actionPerformed(ActionEvent e)
1486 reorderAssociatedWindows(false, false);
1490 public void minimizeAssociated_actionPerformed(ActionEvent e)
1492 reorderAssociatedWindows(true, false);
1495 void closeAssociatedWindows()
1497 reorderAssociatedWindows(false, true);
1503 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1507 protected void garbageCollect_actionPerformed(ActionEvent e)
1509 // We simply collect the garbage
1510 jalview.bin.Cache.log.debug("Collecting garbage...");
1512 jalview.bin.Cache.log.debug("Finished garbage collection.");
1519 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1523 protected void showMemusage_actionPerformed(ActionEvent e)
1525 desktop.showMemoryUsage(showMemusage.isSelected());
1532 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1536 protected void showConsole_actionPerformed(ActionEvent e)
1538 showConsole(showConsole.isSelected());
1541 Console jconsole = null;
1544 * control whether the java console is visible or not
1548 void showConsole(boolean selected)
1550 // TODO: decide if we should update properties file
1551 if (jconsole != null) // BH 2018
1553 showConsole.setSelected(selected);
1554 Cache.setProperty("SHOW_JAVA_CONSOLE",
1555 Boolean.valueOf(selected).toString());
1556 jconsole.setVisible(selected);
1560 void reorderAssociatedWindows(boolean minimize, boolean close)
1562 JInternalFrame[] frames = desktop.getAllFrames();
1563 if (frames == null || frames.length < 1)
1568 AlignmentViewport source = null, target = null;
1569 if (frames[0] instanceof AlignFrame)
1571 source = ((AlignFrame) frames[0]).getCurrentView();
1573 else if (frames[0] instanceof TreePanel)
1575 source = ((TreePanel) frames[0]).getViewPort();
1577 else if (frames[0] instanceof PCAPanel)
1579 source = ((PCAPanel) frames[0]).av;
1581 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1583 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1588 for (int i = 0; i < frames.length; i++)
1591 if (frames[i] == null)
1595 if (frames[i] instanceof AlignFrame)
1597 target = ((AlignFrame) frames[i]).getCurrentView();
1599 else if (frames[i] instanceof TreePanel)
1601 target = ((TreePanel) frames[i]).getViewPort();
1603 else if (frames[i] instanceof PCAPanel)
1605 target = ((PCAPanel) frames[i]).av;
1607 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1609 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1612 if (source == target)
1618 frames[i].setClosed(true);
1622 frames[i].setIcon(minimize);
1625 frames[i].toFront();
1629 } catch (java.beans.PropertyVetoException ex)
1644 protected void preferences_actionPerformed(ActionEvent e)
1650 * Prompts the user to choose a file and then saves the Jalview state as a
1651 * Jalview project file
1654 public void saveState_actionPerformed(boolean asCastor)
1656 JalviewFileChooser chooser = new JalviewFileChooser(
1657 asCastor ? "jvp" : "jvx",
1660 chooser.setFileView(new JalviewFileView());
1661 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1662 int option = chooser.showSaveDialog(this);
1663 if (option == JalviewFileChooser.APPROVE_OPTION)
1665 File choice = chooser.getSelectedFile();
1666 setProjectFile(choice);
1668 new Thread(new Runnable()
1673 // TODO: refactor to Jalview desktop session controller action.
1674 setProgressBar(MessageManager.formatMessage(
1675 "label.saving_jalview_project", new Object[]
1676 { choice.getName() }), choice.hashCode());
1677 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1678 choice.getParent());
1679 // TODO catch and handle errors for savestate
1680 // TODO prevent user from messing with the Desktop whilst we're saving
1685 new Jalview2XML().saveState(choice);
1689 new jalview.project.Jalview2XML().saveState(choice);
1691 } catch (OutOfMemoryError oom)
1694 "Whilst saving current state to " + choice.getName(),
1696 } catch (Exception ex)
1699 "Problems whilst trying to save to " + choice.getName(),
1701 JvOptionPane.showMessageDialog(Desktop.this,
1702 MessageManager.formatMessage(
1703 "label.error_whilst_saving_current_state_to",
1705 { choice.getName() }),
1706 MessageManager.getString("label.couldnt_save_project"),
1707 JvOptionPane.WARNING_MESSAGE);
1709 setProgressBar(null, choice.hashCode());
1715 void setProjectFile(File choice)
1717 this.projectFile = choice;
1720 public File getProjectFile()
1722 return this.projectFile;
1726 * Prompts the user to choose a file and loads in as a Jalview project file
1729 public void loadState_actionPerformed(boolean asCastor)
1731 // TODO: GET RID OF .JVX BEFORE RELEASE JIM!
1732 final String[] suffix = asCastor ? new String[] { "jvp", "jar" }
1735 final String[] desc = asCastor
1737 { "Jalview Project", "Jalview Project (old)" }
1739 { "Jalview Project" };
1740 JalviewFileChooser chooser = new JalviewFileChooser(
1741 Cache.getProperty("LAST_DIRECTORY"), suffix,
1744 chooser.setFileView(new JalviewFileView());
1745 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1746 chooser.setResponseHandler(0, new Runnable()
1751 File selectedFile = chooser.getSelectedFile();
1752 setProjectFile(selectedFile);
1753 final String choice = selectedFile.getAbsolutePath();
1754 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1755 new Thread(new Runnable()
1763 new Jalview2XML().loadJalviewAlign(choice);
1767 new jalview.project.Jalview2XML().loadJalviewAlign(choice);
1769 } catch (OutOfMemoryError oom)
1771 new OOMWarning("Whilst loading project from " + choice, oom);
1772 } catch (Exception ex)
1775 "Problems whilst loading project from " + choice, ex);
1776 JvOptionPane.showMessageDialog(Desktop.desktop,
1777 MessageManager.formatMessage(
1778 "label.error_whilst_loading_project_from",
1781 MessageManager.getString("label.couldnt_load_project"),
1782 JvOptionPane.WARNING_MESSAGE);
1789 chooser.showOpenDialog(this);
1793 public void inputSequence_actionPerformed(ActionEvent e)
1795 new SequenceFetcher(this);
1798 JPanel progressPanel;
1800 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1802 public void startLoading(final Object fileName)
1804 if (fileLoadingCount == 0)
1806 fileLoadingPanels.add(addProgressPanel(MessageManager
1807 .formatMessage("label.loading_file", new Object[]
1813 private JPanel addProgressPanel(String string)
1815 if (progressPanel == null)
1817 progressPanel = new JPanel(new GridLayout(1, 1));
1818 totalProgressCount = 0;
1819 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1821 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1822 JProgressBar progressBar = new JProgressBar();
1823 progressBar.setIndeterminate(true);
1825 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1827 thisprogress.add(progressBar, BorderLayout.CENTER);
1828 progressPanel.add(thisprogress);
1829 ((GridLayout) progressPanel.getLayout()).setRows(
1830 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1831 ++totalProgressCount;
1832 instance.validate();
1833 return thisprogress;
1836 int totalProgressCount = 0;
1838 private void removeProgressPanel(JPanel progbar)
1840 if (progressPanel != null)
1842 synchronized (progressPanel)
1844 progressPanel.remove(progbar);
1845 GridLayout gl = (GridLayout) progressPanel.getLayout();
1846 gl.setRows(gl.getRows() - 1);
1847 if (--totalProgressCount < 1)
1849 this.getContentPane().remove(progressPanel);
1850 progressPanel = null;
1857 public void stopLoading()
1860 if (fileLoadingCount < 1)
1862 while (fileLoadingPanels.size() > 0)
1864 removeProgressPanel(fileLoadingPanels.remove(0));
1866 fileLoadingPanels.clear();
1867 fileLoadingCount = 0;
1872 public static int getViewCount(String alignmentId)
1874 AlignmentViewport[] aps = getViewports(alignmentId);
1875 return (aps == null) ? 0 : aps.length;
1880 * @param alignmentId
1881 * - if null, all sets are returned
1882 * @return all AlignmentPanels concerning the alignmentId sequence set
1884 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1886 if (Desktop.desktop == null)
1888 // no frames created and in headless mode
1889 // TODO: verify that frames are recoverable when in headless mode
1892 List<AlignmentPanel> aps = new ArrayList<>();
1893 AlignFrame[] frames = getAlignFrames();
1898 for (AlignFrame af : frames)
1900 for (AlignmentPanel ap : af.alignPanels)
1902 if (alignmentId == null
1903 || alignmentId.equals(ap.av.getSequenceSetId()))
1909 if (aps.size() == 0)
1913 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1918 * get all the viewports on an alignment.
1920 * @param sequenceSetId
1921 * unique alignment id (may be null - all viewports returned in that
1923 * @return all viewports on the alignment bound to sequenceSetId
1925 public static AlignmentViewport[] getViewports(String sequenceSetId)
1927 List<AlignmentViewport> viewp = new ArrayList<>();
1928 if (desktop != null)
1930 AlignFrame[] frames = Desktop.getAlignFrames();
1932 for (AlignFrame afr : frames)
1934 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1935 .equals(sequenceSetId))
1937 if (afr.alignPanels != null)
1939 for (AlignmentPanel ap : afr.alignPanels)
1941 if (sequenceSetId == null
1942 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1950 viewp.add(afr.getViewport());
1954 if (viewp.size() > 0)
1956 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1963 * Explode the views in the given frame into separate AlignFrame
1967 public static void explodeViews(AlignFrame af)
1969 int size = af.alignPanels.size();
1975 for (int i = 0; i < size; i++)
1977 AlignmentPanel ap = af.alignPanels.get(i);
1978 AlignFrame newaf = new AlignFrame(ap);
1981 * Restore the view's last exploded frame geometry if known. Multiple
1982 * views from one exploded frame share and restore the same (frame)
1983 * position and size.
1985 Rectangle geometry = ap.av.getExplodedGeometry();
1986 if (geometry != null)
1988 newaf.setBounds(geometry);
1991 ap.av.setGatherViewsHere(false);
1993 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1994 AlignFrame.DEFAULT_HEIGHT);
1997 af.alignPanels.clear();
1998 af.closeMenuItem_actionPerformed(true);
2003 * Gather expanded views (separate AlignFrame's) with the same sequence set
2004 * identifier back in to this frame as additional views, and close the expanded
2005 * views. Note the expanded frames may themselves have multiple views. We take
2010 public void gatherViews(AlignFrame source)
2012 source.viewport.setGatherViewsHere(true);
2013 source.viewport.setExplodedGeometry(source.getBounds());
2014 JInternalFrame[] frames = desktop.getAllFrames();
2015 String viewId = source.viewport.getSequenceSetId();
2017 for (int t = 0; t < frames.length; t++)
2019 if (frames[t] instanceof AlignFrame && frames[t] != source)
2021 AlignFrame af = (AlignFrame) frames[t];
2022 boolean gatherThis = false;
2023 for (int a = 0; a < af.alignPanels.size(); a++)
2025 AlignmentPanel ap = af.alignPanels.get(a);
2026 if (viewId.equals(ap.av.getSequenceSetId()))
2029 ap.av.setGatherViewsHere(false);
2030 ap.av.setExplodedGeometry(af.getBounds());
2031 source.addAlignmentPanel(ap, false);
2037 af.alignPanels.clear();
2038 af.closeMenuItem_actionPerformed(true);
2045 jalview.gui.VamsasApplication v_client = null;
2048 public void vamsasImport_actionPerformed(ActionEvent e)
2050 // TODO: JAL-3048 not needed for Jalview-JS
2052 if (v_client == null)
2054 // Load and try to start a session.
2055 JalviewFileChooser chooser = new JalviewFileChooser(
2056 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2058 chooser.setFileView(new JalviewFileView());
2059 chooser.setDialogTitle(
2060 MessageManager.getString("label.open_saved_vamsas_session"));
2061 chooser.setToolTipText(MessageManager.getString(
2062 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2064 int value = chooser.showOpenDialog(this);
2066 if (value == JalviewFileChooser.APPROVE_OPTION)
2068 String fle = chooser.getSelectedFile().toString();
2069 if (!vamsasImport(chooser.getSelectedFile()))
2071 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2072 MessageManager.formatMessage(
2073 "label.couldnt_import_as_vamsas_session",
2077 .getString("label.vamsas_document_import_failed"),
2078 JvOptionPane.ERROR_MESSAGE);
2084 jalview.bin.Cache.log.error(
2085 "Implementation error - load session from a running session is not supported.");
2090 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2093 * @return true if import was a success and a session was started.
2095 public boolean vamsasImport(URL url)
2097 // TODO: create progress bar
2098 if (v_client != null)
2101 jalview.bin.Cache.log.error(
2102 "Implementation error - load session from a running session is not supported.");
2108 // copy the URL content to a temporary local file
2109 // TODO: be a bit cleverer here with nio (?!)
2110 File file = File.createTempFile("vdocfromurl", ".vdj");
2111 FileOutputStream fos = new FileOutputStream(file);
2112 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2113 byte[] buffer = new byte[2048];
2115 while ((ln = bis.read(buffer)) > -1)
2117 fos.write(buffer, 0, ln);
2121 v_client = new jalview.gui.VamsasApplication(this, file,
2122 url.toExternalForm());
2123 } catch (Exception ex)
2125 jalview.bin.Cache.log.error(
2126 "Failed to create new vamsas session from contents of URL "
2131 setupVamsasConnectedGui();
2132 v_client.initial_update(); // TODO: thread ?
2133 return v_client.inSession();
2137 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2140 * @return true if import was a success and a session was started.
2142 public boolean vamsasImport(File file)
2144 if (v_client != null)
2147 jalview.bin.Cache.log.error(
2148 "Implementation error - load session from a running session is not supported.");
2152 setProgressBar(MessageManager.formatMessage(
2153 "status.importing_vamsas_session_from", new Object[]
2154 { file.getName() }), file.hashCode());
2157 v_client = new jalview.gui.VamsasApplication(this, file, null);
2158 } catch (Exception ex)
2160 setProgressBar(MessageManager.formatMessage(
2161 "status.importing_vamsas_session_from", new Object[]
2162 { file.getName() }), file.hashCode());
2163 jalview.bin.Cache.log.error(
2164 "New vamsas session from existing session file failed:", ex);
2167 setupVamsasConnectedGui();
2168 v_client.initial_update(); // TODO: thread ?
2169 setProgressBar(MessageManager.formatMessage(
2170 "status.importing_vamsas_session_from", new Object[]
2171 { file.getName() }), file.hashCode());
2172 return v_client.inSession();
2175 public boolean joinVamsasSession(String mysesid)
2177 if (v_client != null)
2179 throw new Error(MessageManager
2180 .getString("error.try_join_vamsas_session_another"));
2182 if (mysesid == null)
2185 MessageManager.getString("error.invalid_vamsas_session_id"));
2187 v_client = new VamsasApplication(this, mysesid);
2188 setupVamsasConnectedGui();
2189 v_client.initial_update();
2190 return (v_client.inSession());
2194 public void vamsasStart_actionPerformed(ActionEvent e)
2196 if (v_client == null)
2199 // we just start a default session for moment.
2201 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2202 * getProperty("LAST_DIRECTORY"));
2204 * chooser.setFileView(new JalviewFileView());
2205 * chooser.setDialogTitle("Load Vamsas file");
2206 * chooser.setToolTipText("Import");
2208 * int value = chooser.showOpenDialog(this);
2210 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2211 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2213 v_client = new VamsasApplication(this);
2214 setupVamsasConnectedGui();
2215 v_client.initial_update(); // TODO: thread ?
2219 // store current data in session.
2220 v_client.push_update(); // TODO: thread
2224 protected void setupVamsasConnectedGui()
2226 vamsasStart.setText(MessageManager.getString("label.session_update"));
2227 vamsasSave.setVisible(true);
2228 vamsasStop.setVisible(true);
2229 vamsasImport.setVisible(false); // Document import to existing session is
2230 // not possible for vamsas-client-1.0.
2233 protected void setupVamsasDisconnectedGui()
2235 vamsasSave.setVisible(false);
2236 vamsasStop.setVisible(false);
2237 vamsasImport.setVisible(true);
2239 .setText(MessageManager.getString("label.new_vamsas_session"));
2243 public void vamsasStop_actionPerformed(ActionEvent e)
2245 if (v_client != null)
2247 v_client.end_session();
2249 setupVamsasDisconnectedGui();
2253 protected void buildVamsasStMenu()
2255 if (v_client == null)
2257 String[] sess = null;
2260 sess = VamsasApplication.getSessionList();
2261 } catch (Exception e)
2263 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2269 jalview.bin.Cache.log.debug(
2270 "Got current sessions list: " + sess.length + " entries.");
2271 VamsasStMenu.removeAll();
2272 for (int i = 0; i < sess.length; i++)
2274 JMenuItem sessit = new JMenuItem();
2275 sessit.setText(sess[i]);
2276 sessit.setToolTipText(MessageManager
2277 .formatMessage("label.connect_to_session", new Object[]
2279 final Desktop dsktp = this;
2280 final String mysesid = sess[i];
2281 sessit.addActionListener(new ActionListener()
2285 public void actionPerformed(ActionEvent e)
2287 if (dsktp.v_client == null)
2289 Thread rthr = new Thread(new Runnable()
2295 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2296 dsktp.setupVamsasConnectedGui();
2297 dsktp.v_client.initial_update();
2305 VamsasStMenu.add(sessit);
2307 // don't show an empty menu.
2308 VamsasStMenu.setVisible(sess.length > 0);
2313 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2314 VamsasStMenu.removeAll();
2315 VamsasStMenu.setVisible(false);
2320 // Not interested in the content. Just hide ourselves.
2321 VamsasStMenu.setVisible(false);
2326 public void vamsasSave_actionPerformed(ActionEvent e)
2328 // TODO: JAL-3048 not needed for Jalview-JS
2330 if (v_client != null)
2332 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2333 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2336 chooser.setFileView(new JalviewFileView());
2337 chooser.setDialogTitle(MessageManager
2338 .getString("label.save_vamsas_document_archive"));
2340 int value = chooser.showSaveDialog(this);
2342 if (value == JalviewFileChooser.APPROVE_OPTION)
2344 java.io.File choice = chooser.getSelectedFile();
2345 JPanel progpanel = addProgressPanel(MessageManager
2346 .formatMessage("label.saving_vamsas_doc", new Object[]
2347 { choice.getName() }));
2348 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2349 String warnmsg = null;
2350 String warnttl = null;
2353 v_client.vclient.storeDocument(choice);
2356 warnttl = "Serious Problem saving Vamsas Document";
2357 warnmsg = ex.toString();
2358 jalview.bin.Cache.log
2359 .error("Error Whilst saving document to " + choice, ex);
2361 } catch (Exception ex)
2363 warnttl = "Problem saving Vamsas Document.";
2364 warnmsg = ex.toString();
2365 jalview.bin.Cache.log.warn(
2366 "Exception Whilst saving document to " + choice, ex);
2369 removeProgressPanel(progpanel);
2370 if (warnmsg != null)
2372 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2374 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2380 JPanel vamUpdate = null;
2383 * hide vamsas user gui bits when a vamsas document event is being handled.
2386 * true to hide gui, false to reveal gui
2388 public void setVamsasUpdate(boolean b)
2390 Cache.log.debug("Setting gui for Vamsas update "
2391 + (b ? "in progress" : "finished"));
2393 if (vamUpdate != null)
2395 this.removeProgressPanel(vamUpdate);
2399 vamUpdate = this.addProgressPanel(
2400 MessageManager.getString("label.updating_vamsas_session"));
2402 vamsasStart.setVisible(!b);
2403 vamsasStop.setVisible(!b);
2404 vamsasSave.setVisible(!b);
2407 public JInternalFrame[] getAllFrames()
2409 return desktop.getAllFrames();
2413 * Checks the given url to see if it gives a response indicating that the user
2414 * should be informed of a new questionnaire.
2418 public void checkForQuestionnaire(String url)
2420 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2421 // javax.swing.SwingUtilities.invokeLater(jvq);
2422 new Thread(jvq).start();
2425 public void checkURLLinks()
2427 // Thread off the URL link checker
2428 addDialogThread(new Runnable()
2433 if (Cache.getDefault("CHECKURLLINKS", true))
2435 // check what the actual links are - if it's just the default don't
2436 // bother with the warning
2437 List<String> links = Preferences.sequenceUrlLinks
2440 // only need to check links if there is one with a
2441 // SEQUENCE_ID which is not the default EMBL_EBI link
2442 ListIterator<String> li = links.listIterator();
2443 boolean check = false;
2444 List<JLabel> urls = new ArrayList<>();
2445 while (li.hasNext())
2447 String link = li.next();
2448 if (link.contains(SEQUENCE_ID)
2449 && !UrlConstants.isDefaultString(link))
2452 int barPos = link.indexOf("|");
2453 String urlMsg = barPos == -1 ? link
2454 : link.substring(0, barPos) + ": "
2455 + link.substring(barPos + 1);
2456 urls.add(new JLabel(urlMsg));
2464 // ask user to check in case URL links use old style tokens
2465 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2466 JPanel msgPanel = new JPanel();
2467 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2468 msgPanel.add(Box.createVerticalGlue());
2469 JLabel msg = new JLabel(MessageManager
2470 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2471 JLabel msg2 = new JLabel(MessageManager
2472 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2474 for (JLabel url : urls)
2480 final JCheckBox jcb = new JCheckBox(
2481 MessageManager.getString("label.do_not_display_again"));
2482 jcb.addActionListener(new ActionListener()
2485 public void actionPerformed(ActionEvent e)
2487 // update Cache settings for "don't show this again"
2488 boolean showWarningAgain = !jcb.isSelected();
2489 Cache.setProperty("CHECKURLLINKS",
2490 Boolean.valueOf(showWarningAgain).toString());
2495 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2497 .getString("label.SEQUENCE_ID_no_longer_used"),
2498 JvOptionPane.WARNING_MESSAGE);
2505 * Proxy class for JDesktopPane which optionally displays the current memory
2506 * usage and highlights the desktop area with a red bar if free memory runs low.
2510 public class MyDesktopPane extends JDesktopPane
2513 private static final float ONE_MB = 1048576f;
2515 boolean showMemoryUsage = false;
2519 java.text.NumberFormat df;
2521 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2524 public MyDesktopPane(boolean showMemoryUsage)
2526 showMemoryUsage(showMemoryUsage);
2529 public void showMemoryUsage(boolean showMemory)
2531 this.showMemoryUsage = showMemory;
2534 Thread worker = new Thread(this);
2540 public boolean isShowMemoryUsage()
2542 return showMemoryUsage;
2548 df = java.text.NumberFormat.getNumberInstance();
2549 df.setMaximumFractionDigits(2);
2550 runtime = Runtime.getRuntime();
2552 while (showMemoryUsage)
2556 maxMemory = runtime.maxMemory() / ONE_MB;
2557 allocatedMemory = runtime.totalMemory() / ONE_MB;
2558 freeMemory = runtime.freeMemory() / ONE_MB;
2559 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2561 percentUsage = (totalFreeMemory / maxMemory) * 100;
2563 // if (percentUsage < 20)
2565 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2567 // instance.set.setBorder(border1);
2570 // sleep after showing usage
2572 } catch (Exception ex)
2574 ex.printStackTrace();
2580 public void paintComponent(Graphics g)
2582 if (showMemoryUsage && g != null && df != null)
2584 if (percentUsage < 20)
2586 g.setColor(Color.red);
2588 FontMetrics fm = g.getFontMetrics();
2591 g.drawString(MessageManager.formatMessage("label.memory_stats",
2593 { df.format(totalFreeMemory), df.format(maxMemory),
2594 df.format(percentUsage) }),
2595 10, getHeight() - fm.getHeight());
2602 * Accessor method to quickly get all the AlignmentFrames loaded.
2604 * @return an array of AlignFrame, or null if none found
2606 public static AlignFrame[] getAlignFrames()
2608 if (Jalview.isHeadlessMode())
2610 // Desktop.desktop is null in headless mode
2611 return new AlignFrame[] { Jalview.currentAlignFrame };
2614 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2620 List<AlignFrame> avp = new ArrayList<>();
2622 for (int i = frames.length - 1; i > -1; i--)
2624 if (frames[i] instanceof AlignFrame)
2626 avp.add((AlignFrame) frames[i]);
2628 else if (frames[i] instanceof SplitFrame)
2631 * Also check for a split frame containing an AlignFrame
2633 GSplitFrame sf = (GSplitFrame) frames[i];
2634 if (sf.getTopFrame() instanceof AlignFrame)
2636 avp.add((AlignFrame) sf.getTopFrame());
2638 if (sf.getBottomFrame() instanceof AlignFrame)
2640 avp.add((AlignFrame) sf.getBottomFrame());
2644 if (avp.size() == 0)
2648 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2653 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2657 public GStructureViewer[] getJmols()
2659 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2665 List<GStructureViewer> avp = new ArrayList<>();
2667 for (int i = frames.length - 1; i > -1; i--)
2669 if (frames[i] instanceof AppJmol)
2671 GStructureViewer af = (GStructureViewer) frames[i];
2675 if (avp.size() == 0)
2679 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2684 * Add Groovy Support to Jalview
2687 public void groovyShell_actionPerformed()
2691 openGroovyConsole();
2692 } catch (Exception ex)
2694 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2695 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2697 MessageManager.getString("label.couldnt_create_groovy_shell"),
2698 MessageManager.getString("label.groovy_support_failed"),
2699 JvOptionPane.ERROR_MESSAGE);
2704 * Open the Groovy console
2706 void openGroovyConsole()
2708 if (groovyConsole == null)
2710 groovyConsole = new groovy.ui.Console();
2711 groovyConsole.setVariable("Jalview", this);
2712 groovyConsole.run();
2715 * We allow only one console at a time, so that AlignFrame menu option
2716 * 'Calculate | Run Groovy script' is unambiguous.
2717 * Disable 'Groovy Console', and enable 'Run script', when the console is
2718 * opened, and the reverse when it is closed
2720 Window window = (Window) groovyConsole.getFrame();
2721 window.addWindowListener(new WindowAdapter()
2724 public void windowClosed(WindowEvent e)
2727 * rebind CMD-Q from Groovy Console to Jalview Quit
2730 enableExecuteGroovy(false);
2736 * show Groovy console window (after close and reopen)
2738 ((Window) groovyConsole.getFrame()).setVisible(true);
2741 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2742 * and disable opening a second console
2744 enableExecuteGroovy(true);
2748 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
2751 protected void addQuitHandler()
2753 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2754 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2755 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2757 getRootPane().getActionMap().put("Quit", new AbstractAction()
2760 public void actionPerformed(ActionEvent e)
2768 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2771 * true if Groovy console is open
2773 public void enableExecuteGroovy(boolean enabled)
2776 * disable opening a second Groovy console
2777 * (or re-enable when the console is closed)
2779 groovyShell.setEnabled(!enabled);
2781 AlignFrame[] alignFrames = getAlignFrames();
2782 if (alignFrames != null)
2784 for (AlignFrame af : alignFrames)
2786 af.setGroovyEnabled(enabled);
2792 * Progress bars managed by the IProgressIndicator method.
2794 private Hashtable<Long, JPanel> progressBars;
2796 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2801 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2804 public void setProgressBar(String message, long id)
2806 if (progressBars == null)
2808 progressBars = new Hashtable<>();
2809 progressBarHandlers = new Hashtable<>();
2812 if (progressBars.get(new Long(id)) != null)
2814 JPanel panel = progressBars.remove(new Long(id));
2815 if (progressBarHandlers.contains(new Long(id)))
2817 progressBarHandlers.remove(new Long(id));
2819 removeProgressPanel(panel);
2823 progressBars.put(new Long(id), addProgressPanel(message));
2830 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2831 * jalview.gui.IProgressIndicatorHandler)
2834 public void registerHandler(final long id,
2835 final IProgressIndicatorHandler handler)
2837 if (progressBarHandlers == null
2838 || !progressBars.containsKey(new Long(id)))
2840 throw new Error(MessageManager.getString(
2841 "error.call_setprogressbar_before_registering_handler"));
2843 progressBarHandlers.put(new Long(id), handler);
2844 final JPanel progressPanel = progressBars.get(new Long(id));
2845 if (handler.canCancel())
2847 JButton cancel = new JButton(
2848 MessageManager.getString("action.cancel"));
2849 final IProgressIndicator us = this;
2850 cancel.addActionListener(new ActionListener()
2854 public void actionPerformed(ActionEvent e)
2856 handler.cancelActivity(id);
2857 us.setProgressBar(MessageManager
2858 .formatMessage("label.cancelled_params", new Object[]
2859 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2863 progressPanel.add(cancel, BorderLayout.EAST);
2869 * @return true if any progress bars are still active
2872 public boolean operationInProgress()
2874 if (progressBars != null && progressBars.size() > 0)
2882 * This will return the first AlignFrame holding the given viewport instance. It
2883 * will break if there are more than one AlignFrames viewing a particular av.
2886 * @return alignFrame for viewport
2888 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2890 if (desktop != null)
2892 AlignmentPanel[] aps = getAlignmentPanels(
2893 viewport.getSequenceSetId());
2894 for (int panel = 0; aps != null && panel < aps.length; panel++)
2896 if (aps[panel] != null && aps[panel].av == viewport)
2898 return aps[panel].alignFrame;
2905 public VamsasApplication getVamsasApplication()
2912 * flag set if jalview GUI is being operated programmatically
2914 private boolean inBatchMode = false;
2917 * check if jalview GUI is being operated programmatically
2919 * @return inBatchMode
2921 public boolean isInBatchMode()
2927 * set flag if jalview GUI is being operated programmatically
2929 * @param inBatchMode
2931 public void setInBatchMode(boolean inBatchMode)
2933 this.inBatchMode = inBatchMode;
2936 public void startServiceDiscovery()
2938 startServiceDiscovery(false);
2941 public void startServiceDiscovery(boolean blocking)
2943 boolean alive = true;
2944 Thread t0 = null, t1 = null, t2 = null;
2945 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2948 // todo: changesupport handlers need to be transferred
2949 if (discoverer == null)
2951 discoverer = new jalview.ws.jws1.Discoverer();
2952 // register PCS handler for desktop.
2953 discoverer.addPropertyChangeListener(changeSupport);
2955 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2956 // until we phase out completely
2957 (t0 = new Thread(discoverer)).start();
2960 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2962 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2963 .startDiscoverer(changeSupport);
2967 // TODO: do rest service discovery
2976 } catch (Exception e)
2979 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2980 || (t3 != null && t3.isAlive())
2981 || (t0 != null && t0.isAlive());
2987 * called to check if the service discovery process completed successfully.
2991 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2993 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2995 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2996 .getErrorMessages();
2999 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3001 if (serviceChangedDialog == null)
3003 // only run if we aren't already displaying one of these.
3004 addDialogThread(serviceChangedDialog = new Runnable()
3011 * JalviewDialog jd =new JalviewDialog() {
3013 * @Override protected void cancelPressed() { // TODO
3014 * Auto-generated method stub
3016 * }@Override protected void okPressed() { // TODO
3017 * Auto-generated method stub
3019 * }@Override protected void raiseClosed() { // TODO
3020 * Auto-generated method stub
3022 * } }; jd.initDialogFrame(new
3023 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3024 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3025 * + " or mis-configured HTTP proxy settings.<br/>" +
3026 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3028 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3029 * ), true, true, "Web Service Configuration Problem", 450,
3032 * jd.waitForInput();
3034 JvOptionPane.showConfirmDialog(Desktop.desktop,
3035 new JLabel("<html><table width=\"450\"><tr><td>"
3036 + ermsg + "</td></tr></table>"
3037 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3038 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3039 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3040 + " Tools->Preferences dialog box to change them.</p></html>"),
3041 "Web Service Configuration Problem",
3042 JvOptionPane.DEFAULT_OPTION,
3043 JvOptionPane.ERROR_MESSAGE);
3044 serviceChangedDialog = null;
3053 "Errors reported by JABA discovery service. Check web services preferences.\n"
3060 private Runnable serviceChangedDialog = null;
3063 * start a thread to open a URL in the configured browser. Pops up a warning
3064 * dialog to the user if there is an exception when calling out to the browser
3069 public static void showUrl(final String url)
3071 showUrl(url, Desktop.instance);
3075 * Like showUrl but allows progress handler to be specified
3079 * (null) or object implementing IProgressIndicator
3081 public static void showUrl(final String url,
3082 final IProgressIndicator progress)
3084 new Thread(new Runnable()
3091 if (progress != null)
3093 progress.setProgressBar(MessageManager
3094 .formatMessage("status.opening_params", new Object[]
3095 { url }), this.hashCode());
3097 jalview.util.BrowserLauncher.openURL(url);
3098 } catch (Exception ex)
3100 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3102 .getString("label.web_browser_not_found_unix"),
3103 MessageManager.getString("label.web_browser_not_found"),
3104 JvOptionPane.WARNING_MESSAGE);
3106 ex.printStackTrace();
3108 if (progress != null)
3110 progress.setProgressBar(null, this.hashCode());
3116 public static WsParamSetManager wsparamManager = null;
3118 public static ParamManager getUserParameterStore()
3120 if (wsparamManager == null)
3122 wsparamManager = new WsParamSetManager();
3124 return wsparamManager;
3128 * static hyperlink handler proxy method for use by Jalview's internal windows
3132 public static void hyperlinkUpdate(HyperlinkEvent e)
3134 if (e.getEventType() == EventType.ACTIVATED)
3139 url = e.getURL().toString();
3140 Desktop.showUrl(url);
3141 } catch (Exception x)
3145 if (Cache.log != null)
3147 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3152 "Couldn't handle string " + url + " as a URL.");
3155 // ignore any exceptions due to dud links.
3162 * single thread that handles display of dialogs to user.
3164 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3167 * flag indicating if dialogExecutor should try to acquire a permit
3169 private volatile boolean dialogPause = true;
3174 private java.util.concurrent.Semaphore block = new Semaphore(0);
3176 private static groovy.ui.Console groovyConsole;
3179 * add another dialog thread to the queue
3183 public void addDialogThread(final Runnable prompter)
3185 dialogExecutor.submit(new Runnable()
3195 } catch (InterruptedException x)
3200 if (instance == null)
3206 SwingUtilities.invokeAndWait(prompter);
3207 } catch (Exception q)
3209 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3215 public void startDialogQueue()
3217 // set the flag so we don't pause waiting for another permit and semaphore
3218 // the current task to begin
3219 dialogPause = false;
3224 * Outputs an image of the desktop to file in EPS format, after prompting the
3225 * user for choice of Text or Lineart character rendering (unless a preference
3226 * has been set). The file name is generated as
3229 * Jalview_snapshot_nnnnn.eps where nnnnn is the current timestamp in milliseconds
3233 protected void snapShotWindow_actionPerformed(ActionEvent e)
3235 // currently the menu option to do this is not shown
3238 int width = getWidth();
3239 int height = getHeight();
3241 "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
3242 ImageWriterI writer = new ImageWriterI()
3245 public void exportImage(Graphics g) throws Exception
3248 Cache.log.info("Successfully written snapshot to file "
3249 + of.getAbsolutePath());
3252 String title = "View of desktop";
3253 ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
3255 exporter.doExport(of, this, width, height, title);
3259 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3260 * This respects (remembers) any previous 'exploded geometry' i.e. the size and
3261 * location last time the view was expanded (if any). However it does not
3262 * remember the split pane divider location - this is set to match the
3263 * 'exploding' frame.
3267 public void explodeViews(SplitFrame sf)
3269 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3270 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3271 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3273 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3275 int viewCount = topPanels.size();
3282 * Processing in reverse order works, forwards order leaves the first panels
3283 * not visible. I don't know why!
3285 for (int i = viewCount - 1; i >= 0; i--)
3288 * Make new top and bottom frames. These take over the respective
3289 * AlignmentPanel objects, including their AlignmentViewports, so the
3290 * cdna/protein relationships between the viewports is carried over to the
3293 * explodedGeometry holds the (x, y) position of the previously exploded
3294 * SplitFrame, and the (width, height) of the AlignFrame component
3296 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3297 AlignFrame newTopFrame = new AlignFrame(topPanel);
3298 newTopFrame.setSize(oldTopFrame.getSize());
3299 newTopFrame.setVisible(true);
3300 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3301 .getExplodedGeometry();
3302 if (geometry != null)
3304 newTopFrame.setSize(geometry.getSize());
3307 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3308 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3309 newBottomFrame.setSize(oldBottomFrame.getSize());
3310 newBottomFrame.setVisible(true);
3311 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3312 .getExplodedGeometry();
3313 if (geometry != null)
3315 newBottomFrame.setSize(geometry.getSize());
3318 topPanel.av.setGatherViewsHere(false);
3319 bottomPanel.av.setGatherViewsHere(false);
3320 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3322 if (geometry != null)
3324 splitFrame.setLocation(geometry.getLocation());
3326 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3330 * Clear references to the panels (now relocated in the new SplitFrames)
3331 * before closing the old SplitFrame.
3334 bottomPanels.clear();
3339 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3340 * back into the given SplitFrame as additional views. Note that the gathered
3341 * frames may themselves have multiple views.
3345 public void gatherViews(GSplitFrame source)
3348 * special handling of explodedGeometry for a view within a SplitFrame: - it
3349 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3350 * height) of the AlignFrame component
3352 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3353 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3354 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3355 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3356 myBottomFrame.viewport
3357 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3358 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3359 myTopFrame.viewport.setGatherViewsHere(true);
3360 myBottomFrame.viewport.setGatherViewsHere(true);
3361 String topViewId = myTopFrame.viewport.getSequenceSetId();
3362 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3364 JInternalFrame[] frames = desktop.getAllFrames();
3365 for (JInternalFrame frame : frames)
3367 if (frame instanceof SplitFrame && frame != source)
3369 SplitFrame sf = (SplitFrame) frame;
3370 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3371 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3372 boolean gatherThis = false;
3373 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3375 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3376 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3377 if (topViewId.equals(topPanel.av.getSequenceSetId())
3378 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3381 topPanel.av.setGatherViewsHere(false);
3382 bottomPanel.av.setGatherViewsHere(false);
3383 topPanel.av.setExplodedGeometry(
3384 new Rectangle(sf.getLocation(), topFrame.getSize()));
3385 bottomPanel.av.setExplodedGeometry(
3386 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3387 myTopFrame.addAlignmentPanel(topPanel, false);
3388 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3394 topFrame.getAlignPanels().clear();
3395 bottomFrame.getAlignPanels().clear();
3402 * The dust settles...give focus to the tab we did this from.
3404 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3407 public static groovy.ui.Console getGroovyConsole()
3409 return groovyConsole;
3413 * handles the payload of a drag and drop event.
3415 * TODO refactor to desktop utilities class
3418 * - Data source strings extracted from the drop event
3420 * - protocol for each data source extracted from the drop event
3424 * - the payload from the drop event
3427 public static void transferFromDropTarget(List<Object> files,
3428 List<DataSourceType> protocols, DropTargetDropEvent evt,
3429 Transferable t) throws Exception
3432 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3434 // DataFlavor[] flavors = t.getTransferDataFlavors();
3435 // for (int i = 0; i < flavors.length; i++) {
3436 // if (flavors[i].isFlavorJavaFileListType()) {
3437 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3438 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3439 // for (int j = 0; j < list.size(); j++) {
3440 // File file = (File) list.get(j);
3441 // byte[] data = getDroppedFileBytes(file);
3442 // fileName.setText(file.getName() + " - " + data.length + " " +
3443 // evt.getLocation());
3444 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3445 // target.setText(new String(data));
3447 // dtde.dropComplete(true);
3452 DataFlavor uriListFlavor = new DataFlavor(
3453 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3456 urlFlavour = new DataFlavor(
3457 "application/x-java-url; class=java.net.URL");
3458 } catch (ClassNotFoundException cfe)
3460 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3463 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3468 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3469 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3470 // means url may be null.
3473 protocols.add(DataSourceType.URL);
3474 files.add(url.toString());
3475 Cache.log.debug("Drop handled as URL dataflavor "
3476 + files.get(files.size() - 1));
3481 if (Platform.isAMac())
3484 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3488 } catch (Throwable ex)
3490 Cache.log.debug("URL drop handler failed.", ex);
3493 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3495 // Works on Windows and MacOSX
3496 Cache.log.debug("Drop handled as javaFileListFlavor");
3497 for (Object file : (List) t
3498 .getTransferData(DataFlavor.javaFileListFlavor))
3501 protocols.add(DataSourceType.FILE);
3506 // Unix like behaviour
3507 boolean added = false;
3509 if (t.isDataFlavorSupported(uriListFlavor))
3511 Cache.log.debug("Drop handled as uriListFlavor");
3512 // This is used by Unix drag system
3513 data = (String) t.getTransferData(uriListFlavor);
3517 // fallback to text: workaround - on OSX where there's a JVM bug
3518 Cache.log.debug("standard URIListFlavor failed. Trying text");
3519 // try text fallback
3520 DataFlavor textDf = new DataFlavor(
3521 "text/plain;class=java.lang.String");
3522 if (t.isDataFlavorSupported(textDf))
3524 data = (String) t.getTransferData(textDf);
3527 Cache.log.debug("Plain text drop content returned "
3528 + (data == null ? "Null - failed" : data));
3533 while (protocols.size() < files.size())
3535 Cache.log.debug("Adding missing FILE protocol for "
3536 + files.get(protocols.size()));
3537 protocols.add(DataSourceType.FILE);
3539 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3540 data, "\r\n"); st.hasMoreTokens();)
3543 String s = st.nextToken();
3544 if (s.startsWith("#"))
3546 // the line is a comment (as per the RFC 2483)
3549 java.net.URI uri = new java.net.URI(s);
3550 if (uri.getScheme().toLowerCase().startsWith("http"))
3552 protocols.add(DataSourceType.URL);
3553 files.add(uri.toString());
3557 // otherwise preserve old behaviour: catch all for file objects
3558 java.io.File file = new java.io.File(uri);
3559 protocols.add(DataSourceType.FILE);
3560 files.add(file.toString());
3565 if (Cache.log.isDebugEnabled())
3567 if (data == null || !added)
3570 if (t.getTransferDataFlavors() != null
3571 && t.getTransferDataFlavors().length > 0)
3574 "Couldn't resolve drop data. Here are the supported flavors:");
3575 for (DataFlavor fl : t.getTransferDataFlavors())
3578 "Supported transfer dataflavor: " + fl.toString());
3579 Object df = t.getTransferData(fl);
3582 Cache.log.debug("Retrieves: " + df);
3586 Cache.log.debug("Retrieved nothing");
3592 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3598 if (Platform.isWindows())
3601 Cache.log.debug("Scanning dropped content for Windows Link Files");
3603 // resolve any .lnk files in the file drop
3604 for (int f = 0; f < files.size(); f++)
3606 String source = files.get(f).toString().toLowerCase();
3607 if (protocols.get(f).equals(DataSourceType.FILE)
3608 && (source.endsWith(".lnk") || source.endsWith(".url")
3609 || source.endsWith(".site")))
3613 Object obj = files.get(f);
3614 File lf = (obj instanceof File ? (File) obj
3615 : new File((String) obj));
3616 // process link file to get a URL
3617 Cache.log.debug("Found potential link file: " + lf);
3618 WindowsShortcut wscfile = new WindowsShortcut(lf);
3619 String fullname = wscfile.getRealFilename();
3620 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3621 files.set(f, fullname);
3622 Cache.log.debug("Parsed real filename " + fullname
3623 + " to extract protocol: " + protocols.get(f));
3624 } catch (Exception ex)
3627 "Couldn't parse " + files.get(f) + " as a link file.",
3636 * Sets the Preferences property for experimental features to True or False
3637 * depending on the state of the controlling menu item
3640 protected void showExperimental_actionPerformed(boolean selected)
3642 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3646 * Answers a (possibly empty) list of any structure viewer frames (currently for
3647 * either Jmol or Chimera) which are currently open. This may optionally be
3648 * restricted to viewers of a specified class, or viewers linked to a specified
3652 * if not null, only return viewers linked to this panel
3653 * @param structureViewerClass
3654 * if not null, only return viewers of this class
3657 public List<StructureViewerBase> getStructureViewers(
3658 AlignmentPanel apanel,
3659 Class<? extends StructureViewerBase> structureViewerClass)
3661 List<StructureViewerBase> result = new ArrayList<>();
3662 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3664 for (JInternalFrame frame : frames)
3666 if (frame instanceof StructureViewerBase)
3668 if (structureViewerClass == null
3669 || structureViewerClass.isInstance(frame))
3672 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3674 result.add((StructureViewerBase) frame);