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.util.dialogrunner.RunResponse;
50 import jalview.viewmodel.AlignmentViewport;
51 import jalview.ws.params.ParamManager;
52 import jalview.ws.utils.UrlDownloadClient;
54 import java.awt.BorderLayout;
55 import java.awt.Color;
56 import java.awt.Dimension;
57 import java.awt.FontMetrics;
58 import java.awt.Graphics;
59 import java.awt.GridLayout;
60 import java.awt.Point;
61 import java.awt.Rectangle;
62 import java.awt.Toolkit;
63 import java.awt.Window;
64 import java.awt.datatransfer.Clipboard;
65 import java.awt.datatransfer.ClipboardOwner;
66 import java.awt.datatransfer.DataFlavor;
67 import java.awt.datatransfer.Transferable;
68 import java.awt.dnd.DnDConstants;
69 import java.awt.dnd.DropTargetDragEvent;
70 import java.awt.dnd.DropTargetDropEvent;
71 import java.awt.dnd.DropTargetEvent;
72 import java.awt.dnd.DropTargetListener;
73 import java.awt.event.ActionEvent;
74 import java.awt.event.ActionListener;
75 import java.awt.event.InputEvent;
76 import java.awt.event.KeyEvent;
77 import java.awt.event.MouseAdapter;
78 import java.awt.event.MouseEvent;
79 import java.awt.event.WindowAdapter;
80 import java.awt.event.WindowEvent;
81 import java.beans.PropertyChangeEvent;
82 import java.beans.PropertyChangeListener;
83 import java.io.BufferedInputStream;
85 import java.io.FileOutputStream;
86 import java.io.IOException;
88 import java.util.ArrayList;
89 import java.util.Hashtable;
90 import java.util.List;
91 import java.util.ListIterator;
92 import java.util.StringTokenizer;
93 import java.util.Vector;
94 import java.util.concurrent.ExecutorService;
95 import java.util.concurrent.Executors;
96 import java.util.concurrent.Semaphore;
98 import javax.swing.AbstractAction;
99 import javax.swing.Action;
100 import javax.swing.ActionMap;
101 import javax.swing.Box;
102 import javax.swing.BoxLayout;
103 import javax.swing.DefaultDesktopManager;
104 import javax.swing.DesktopManager;
105 import javax.swing.InputMap;
106 import javax.swing.JButton;
107 import javax.swing.JCheckBox;
108 import javax.swing.JComboBox;
109 import javax.swing.JComponent;
110 import javax.swing.JDesktopPane;
111 import javax.swing.JFrame;
112 import javax.swing.JInternalFrame;
113 import javax.swing.JLabel;
114 import javax.swing.JMenuItem;
115 import javax.swing.JPanel;
116 import javax.swing.JPopupMenu;
117 import javax.swing.JProgressBar;
118 import javax.swing.KeyStroke;
119 import javax.swing.SwingUtilities;
120 import javax.swing.event.HyperlinkEvent;
121 import javax.swing.event.HyperlinkEvent.EventType;
122 import javax.swing.event.InternalFrameAdapter;
123 import javax.swing.event.InternalFrameEvent;
124 import javax.swing.event.MenuEvent;
125 import javax.swing.event.MenuListener;
127 import org.stackoverflowusers.file.WindowsShortcut;
134 * @version $Revision: 1.155 $
136 public class Desktop extends jalview.jbgui.GDesktop
137 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
138 jalview.api.StructureSelectionManagerProvider
140 private static int DEFAULT_MIN_WIDTH = 300;
142 private static int DEFAULT_MIN_HEIGHT = 250;
144 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
146 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
148 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
150 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
153 * news reader - null if it was never started.
155 private BlogReader jvnews = null;
157 private File projectFile;
161 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
163 public void addJalviewPropertyChangeListener(
164 PropertyChangeListener listener)
166 changeSupport.addJalviewPropertyChangeListener(listener);
170 * @param propertyName
172 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
173 * java.beans.PropertyChangeListener)
175 public void addJalviewPropertyChangeListener(String propertyName,
176 PropertyChangeListener listener)
178 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
182 * @param propertyName
184 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
185 * java.beans.PropertyChangeListener)
187 public void removeJalviewPropertyChangeListener(String propertyName,
188 PropertyChangeListener listener)
190 changeSupport.removeJalviewPropertyChangeListener(propertyName,
194 /** Singleton Desktop instance */
195 public static Desktop instance;
197 public static MyDesktopPane desktop;
199 public static MyDesktopPane getDesktop()
201 // BH 2018 could use currentThread() here as a reference to a
202 // Hashtable<Thread, MyDesktopPane> in JavaScript
206 static int openFrameCount = 0;
208 static final int xOffset = 30;
210 static final int yOffset = 30;
212 public static jalview.ws.jws1.Discoverer discoverer;
214 public static Object[] jalviewClipboard;
216 public static boolean internalCopy = false;
218 static int fileLoadingCount = 0;
220 class MyDesktopManager implements DesktopManager
223 private DesktopManager delegate;
225 public MyDesktopManager(DesktopManager delegate)
227 this.delegate = delegate;
231 public void activateFrame(JInternalFrame f)
235 delegate.activateFrame(f);
236 } catch (NullPointerException npe)
238 Point p = getMousePosition();
239 instance.showPasteMenu(p.x, p.y);
244 public void beginDraggingFrame(JComponent f)
246 delegate.beginDraggingFrame(f);
250 public void beginResizingFrame(JComponent f, int direction)
252 delegate.beginResizingFrame(f, direction);
256 public void closeFrame(JInternalFrame f)
258 delegate.closeFrame(f);
262 public void deactivateFrame(JInternalFrame f)
264 delegate.deactivateFrame(f);
268 public void deiconifyFrame(JInternalFrame f)
270 delegate.deiconifyFrame(f);
274 public void dragFrame(JComponent f, int newX, int newY)
280 delegate.dragFrame(f, newX, newY);
284 public void endDraggingFrame(JComponent f)
286 delegate.endDraggingFrame(f);
291 public void endResizingFrame(JComponent f)
293 delegate.endResizingFrame(f);
298 public void iconifyFrame(JInternalFrame f)
300 delegate.iconifyFrame(f);
304 public void maximizeFrame(JInternalFrame f)
306 delegate.maximizeFrame(f);
310 public void minimizeFrame(JInternalFrame f)
312 delegate.minimizeFrame(f);
316 public void openFrame(JInternalFrame f)
318 delegate.openFrame(f);
322 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
329 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
333 public void setBoundsForFrame(JComponent f, int newX, int newY,
334 int newWidth, int newHeight)
336 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
339 // All other methods, simply delegate
344 * 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);
366 showMemusage.setSelected(selmemusage);
367 desktop.setBackground(Color.white);
368 getContentPane().setLayout(new BorderLayout());
369 // alternate config - have scrollbars - see notes in JAL-153
370 // JScrollPane sp = new JScrollPane();
371 // sp.getViewport().setView(desktop);
372 // getContentPane().add(sp, BorderLayout.CENTER);
373 getContentPane().add(desktop, BorderLayout.CENTER);
374 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
376 // This line prevents Windows Look&Feel resizing all new windows to maximum
377 // if previous window was maximised
378 desktop.setDesktopManager(new MyDesktopManager(
379 (Platform.isWindows() ? new DefaultDesktopManager()
381 ? new AquaInternalFrameManager(
382 desktop.getDesktopManager())
383 : desktop.getDesktopManager())));
385 Rectangle dims = getLastKnownDimensions("");
392 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
393 int xPos = Math.max(5, (screenSize.width - 900) / 2);
394 int yPos = Math.max(5, (screenSize.height - 650) / 2);
395 setBounds(xPos, yPos, 900, 650);
404 jconsole = new Console(this, showjconsole);
405 // add essential build information
406 jconsole.setHeader("Jalview Version: "
407 + jalview.bin.Cache.getProperty("VERSION") + "\n"
408 + "Jalview Installation: "
409 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
410 + "\n" + "Build Date: "
411 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
412 + "Java version: " + System.getProperty("java.version") + "\n"
413 + System.getProperty("os.arch") + " "
414 + System.getProperty("os.name") + " "
415 + System.getProperty("os.version"));
417 showConsole(showjconsole);
419 showNews.setVisible(false);
421 experimentalFeatures.setSelected(showExperimental());
423 getIdentifiersOrgData();
427 // Spawn a thread that shows the splashscreen
429 SwingUtilities.invokeLater(new Runnable()
438 // Thread off a new instance of the file chooser - this reduces the time it
439 // takes to open it later on.
440 new Thread(new Runnable()
445 Cache.log.debug("Filechooser init thread started.");
446 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
447 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
449 Cache.log.debug("Filechooser init thread finished.");
452 // Add the service change listener
453 changeSupport.addJalviewPropertyChangeListener("services",
454 new PropertyChangeListener()
458 public void propertyChange(PropertyChangeEvent evt)
460 Cache.log.debug("Firing service changed event for "
461 + evt.getNewValue());
462 JalviewServicesChanged(evt);
467 } // end BH 2018 ignore
469 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
471 this.addWindowListener(new WindowAdapter()
474 public void windowClosing(WindowEvent evt)
481 this.addMouseListener(ma = new MouseAdapter()
484 public void mousePressed(MouseEvent evt)
486 if (evt.isPopupTrigger()) // Mac
488 showPasteMenu(evt.getX(), evt.getY());
493 public void mouseReleased(MouseEvent evt)
495 if (evt.isPopupTrigger()) // Windows
497 showPasteMenu(evt.getX(), evt.getY());
501 desktop.addMouseListener(ma);
506 * Answers true if user preferences to enable experimental features is True
511 public boolean showExperimental()
513 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
514 Boolean.FALSE.toString());
515 return Boolean.valueOf(experimental).booleanValue();
518 public void doConfigureStructurePrefs()
520 // configure services
521 StructureSelectionManager ssm = StructureSelectionManager
522 .getStructureSelectionManager(this);
523 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
525 ssm.setAddTempFacAnnot(jalview.bin.Cache
526 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
527 ssm.setProcessSecondaryStructure(jalview.bin.Cache
528 .getDefault(Preferences.STRUCT_FROM_PDB, true));
529 ssm.setSecStructServices(
530 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
534 ssm.setAddTempFacAnnot(false);
535 ssm.setProcessSecondaryStructure(false);
536 ssm.setSecStructServices(false);
540 public void checkForNews()
542 final Desktop me = this;
543 // Thread off the news reader, in case there are connection problems.
544 addDialogThread(new Runnable()
549 Cache.log.debug("Starting news thread.");
550 jvnews = new BlogReader(me);
551 showNews.setVisible(true);
552 Cache.log.debug("Completed news thread.");
557 public void getIdentifiersOrgData()
559 // Thread off the identifiers fetcher
560 addDialogThread(new Runnable()
565 Cache.log.debug("Downloading data from identifiers.org");
566 UrlDownloadClient client = new UrlDownloadClient();
569 client.download(IdOrgSettings.getUrl(),
570 IdOrgSettings.getDownloadLocation());
571 } catch (IOException e)
573 Cache.log.debug("Exception downloading identifiers.org data"
581 protected void showNews_actionPerformed(ActionEvent e)
583 showNews(showNews.isSelected());
586 void showNews(boolean visible)
588 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
589 showNews.setSelected(visible);
590 if (visible && !jvnews.isVisible())
592 new Thread(new Runnable()
597 long now = System.currentTimeMillis();
598 Desktop.instance.setProgressBar(
599 MessageManager.getString("status.refreshing_news"), now);
600 jvnews.refreshNews();
601 Desktop.instance.setProgressBar(null, now);
609 * recover the last known dimensions for a jalview window
612 * - empty string is desktop, all other windows have unique prefix
613 * @return null or last known dimensions scaled to current geometry (if last
614 * window geom was known)
616 Rectangle getLastKnownDimensions(String windowName)
618 // TODO: lock aspect ratio for scaling desktop Bug #0058199
619 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
620 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
621 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
622 String width = jalview.bin.Cache
623 .getProperty(windowName + "SCREEN_WIDTH");
624 String height = jalview.bin.Cache
625 .getProperty(windowName + "SCREEN_HEIGHT");
626 if ((x != null) && (y != null) && (width != null) && (height != null))
628 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
629 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
630 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
632 // attempt #1 - try to cope with change in screen geometry - this
633 // version doesn't preserve original jv aspect ratio.
634 // take ratio of current screen size vs original screen size.
635 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
636 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
637 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
638 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
639 // rescale the bounds depending upon the current screen geometry.
640 ix = (int) (ix * sw);
641 iw = (int) (iw * sw);
642 iy = (int) (iy * sh);
643 ih = (int) (ih * sh);
644 while (ix >= screenSize.width)
646 jalview.bin.Cache.log.debug(
647 "Window geometry location recall error: shifting horizontal to within screenbounds.");
648 ix -= screenSize.width;
650 while (iy >= screenSize.height)
652 jalview.bin.Cache.log.debug(
653 "Window geometry location recall error: shifting vertical to within screenbounds.");
654 iy -= screenSize.height;
656 jalview.bin.Cache.log.debug(
657 "Got last known dimensions for " + windowName + ": x:" + ix
658 + " y:" + iy + " width:" + iw + " height:" + ih);
660 // return dimensions for new instance
661 return new Rectangle(ix, iy, iw, ih);
666 private void doVamsasClientCheck()
668 if (Cache.vamsasJarsPresent())
670 setupVamsasDisconnectedGui();
671 VamsasMenu.setVisible(true);
672 final Desktop us = this;
673 VamsasMenu.addMenuListener(new MenuListener()
675 // this listener remembers when the menu was first selected, and
676 // doesn't rebuild the session list until it has been cleared and
678 boolean refresh = true;
681 public void menuCanceled(MenuEvent e)
687 public void menuDeselected(MenuEvent e)
693 public void menuSelected(MenuEvent e)
697 us.buildVamsasStMenu();
702 vamsasStart.setVisible(true);
706 void showPasteMenu(int x, int y)
708 JPopupMenu popup = new JPopupMenu();
709 JMenuItem item = new JMenuItem(
710 MessageManager.getString("label.paste_new_window"));
711 item.addActionListener(new ActionListener()
714 public void actionPerformed(ActionEvent evt)
721 popup.show(this, x, y);
728 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
729 Transferable contents = c.getContents(this);
731 if (contents != null)
733 String file = (String) contents
734 .getTransferData(DataFlavor.stringFlavor);
736 FileFormatI format = new IdentifyFile().identify(file,
737 DataSourceType.PASTE);
739 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
742 } catch (Exception ex)
745 "Unable to paste alignment from system clipboard:\n" + ex);
750 * Adds and opens the given frame to the desktop
761 public static synchronized void addInternalFrame(
762 final JInternalFrame frame, String title, int w, int h)
764 addInternalFrame(frame, title, true, w, h, true, false);
768 * Add an internal frame to the Jalview desktop
775 * When true, display frame immediately, otherwise, caller must call
776 * setVisible themselves.
782 public static synchronized void addInternalFrame(
783 final JInternalFrame frame, String title, boolean makeVisible,
786 addInternalFrame(frame, title, makeVisible, w, h, true, false);
790 * Add an internal frame to the Jalview desktop and make it visible
803 public static synchronized void addInternalFrame(
804 final JInternalFrame frame, String title, int w, int h,
807 addInternalFrame(frame, title, true, w, h, resizable, false);
811 * Add an internal frame to the Jalview desktop
818 * When true, display frame immediately, otherwise, caller must call
819 * setVisible themselves.
826 * @param ignoreMinSize
827 * Do not set the default minimum size for frame
829 public static synchronized void addInternalFrame(
830 final JInternalFrame frame, String title, boolean makeVisible,
831 int w, int h, boolean resizable, boolean ignoreMinSize)
834 // TODO: allow callers to determine X and Y position of frame (eg. via
836 // TODO: consider fixing method to update entries in the window submenu with
837 // the current window title
839 frame.setTitle(title);
840 if (frame.getWidth() < 1 || frame.getHeight() < 1)
844 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
845 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
846 // IF JALVIEW IS RUNNING HEADLESS
847 // ///////////////////////////////////////////////
848 if (instance == null || (System.getProperty("java.awt.headless") != null
849 && System.getProperty("java.awt.headless").equals("true")))
858 frame.setMinimumSize(
859 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
861 // Set default dimension for Alignment Frame window.
862 // The Alignment Frame window could be added from a number of places,
864 // I did this here in order not to miss out on any Alignment frame.
865 if (frame instanceof AlignFrame)
867 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
868 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
872 frame.setVisible(makeVisible);
873 frame.setClosable(true);
874 frame.setResizable(resizable);
875 frame.setMaximizable(resizable);
876 frame.setIconifiable(resizable);
877 frame.setOpaque(/** @j2sNative true || */
880 if (frame.getX() < 1 && frame.getY() < 1)
882 frame.setLocation(xOffset * openFrameCount,
883 yOffset * ((openFrameCount - 1) % 10) + yOffset);
887 * add an entry for the new frame in the Window menu
888 * (and remove it when the frame is closed)
890 final JMenuItem menuItem = new JMenuItem(title);
891 frame.addInternalFrameListener(new InternalFrameAdapter()
894 public void internalFrameActivated(InternalFrameEvent evt)
896 JInternalFrame itf = desktop.getSelectedFrame();
899 if (itf instanceof AlignFrame)
901 Jalview.setCurrentAlignFrame((AlignFrame) itf);
908 public void internalFrameClosed(InternalFrameEvent evt)
910 PaintRefresher.RemoveComponent(frame);
913 * defensive check to prevent frames being
914 * added half off the window
916 if (openFrameCount > 0)
922 * ensure no reference to alignFrame retained by menu item listener
924 if (menuItem.getActionListeners().length > 0)
926 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
928 windowMenu.remove(menuItem);
932 menuItem.addActionListener(new ActionListener()
935 public void actionPerformed(ActionEvent e)
939 frame.setSelected(true);
940 frame.setIcon(false);
941 } catch (java.beans.PropertyVetoException ex)
943 // System.err.println(ex.toString());
948 setKeyBindings(frame);
952 windowMenu.add(menuItem);
957 frame.setSelected(true);
958 frame.requestFocus();
959 } catch (java.beans.PropertyVetoException ve)
961 } catch (java.lang.ClassCastException cex)
964 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
970 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
975 private static void setKeyBindings(JInternalFrame frame)
977 @SuppressWarnings("serial")
978 final Action closeAction = new AbstractAction()
981 public void actionPerformed(ActionEvent e)
988 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
990 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
991 InputEvent.CTRL_DOWN_MASK);
992 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
993 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
995 InputMap inputMap = frame
996 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
997 String ctrlW = ctrlWKey.toString();
998 inputMap.put(ctrlWKey, ctrlW);
999 inputMap.put(cmdWKey, ctrlW);
1001 ActionMap actionMap = frame.getActionMap();
1002 actionMap.put(ctrlW, closeAction);
1006 public void lostOwnership(Clipboard clipboard, Transferable contents)
1010 Desktop.jalviewClipboard = null;
1013 internalCopy = false;
1017 public void dragEnter(DropTargetDragEvent evt)
1022 public void dragExit(DropTargetEvent evt)
1027 public void dragOver(DropTargetDragEvent evt)
1032 public void dropActionChanged(DropTargetDragEvent evt)
1043 public void drop(DropTargetDropEvent evt)
1045 boolean success = true;
1046 // JAL-1552 - acceptDrop required before getTransferable call for
1047 // Java's Transferable for native dnd
1048 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1049 Transferable t = evt.getTransferable();
1050 List<Object> files = new ArrayList<>();
1051 List<DataSourceType> protocols = new ArrayList<>();
1055 Desktop.transferFromDropTarget(files, protocols, evt, t);
1056 } catch (Exception e)
1058 e.printStackTrace();
1066 for (int i = 0; i < files.size(); i++)
1068 // BH 2018 File or String
1069 Object file = files.get(i);
1070 String fileName = file.toString();
1071 DataSourceType protocol = (protocols == null)
1072 ? DataSourceType.FILE
1074 FileFormatI format = null;
1076 if (fileName.endsWith(".jar"))
1078 format = FileFormat.Jalview;
1083 format = new IdentifyFile().identify(file, protocol);
1086 new FileLoader().LoadFile(null, file, protocol, format);
1089 } catch (Exception ex)
1094 evt.dropComplete(success); // need this to ensure input focus is properly
1095 // transfered to any new windows created
1105 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1107 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1108 JalviewFileChooser chooser = JalviewFileChooser
1109 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1111 chooser.setFileView(new JalviewFileView());
1112 chooser.setDialogTitle(
1113 MessageManager.getString("label.open_local_file"));
1114 chooser.setToolTipText(MessageManager.getString("action.open"));
1116 chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION)
1122 File selectedFile = chooser.getSelectedFile();
1123 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1125 FileFormatI format = chooser.getSelectedFormat();
1128 * Call IdentifyFile to verify the file contains what its extension implies.
1129 * Skip this step for dynamically added file formats, because
1130 * IdentifyFile does not know how to recognise them.
1132 if (FileFormats.getInstance().isIdentifiable(format))
1136 format = new IdentifyFile().identify(selectedFile,
1137 DataSourceType.FILE);
1138 } catch (FileFormatException e)
1140 // format = null; //??
1144 new FileLoader().LoadFile(viewport, selectedFile,
1145 DataSourceType.FILE, format);
1147 }).openDialog(this);
1157 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1159 // This construct allows us to have a wider textfield
1161 JLabel label = new JLabel(
1162 MessageManager.getString("label.input_file_url"));
1164 JComboBox history = new JComboBox();
1165 JPanel panel = new JPanel(new GridLayout(2, 1));
1168 history.setPreferredSize(new Dimension(400, 20));
1169 history.setEditable(true);
1170 history.addItem("http://www.");
1172 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1176 if (historyItems != null)
1178 st = new StringTokenizer(historyItems, "\t");
1180 while (st.hasMoreTokens())
1182 history.addItem(st.nextElement());
1186 // BH 2018 -- providing a callback for SwingJS
1187 // dialogOption is just a simple way to provide
1188 // context for the modal-like response.
1189 // The only requirement is that desktop implement
1190 // PropertyChangeListener, which is used already in Java
1191 // for changes in input value and such within the dialogs.
1193 String dialogOption = "label.input_alignment_from_url";
1194 desktop.dialogData = new Object[] { dialogOption, viewport, history };
1195 desktop.onDialogReturn(JvOptionPane.showInternalConfirmDialog(desktop,
1196 panel, MessageManager.getString(dialogOption),
1197 JvOptionPane.OK_CANCEL_OPTION));
1199 // no code may follow this, as SwingJS will not block
1200 // callback in JavaScript comes via a property change event,
1201 // thus going into desktop.onDialogReturn(int) just the same as
1207 * Opens the CutAndPaste window for the user to paste an alignment in to
1210 * - if not null, the pasted alignment is added to the current
1211 * alignment; if null, to a new alignment window
1214 public void inputTextboxMenuItem_actionPerformed(
1215 AlignmentViewPanel viewPanel)
1217 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1218 cap.setForInput(viewPanel);
1219 Desktop.addInternalFrame(cap,
1220 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1230 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1231 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1233 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1234 screen.height + "");
1235 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1236 getWidth(), getHeight()));
1238 if (jconsole != null)
1240 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1241 jconsole.stopConsole();
1245 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1248 if (dialogExecutor != null)
1250 dialogExecutor.shutdownNow();
1252 closeAll_actionPerformed(null);
1254 if (groovyConsole != null)
1256 // suppress a possible repeat prompt to save script
1257 groovyConsole.setDirty(false);
1258 groovyConsole.exit();
1263 private void storeLastKnownDimensions(String string, Rectangle jc)
1265 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1266 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1267 + " height:" + jc.height);
1269 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1270 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1271 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1272 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1282 public void aboutMenuItem_actionPerformed(ActionEvent e)
1284 // StringBuffer message = getAboutMessage(false);
1285 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1287 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1288 new Thread(new Runnable()
1293 new SplashScreen(true);
1298 public StringBuffer getAboutMessage(boolean shortv)
1300 StringBuffer message = new StringBuffer();
1301 message.append("<html>");
1304 message.append("<h1><strong>Version: "
1305 + jalview.bin.Cache.getProperty("VERSION")
1306 + "</strong></h1>");
1307 message.append("<strong>Last Updated: <em>"
1308 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1309 + "</em></strong>");
1315 message.append("<strong>Version "
1316 + jalview.bin.Cache.getProperty("VERSION")
1317 + "; last updated: "
1318 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1321 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1322 .equals("Checking"))
1324 message.append("<br>...Checking latest version...</br>");
1326 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1327 .equals(jalview.bin.Cache.getProperty("VERSION")))
1329 boolean red = false;
1330 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1331 .indexOf("automated build") == -1)
1334 // Displayed when code version and jnlp version do not match and code
1335 // version is not a development build
1336 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1339 message.append("<br>!! Version "
1340 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1342 + " is available for download from "
1343 + jalview.bin.Cache.getDefault("www.jalview.org",
1344 "http://www.jalview.org")
1348 message.append("</div>");
1351 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1353 "The Jalview Authors (See AUTHORS file for current list)")
1354 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1355 + "<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"
1356 + "<br><br>If you use Jalview, please cite:"
1357 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1358 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1359 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1365 * Action on requesting Help documentation
1368 public void documentationMenuItem_actionPerformed()
1374 BrowserLauncher.openURL("http://www.jalview.org/help.html");
1378 Help.showHelpWindow();
1380 } catch (Exception ex)
1382 System.err.println("Error opening help: " + ex.getMessage());
1387 public void closeAll_actionPerformed(ActionEvent e)
1389 // TODO show a progress bar while closing?
1390 JInternalFrame[] frames = desktop.getAllFrames();
1391 for (int i = 0; i < frames.length; i++)
1395 frames[i].setClosed(true);
1396 } catch (java.beans.PropertyVetoException ex)
1400 Jalview.setCurrentAlignFrame(null);
1401 System.out.println("ALL CLOSED");
1402 if (v_client != null)
1404 // TODO clear binding to vamsas document objects on close_all
1408 * reset state of singleton objects as appropriate (clear down session state
1409 * when all windows are closed)
1411 StructureSelectionManager ssm = StructureSelectionManager
1412 .getStructureSelectionManager(this);
1420 public void raiseRelated_actionPerformed(ActionEvent e)
1422 reorderAssociatedWindows(false, false);
1426 public void minimizeAssociated_actionPerformed(ActionEvent e)
1428 reorderAssociatedWindows(true, false);
1431 void closeAssociatedWindows()
1433 reorderAssociatedWindows(false, true);
1439 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1443 protected void garbageCollect_actionPerformed(ActionEvent e)
1445 // We simply collect the garbage
1446 jalview.bin.Cache.log.debug("Collecting garbage...");
1448 jalview.bin.Cache.log.debug("Finished garbage collection.");
1455 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1459 protected void showMemusage_actionPerformed(ActionEvent e)
1461 desktop.showMemoryUsage(showMemusage.isSelected());
1468 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1472 protected void showConsole_actionPerformed(ActionEvent e)
1474 showConsole(showConsole.isSelected());
1477 Console jconsole = null;
1480 * control whether the java console is visible or not
1484 void showConsole(boolean selected)
1486 // TODO: decide if we should update properties file
1487 if (jconsole != null) // BH 2018
1489 showConsole.setSelected(selected);
1490 Cache.setProperty("SHOW_JAVA_CONSOLE",
1491 Boolean.valueOf(selected).toString());
1492 jconsole.setVisible(selected);
1496 void reorderAssociatedWindows(boolean minimize, boolean close)
1498 JInternalFrame[] frames = desktop.getAllFrames();
1499 if (frames == null || frames.length < 1)
1504 AlignmentViewport source = null, target = null;
1505 if (frames[0] instanceof AlignFrame)
1507 source = ((AlignFrame) frames[0]).getCurrentView();
1509 else if (frames[0] instanceof TreePanel)
1511 source = ((TreePanel) frames[0]).getViewPort();
1513 else if (frames[0] instanceof PCAPanel)
1515 source = ((PCAPanel) frames[0]).av;
1517 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1519 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1524 for (int i = 0; i < frames.length; i++)
1527 if (frames[i] == null)
1531 if (frames[i] instanceof AlignFrame)
1533 target = ((AlignFrame) frames[i]).getCurrentView();
1535 else if (frames[i] instanceof TreePanel)
1537 target = ((TreePanel) frames[i]).getViewPort();
1539 else if (frames[i] instanceof PCAPanel)
1541 target = ((PCAPanel) frames[i]).av;
1543 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1545 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1548 if (source == target)
1554 frames[i].setClosed(true);
1558 frames[i].setIcon(minimize);
1561 frames[i].toFront();
1565 } catch (java.beans.PropertyVetoException ex)
1580 protected void preferences_actionPerformed(ActionEvent e)
1586 * Prompts the user to choose a file and then saves the Jalview state as a
1587 * Jalview project file
1590 public void saveState_actionPerformed()
1592 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1595 chooser.setFileView(new JalviewFileView());
1596 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1598 int value = chooser.showSaveDialog(this);
1600 if (value == JalviewFileChooser.APPROVE_OPTION)
1602 final Desktop me = this;
1603 final java.io.File choice = chooser.getSelectedFile();
1604 setProjectFile(choice);
1606 new Thread(new Runnable()
1611 // TODO: refactor to Jalview desktop session controller action.
1612 setProgressBar(MessageManager.formatMessage(
1613 "label.saving_jalview_project", new Object[]
1614 { choice.getName() }), choice.hashCode());
1615 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1616 choice.getParent());
1617 // TODO catch and handle errors for savestate
1618 // TODO prevent user from messing with the Desktop whilst we're saving
1621 new Jalview2XML().saveState(choice);
1622 } catch (OutOfMemoryError oom)
1625 "Whilst saving current state to " + choice.getName(),
1627 } catch (Exception ex)
1630 "Problems whilst trying to save to " + choice.getName(),
1632 JvOptionPane.showMessageDialog(me,
1633 MessageManager.formatMessage(
1634 "label.error_whilst_saving_current_state_to",
1636 { choice.getName() }),
1637 MessageManager.getString("label.couldnt_save_project"),
1638 JvOptionPane.WARNING_MESSAGE);
1640 setProgressBar(null, choice.hashCode());
1646 private void setProjectFile(File choice)
1648 this.projectFile = choice;
1651 public File getProjectFile()
1653 return this.projectFile;
1657 * Prompts the user to choose a file and loads in as a Jalview project file
1660 public void loadState_actionPerformed()
1662 JalviewFileChooser chooser = new JalviewFileChooser(
1663 Cache.getProperty("LAST_DIRECTORY"), new String[]
1666 { "Jalview Project", "Jalview Project (old)" },
1668 chooser.setFileView(new JalviewFileView());
1669 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1671 int value = chooser.showOpenDialog(this);
1673 if (value == JalviewFileChooser.APPROVE_OPTION)
1675 final File selectedFile = chooser.getSelectedFile();
1676 setProjectFile(selectedFile);
1677 final String choice = selectedFile.getAbsolutePath();
1678 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1679 new Thread(new Runnable()
1684 setProgressBar(MessageManager.formatMessage(
1685 "label.loading_jalview_project", new Object[]
1686 { choice }), choice.hashCode());
1689 new Jalview2XML().loadJalviewAlign(choice);
1690 } catch (OutOfMemoryError oom)
1692 new OOMWarning("Whilst loading project from " + choice, oom);
1693 } catch (Exception ex)
1696 "Problems whilst loading project from " + choice, ex);
1697 JvOptionPane.showMessageDialog(Desktop.desktop,
1698 MessageManager.formatMessage(
1699 "label.error_whilst_loading_project_from",
1702 MessageManager.getString("label.couldnt_load_project"),
1703 JvOptionPane.WARNING_MESSAGE);
1705 setProgressBar(null, choice.hashCode());
1712 public void inputSequence_actionPerformed(ActionEvent e)
1714 new SequenceFetcher(this);
1717 JPanel progressPanel;
1719 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1721 public void startLoading(final Object fileName)
1723 if (fileLoadingCount == 0)
1725 fileLoadingPanels.add(addProgressPanel(MessageManager
1726 .formatMessage("label.loading_file", new Object[]
1732 private JPanel addProgressPanel(String string)
1734 if (progressPanel == null)
1736 progressPanel = new JPanel(new GridLayout(1, 1));
1737 totalProgressCount = 0;
1738 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1740 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1741 JProgressBar progressBar = new JProgressBar();
1742 progressBar.setIndeterminate(true);
1744 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1746 thisprogress.add(progressBar, BorderLayout.CENTER);
1747 progressPanel.add(thisprogress);
1748 ((GridLayout) progressPanel.getLayout()).setRows(
1749 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1750 ++totalProgressCount;
1751 instance.validate();
1752 return thisprogress;
1755 int totalProgressCount = 0;
1757 private void removeProgressPanel(JPanel progbar)
1759 if (progressPanel != null)
1761 synchronized (progressPanel)
1763 progressPanel.remove(progbar);
1764 GridLayout gl = (GridLayout) progressPanel.getLayout();
1765 gl.setRows(gl.getRows() - 1);
1766 if (--totalProgressCount < 1)
1768 this.getContentPane().remove(progressPanel);
1769 progressPanel = null;
1776 public void stopLoading()
1779 if (fileLoadingCount < 1)
1781 while (fileLoadingPanels.size() > 0)
1783 removeProgressPanel(fileLoadingPanels.remove(0));
1785 fileLoadingPanels.clear();
1786 fileLoadingCount = 0;
1791 public static int getViewCount(String alignmentId)
1793 AlignmentViewport[] aps = getViewports(alignmentId);
1794 return (aps == null) ? 0 : aps.length;
1799 * @param alignmentId
1800 * - if null, all sets are returned
1801 * @return all AlignmentPanels concerning the alignmentId sequence set
1803 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1805 if (Desktop.desktop == null)
1807 // no frames created and in headless mode
1808 // TODO: verify that frames are recoverable when in headless mode
1811 List<AlignmentPanel> aps = new ArrayList<>();
1812 AlignFrame[] frames = getAlignFrames();
1817 for (AlignFrame af : frames)
1819 for (AlignmentPanel ap : af.alignPanels)
1821 if (alignmentId == null
1822 || alignmentId.equals(ap.av.getSequenceSetId()))
1828 if (aps.size() == 0)
1832 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1837 * get all the viewports on an alignment.
1839 * @param sequenceSetId
1840 * unique alignment id (may be null - all viewports returned in that
1842 * @return all viewports on the alignment bound to sequenceSetId
1844 public static AlignmentViewport[] getViewports(String sequenceSetId)
1846 List<AlignmentViewport> viewp = new ArrayList<>();
1847 if (desktop != null)
1849 AlignFrame[] frames = Desktop.getAlignFrames();
1851 for (AlignFrame afr : frames)
1853 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1854 .equals(sequenceSetId))
1856 if (afr.alignPanels != null)
1858 for (AlignmentPanel ap : afr.alignPanels)
1860 if (sequenceSetId == null
1861 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1869 viewp.add(afr.getViewport());
1873 if (viewp.size() > 0)
1875 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1882 * Explode the views in the given frame into separate AlignFrame
1886 public static void explodeViews(AlignFrame af)
1888 int size = af.alignPanels.size();
1894 for (int i = 0; i < size; i++)
1896 AlignmentPanel ap = af.alignPanels.get(i);
1897 AlignFrame newaf = new AlignFrame(ap);
1900 * Restore the view's last exploded frame geometry if known. Multiple
1901 * views from one exploded frame share and restore the same (frame)
1902 * position and size.
1904 Rectangle geometry = ap.av.getExplodedGeometry();
1905 if (geometry != null)
1907 newaf.setBounds(geometry);
1910 ap.av.setGatherViewsHere(false);
1912 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1913 AlignFrame.DEFAULT_HEIGHT);
1916 af.alignPanels.clear();
1917 af.closeMenuItem_actionPerformed(true);
1922 * Gather expanded views (separate AlignFrame's) with the same sequence set
1923 * identifier back in to this frame as additional views, and close the expanded
1924 * views. Note the expanded frames may themselves have multiple views. We take
1929 public void gatherViews(AlignFrame source)
1931 source.viewport.setGatherViewsHere(true);
1932 source.viewport.setExplodedGeometry(source.getBounds());
1933 JInternalFrame[] frames = desktop.getAllFrames();
1934 String viewId = source.viewport.getSequenceSetId();
1936 for (int t = 0; t < frames.length; t++)
1938 if (frames[t] instanceof AlignFrame && frames[t] != source)
1940 AlignFrame af = (AlignFrame) frames[t];
1941 boolean gatherThis = false;
1942 for (int a = 0; a < af.alignPanels.size(); a++)
1944 AlignmentPanel ap = af.alignPanels.get(a);
1945 if (viewId.equals(ap.av.getSequenceSetId()))
1948 ap.av.setGatherViewsHere(false);
1949 ap.av.setExplodedGeometry(af.getBounds());
1950 source.addAlignmentPanel(ap, false);
1956 af.alignPanels.clear();
1957 af.closeMenuItem_actionPerformed(true);
1964 jalview.gui.VamsasApplication v_client = null;
1967 public void vamsasImport_actionPerformed(ActionEvent e)
1969 // TODO: JAL-3048 not needed for Jalview-JS
1971 if (v_client == null)
1973 // Load and try to start a session.
1974 JalviewFileChooser chooser = new JalviewFileChooser(
1975 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
1977 chooser.setFileView(new JalviewFileView());
1978 chooser.setDialogTitle(
1979 MessageManager.getString("label.open_saved_vamsas_session"));
1980 chooser.setToolTipText(MessageManager.getString(
1981 "label.select_vamsas_session_opened_as_new_vamsas_session"));
1983 int value = chooser.showOpenDialog(this);
1985 if (value == JalviewFileChooser.APPROVE_OPTION)
1987 String fle = chooser.getSelectedFile().toString();
1988 if (!vamsasImport(chooser.getSelectedFile()))
1990 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1991 MessageManager.formatMessage(
1992 "label.couldnt_import_as_vamsas_session",
1996 .getString("label.vamsas_document_import_failed"),
1997 JvOptionPane.ERROR_MESSAGE);
2003 jalview.bin.Cache.log.error(
2004 "Implementation error - load session from a running session is not supported.");
2009 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2012 * @return true if import was a success and a session was started.
2014 public boolean vamsasImport(URL url)
2016 // TODO: create progress bar
2017 if (v_client != null)
2020 jalview.bin.Cache.log.error(
2021 "Implementation error - load session from a running session is not supported.");
2027 // copy the URL content to a temporary local file
2028 // TODO: be a bit cleverer here with nio (?!)
2029 File file = File.createTempFile("vdocfromurl", ".vdj");
2030 FileOutputStream fos = new FileOutputStream(file);
2031 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2032 byte[] buffer = new byte[2048];
2034 while ((ln = bis.read(buffer)) > -1)
2036 fos.write(buffer, 0, ln);
2040 v_client = new jalview.gui.VamsasApplication(this, file,
2041 url.toExternalForm());
2042 } catch (Exception ex)
2044 jalview.bin.Cache.log.error(
2045 "Failed to create new vamsas session from contents of URL "
2050 setupVamsasConnectedGui();
2051 v_client.initial_update(); // TODO: thread ?
2052 return v_client.inSession();
2056 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2059 * @return true if import was a success and a session was started.
2061 public boolean vamsasImport(File file)
2063 if (v_client != null)
2066 jalview.bin.Cache.log.error(
2067 "Implementation error - load session from a running session is not supported.");
2071 setProgressBar(MessageManager.formatMessage(
2072 "status.importing_vamsas_session_from", new Object[]
2073 { file.getName() }), file.hashCode());
2076 v_client = new jalview.gui.VamsasApplication(this, file, null);
2077 } catch (Exception ex)
2079 setProgressBar(MessageManager.formatMessage(
2080 "status.importing_vamsas_session_from", new Object[]
2081 { file.getName() }), file.hashCode());
2082 jalview.bin.Cache.log.error(
2083 "New vamsas session from existing session file failed:", ex);
2086 setupVamsasConnectedGui();
2087 v_client.initial_update(); // TODO: thread ?
2088 setProgressBar(MessageManager.formatMessage(
2089 "status.importing_vamsas_session_from", new Object[]
2090 { file.getName() }), file.hashCode());
2091 return v_client.inSession();
2094 public boolean joinVamsasSession(String mysesid)
2096 if (v_client != null)
2098 throw new Error(MessageManager
2099 .getString("error.try_join_vamsas_session_another"));
2101 if (mysesid == null)
2104 MessageManager.getString("error.invalid_vamsas_session_id"));
2106 v_client = new VamsasApplication(this, mysesid);
2107 setupVamsasConnectedGui();
2108 v_client.initial_update();
2109 return (v_client.inSession());
2113 public void vamsasStart_actionPerformed(ActionEvent e)
2115 if (v_client == null)
2118 // we just start a default session for moment.
2120 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2121 * getProperty("LAST_DIRECTORY"));
2123 * chooser.setFileView(new JalviewFileView());
2124 * chooser.setDialogTitle("Load Vamsas file");
2125 * chooser.setToolTipText("Import");
2127 * int value = chooser.showOpenDialog(this);
2129 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2130 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2132 v_client = new VamsasApplication(this);
2133 setupVamsasConnectedGui();
2134 v_client.initial_update(); // TODO: thread ?
2138 // store current data in session.
2139 v_client.push_update(); // TODO: thread
2143 protected void setupVamsasConnectedGui()
2145 vamsasStart.setText(MessageManager.getString("label.session_update"));
2146 vamsasSave.setVisible(true);
2147 vamsasStop.setVisible(true);
2148 vamsasImport.setVisible(false); // Document import to existing session is
2149 // not possible for vamsas-client-1.0.
2152 protected void setupVamsasDisconnectedGui()
2154 vamsasSave.setVisible(false);
2155 vamsasStop.setVisible(false);
2156 vamsasImport.setVisible(true);
2158 .setText(MessageManager.getString("label.new_vamsas_session"));
2162 public void vamsasStop_actionPerformed(ActionEvent e)
2164 if (v_client != null)
2166 v_client.end_session();
2168 setupVamsasDisconnectedGui();
2172 protected void buildVamsasStMenu()
2174 if (v_client == null)
2176 String[] sess = null;
2179 sess = VamsasApplication.getSessionList();
2180 } catch (Exception e)
2182 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2188 jalview.bin.Cache.log.debug(
2189 "Got current sessions list: " + sess.length + " entries.");
2190 VamsasStMenu.removeAll();
2191 for (int i = 0; i < sess.length; i++)
2193 JMenuItem sessit = new JMenuItem();
2194 sessit.setText(sess[i]);
2195 sessit.setToolTipText(MessageManager
2196 .formatMessage("label.connect_to_session", new Object[]
2198 final Desktop dsktp = this;
2199 final String mysesid = sess[i];
2200 sessit.addActionListener(new ActionListener()
2204 public void actionPerformed(ActionEvent e)
2206 if (dsktp.v_client == null)
2208 Thread rthr = new Thread(new Runnable()
2214 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2215 dsktp.setupVamsasConnectedGui();
2216 dsktp.v_client.initial_update();
2224 VamsasStMenu.add(sessit);
2226 // don't show an empty menu.
2227 VamsasStMenu.setVisible(sess.length > 0);
2232 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2233 VamsasStMenu.removeAll();
2234 VamsasStMenu.setVisible(false);
2239 // Not interested in the content. Just hide ourselves.
2240 VamsasStMenu.setVisible(false);
2245 public void vamsasSave_actionPerformed(ActionEvent e)
2247 // TODO: JAL-3048 not needed for Jalview-JS
2249 if (v_client != null)
2251 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2252 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2255 chooser.setFileView(new JalviewFileView());
2256 chooser.setDialogTitle(MessageManager
2257 .getString("label.save_vamsas_document_archive"));
2259 int value = chooser.showSaveDialog(this);
2261 if (value == JalviewFileChooser.APPROVE_OPTION)
2263 java.io.File choice = chooser.getSelectedFile();
2264 JPanel progpanel = addProgressPanel(MessageManager
2265 .formatMessage("label.saving_vamsas_doc", new Object[]
2266 { choice.getName() }));
2267 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2268 String warnmsg = null;
2269 String warnttl = null;
2272 v_client.vclient.storeDocument(choice);
2275 warnttl = "Serious Problem saving Vamsas Document";
2276 warnmsg = ex.toString();
2277 jalview.bin.Cache.log
2278 .error("Error Whilst saving document to " + choice, ex);
2280 } catch (Exception ex)
2282 warnttl = "Problem saving Vamsas Document.";
2283 warnmsg = ex.toString();
2284 jalview.bin.Cache.log.warn(
2285 "Exception Whilst saving document to " + choice, ex);
2288 removeProgressPanel(progpanel);
2289 if (warnmsg != null)
2291 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2293 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2299 JPanel vamUpdate = null;
2302 * hide vamsas user gui bits when a vamsas document event is being handled.
2305 * true to hide gui, false to reveal gui
2307 public void setVamsasUpdate(boolean b)
2309 Cache.log.debug("Setting gui for Vamsas update "
2310 + (b ? "in progress" : "finished"));
2312 if (vamUpdate != null)
2314 this.removeProgressPanel(vamUpdate);
2318 vamUpdate = this.addProgressPanel(
2319 MessageManager.getString("label.updating_vamsas_session"));
2321 vamsasStart.setVisible(!b);
2322 vamsasStop.setVisible(!b);
2323 vamsasSave.setVisible(!b);
2326 public JInternalFrame[] getAllFrames()
2328 return desktop.getAllFrames();
2332 * Checks the given url to see if it gives a response indicating that the user
2333 * should be informed of a new questionnaire.
2337 public void checkForQuestionnaire(String url)
2339 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2340 // javax.swing.SwingUtilities.invokeLater(jvq);
2341 new Thread(jvq).start();
2344 public void checkURLLinks()
2346 // Thread off the URL link checker
2347 addDialogThread(new Runnable()
2352 if (Cache.getDefault("CHECKURLLINKS", true))
2354 // check what the actual links are - if it's just the default don't
2355 // bother with the warning
2356 List<String> links = Preferences.sequenceUrlLinks
2359 // only need to check links if there is one with a
2360 // SEQUENCE_ID which is not the default EMBL_EBI link
2361 ListIterator<String> li = links.listIterator();
2362 boolean check = false;
2363 List<JLabel> urls = new ArrayList<>();
2364 while (li.hasNext())
2366 String link = li.next();
2367 if (link.contains(SEQUENCE_ID)
2368 && !UrlConstants.isDefaultString(link))
2371 int barPos = link.indexOf("|");
2372 String urlMsg = barPos == -1 ? link
2373 : link.substring(0, barPos) + ": "
2374 + link.substring(barPos + 1);
2375 urls.add(new JLabel(urlMsg));
2383 // ask user to check in case URL links use old style tokens
2384 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2385 JPanel msgPanel = new JPanel();
2386 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2387 msgPanel.add(Box.createVerticalGlue());
2388 JLabel msg = new JLabel(MessageManager
2389 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2390 JLabel msg2 = new JLabel(MessageManager
2391 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2393 for (JLabel url : urls)
2399 final JCheckBox jcb = new JCheckBox(
2400 MessageManager.getString("label.do_not_display_again"));
2401 jcb.addActionListener(new ActionListener()
2404 public void actionPerformed(ActionEvent e)
2406 // update Cache settings for "don't show this again"
2407 boolean showWarningAgain = !jcb.isSelected();
2408 Cache.setProperty("CHECKURLLINKS",
2409 Boolean.valueOf(showWarningAgain).toString());
2414 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2416 .getString("label.SEQUENCE_ID_no_longer_used"),
2417 JvOptionPane.WARNING_MESSAGE);
2424 * Proxy class for JDesktopPane which optionally displays the current memory
2425 * usage and highlights the desktop area with a red bar if free memory runs low.
2429 public class MyDesktopPane extends JDesktopPane
2430 implements Runnable, PropertyChangeListener
2433 public Object[] dialogData;
2437 public void propertyChange(PropertyChangeEvent event)
2439 // TODO this is obsolete with JAL-3048 - delete?
2440 Object val = event.getNewValue();
2441 String name = event.getPropertyName();
2442 System.out.println(name);
2443 switch (event.getSource().getClass().getName())
2445 case "javax.swing.JOptionPane":
2449 onDialogReturn(val);
2452 if (val instanceof Integer)
2454 onDialogReturn(((Integer) val).intValue());
2458 onDialogReturn(val);
2463 case "javax.swing.JFileChooser":
2466 case "SelectedFile":
2467 // in JavaScript, this File object will have a _bytes property,
2468 // because the file data has already been loaded
2469 onDialogReturn(new Object[] { (File) val });
2474 System.out.println(event.getSource().getClass().getName() + " "
2475 + event.getPropertyName() + ": " + event.getNewValue());
2478 // JSCOmponent.DialogCaller interface
2479 void onDialogReturn(Object value)
2481 switch ((String) dialogData[0])
2483 case "SelectedFile":
2485 dialogData[0] = value;
2486 ((Runnable) dialogData[1]).run();
2492 // JSCOmponent.DialogCaller interface
2493 void onDialogReturn(int value)
2495 if (value != Math.floor(value))
2497 // in JavaScript, this will be NaN, oddly enough
2501 switch ((String) dialogData[0])
2504 dialogData[0] = Integer.valueOf(value);
2505 ((Runnable) dialogData[1]).run();
2507 case "label.input_alignment_from_url":
2508 // reconstruct the parameter data
2510 AlignViewport viewport = (AlignViewport) dialogData[1];
2511 JComboBox history = (JComboBox) dialogData[2];
2512 // the rest of this is unchangaed
2513 if (reply != JvOptionPane.OK_OPTION)
2518 String url = history.getSelectedItem().toString();
2520 if (url.toLowerCase().endsWith(".jar"))
2522 if (viewport != null)
2524 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2525 FileFormat.Jalview);
2529 new FileLoader().LoadFile(url, DataSourceType.URL,
2530 FileFormat.Jalview);
2535 FileFormatI format = null;
2538 format = new IdentifyFile().identify(url, DataSourceType.URL);
2539 } catch (FileFormatException e)
2541 // TODO revise error handling, distinguish between
2542 // URL not found and response not valid
2547 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2548 MessageManager.formatMessage("label.couldnt_locate",
2551 MessageManager.getString("label.url_not_found"),
2552 JvOptionPane.WARNING_MESSAGE);
2557 if (viewport != null)
2559 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2564 new FileLoader().LoadFile(url, DataSourceType.URL, format);
2573 private static final float ONE_MB = 1048576f;
2575 boolean showMemoryUsage = false;
2579 java.text.NumberFormat df;
2581 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2584 public MyDesktopPane(boolean showMemoryUsage)
2586 showMemoryUsage(showMemoryUsage);
2589 public void showMemoryUsage(boolean showMemory)
2591 this.showMemoryUsage = showMemory;
2594 Thread worker = new Thread(this);
2600 public boolean isShowMemoryUsage()
2602 return showMemoryUsage;
2608 df = java.text.NumberFormat.getNumberInstance();
2609 df.setMaximumFractionDigits(2);
2610 runtime = Runtime.getRuntime();
2612 while (showMemoryUsage)
2616 maxMemory = runtime.maxMemory() / ONE_MB;
2617 allocatedMemory = runtime.totalMemory() / ONE_MB;
2618 freeMemory = runtime.freeMemory() / ONE_MB;
2619 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2621 percentUsage = (totalFreeMemory / maxMemory) * 100;
2623 // if (percentUsage < 20)
2625 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2627 // instance.set.setBorder(border1);
2630 // sleep after showing usage
2632 } catch (Exception ex)
2634 ex.printStackTrace();
2640 public void paintComponent(Graphics g)
2642 if (showMemoryUsage && g != null && df != null)
2644 if (percentUsage < 20)
2646 g.setColor(Color.red);
2648 FontMetrics fm = g.getFontMetrics();
2651 g.drawString(MessageManager.formatMessage("label.memory_stats",
2653 { df.format(totalFreeMemory), df.format(maxMemory),
2654 df.format(percentUsage) }),
2655 10, getHeight() - fm.getHeight());
2662 * Accessor method to quickly get all the AlignmentFrames loaded.
2664 * @return an array of AlignFrame, or null if none found
2666 public static AlignFrame[] getAlignFrames()
2668 if (Jalview.isHeadlessMode())
2670 // Desktop.desktop is null in headless mode
2671 return new AlignFrame[] { Jalview.currentAlignFrame };
2674 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2680 List<AlignFrame> avp = new ArrayList<>();
2682 for (int i = frames.length - 1; i > -1; i--)
2684 if (frames[i] instanceof AlignFrame)
2686 avp.add((AlignFrame) frames[i]);
2688 else if (frames[i] instanceof SplitFrame)
2691 * Also check for a split frame containing an AlignFrame
2693 GSplitFrame sf = (GSplitFrame) frames[i];
2694 if (sf.getTopFrame() instanceof AlignFrame)
2696 avp.add((AlignFrame) sf.getTopFrame());
2698 if (sf.getBottomFrame() instanceof AlignFrame)
2700 avp.add((AlignFrame) sf.getBottomFrame());
2704 if (avp.size() == 0)
2708 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2713 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2717 public GStructureViewer[] getJmols()
2719 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2725 List<GStructureViewer> avp = new ArrayList<>();
2727 for (int i = frames.length - 1; i > -1; i--)
2729 if (frames[i] instanceof AppJmol)
2731 GStructureViewer af = (GStructureViewer) frames[i];
2735 if (avp.size() == 0)
2739 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2744 * Add Groovy Support to Jalview
2747 public void groovyShell_actionPerformed()
2751 openGroovyConsole();
2752 } catch (Exception ex)
2754 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2755 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2757 MessageManager.getString("label.couldnt_create_groovy_shell"),
2758 MessageManager.getString("label.groovy_support_failed"),
2759 JvOptionPane.ERROR_MESSAGE);
2764 * Open the Groovy console
2766 void openGroovyConsole()
2768 if (groovyConsole == null)
2770 groovyConsole = new groovy.ui.Console();
2771 groovyConsole.setVariable("Jalview", this);
2772 groovyConsole.run();
2775 * We allow only one console at a time, so that AlignFrame menu option
2776 * 'Calculate | Run Groovy script' is unambiguous.
2777 * Disable 'Groovy Console', and enable 'Run script', when the console is
2778 * opened, and the reverse when it is closed
2780 Window window = (Window) groovyConsole.getFrame();
2781 window.addWindowListener(new WindowAdapter()
2784 public void windowClosed(WindowEvent e)
2787 * rebind CMD-Q from Groovy Console to Jalview Quit
2790 enableExecuteGroovy(false);
2796 * show Groovy console window (after close and reopen)
2798 ((Window) groovyConsole.getFrame()).setVisible(true);
2801 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2802 * and disable opening a second console
2804 enableExecuteGroovy(true);
2808 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
2811 protected void addQuitHandler()
2813 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2814 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2815 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2817 getRootPane().getActionMap().put("Quit", new AbstractAction()
2820 public void actionPerformed(ActionEvent e)
2828 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2831 * true if Groovy console is open
2833 public void enableExecuteGroovy(boolean enabled)
2836 * disable opening a second Groovy console
2837 * (or re-enable when the console is closed)
2839 groovyShell.setEnabled(!enabled);
2841 AlignFrame[] alignFrames = getAlignFrames();
2842 if (alignFrames != null)
2844 for (AlignFrame af : alignFrames)
2846 af.setGroovyEnabled(enabled);
2852 * Progress bars managed by the IProgressIndicator method.
2854 private Hashtable<Long, JPanel> progressBars;
2856 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2861 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2864 public void setProgressBar(String message, long id)
2866 if (progressBars == null)
2868 progressBars = new Hashtable<>();
2869 progressBarHandlers = new Hashtable<>();
2872 if (progressBars.get(new Long(id)) != null)
2874 JPanel panel = progressBars.remove(new Long(id));
2875 if (progressBarHandlers.contains(new Long(id)))
2877 progressBarHandlers.remove(new Long(id));
2879 removeProgressPanel(panel);
2883 progressBars.put(new Long(id), addProgressPanel(message));
2890 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2891 * jalview.gui.IProgressIndicatorHandler)
2894 public void registerHandler(final long id,
2895 final IProgressIndicatorHandler handler)
2897 if (progressBarHandlers == null
2898 || !progressBars.containsKey(new Long(id)))
2900 throw new Error(MessageManager.getString(
2901 "error.call_setprogressbar_before_registering_handler"));
2903 progressBarHandlers.put(new Long(id), handler);
2904 final JPanel progressPanel = progressBars.get(new Long(id));
2905 if (handler.canCancel())
2907 JButton cancel = new JButton(
2908 MessageManager.getString("action.cancel"));
2909 final IProgressIndicator us = this;
2910 cancel.addActionListener(new ActionListener()
2914 public void actionPerformed(ActionEvent e)
2916 handler.cancelActivity(id);
2917 us.setProgressBar(MessageManager
2918 .formatMessage("label.cancelled_params", new Object[]
2919 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2923 progressPanel.add(cancel, BorderLayout.EAST);
2929 * @return true if any progress bars are still active
2932 public boolean operationInProgress()
2934 if (progressBars != null && progressBars.size() > 0)
2942 * This will return the first AlignFrame holding the given viewport instance. It
2943 * will break if there are more than one AlignFrames viewing a particular av.
2946 * @return alignFrame for viewport
2948 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2950 if (desktop != null)
2952 AlignmentPanel[] aps = getAlignmentPanels(
2953 viewport.getSequenceSetId());
2954 for (int panel = 0; aps != null && panel < aps.length; panel++)
2956 if (aps[panel] != null && aps[panel].av == viewport)
2958 return aps[panel].alignFrame;
2965 public VamsasApplication getVamsasApplication()
2972 * flag set if jalview GUI is being operated programmatically
2974 private boolean inBatchMode = false;
2977 * check if jalview GUI is being operated programmatically
2979 * @return inBatchMode
2981 public boolean isInBatchMode()
2987 * set flag if jalview GUI is being operated programmatically
2989 * @param inBatchMode
2991 public void setInBatchMode(boolean inBatchMode)
2993 this.inBatchMode = inBatchMode;
2996 public void startServiceDiscovery()
2998 startServiceDiscovery(false);
3001 public void startServiceDiscovery(boolean blocking)
3003 boolean alive = true;
3004 Thread t0 = null, t1 = null, t2 = null;
3005 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3008 // todo: changesupport handlers need to be transferred
3009 if (discoverer == null)
3011 discoverer = new jalview.ws.jws1.Discoverer();
3012 // register PCS handler for desktop.
3013 discoverer.addPropertyChangeListener(changeSupport);
3015 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3016 // until we phase out completely
3017 (t0 = new Thread(discoverer)).start();
3020 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3022 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3023 .startDiscoverer(changeSupport);
3027 // TODO: do rest service discovery
3036 } catch (Exception e)
3039 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3040 || (t3 != null && t3.isAlive())
3041 || (t0 != null && t0.isAlive());
3047 * called to check if the service discovery process completed successfully.
3051 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3053 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3055 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3056 .getErrorMessages();
3059 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3061 if (serviceChangedDialog == null)
3063 // only run if we aren't already displaying one of these.
3064 addDialogThread(serviceChangedDialog = new Runnable()
3071 * JalviewDialog jd =new JalviewDialog() {
3073 * @Override protected void cancelPressed() { // TODO
3074 * Auto-generated method stub
3076 * }@Override protected void okPressed() { // TODO
3077 * Auto-generated method stub
3079 * }@Override protected void raiseClosed() { // TODO
3080 * Auto-generated method stub
3082 * } }; jd.initDialogFrame(new
3083 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3084 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3085 * + " or mis-configured HTTP proxy settings.<br/>" +
3086 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3088 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3089 * ), true, true, "Web Service Configuration Problem", 450,
3092 * jd.waitForInput();
3094 JvOptionPane.showConfirmDialog(Desktop.desktop,
3095 new JLabel("<html><table width=\"450\"><tr><td>"
3096 + ermsg + "</td></tr></table>"
3097 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3098 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3099 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3100 + " Tools->Preferences dialog box to change them.</p></html>"),
3101 "Web Service Configuration Problem",
3102 JvOptionPane.DEFAULT_OPTION,
3103 JvOptionPane.ERROR_MESSAGE);
3104 serviceChangedDialog = null;
3113 "Errors reported by JABA discovery service. Check web services preferences.\n"
3120 private Runnable serviceChangedDialog = null;
3123 * start a thread to open a URL in the configured browser. Pops up a warning
3124 * dialog to the user if there is an exception when calling out to the browser
3129 public static void showUrl(final String url)
3131 showUrl(url, Desktop.instance);
3135 * Like showUrl but allows progress handler to be specified
3139 * (null) or object implementing IProgressIndicator
3141 public static void showUrl(final String url,
3142 final IProgressIndicator progress)
3144 new Thread(new Runnable()
3151 if (progress != null)
3153 progress.setProgressBar(MessageManager
3154 .formatMessage("status.opening_params", new Object[]
3155 { url }), this.hashCode());
3157 jalview.util.BrowserLauncher.openURL(url);
3158 } catch (Exception ex)
3160 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3162 .getString("label.web_browser_not_found_unix"),
3163 MessageManager.getString("label.web_browser_not_found"),
3164 JvOptionPane.WARNING_MESSAGE);
3166 ex.printStackTrace();
3168 if (progress != null)
3170 progress.setProgressBar(null, this.hashCode());
3176 public static WsParamSetManager wsparamManager = null;
3178 public static ParamManager getUserParameterStore()
3180 if (wsparamManager == null)
3182 wsparamManager = new WsParamSetManager();
3184 return wsparamManager;
3188 * static hyperlink handler proxy method for use by Jalview's internal windows
3192 public static void hyperlinkUpdate(HyperlinkEvent e)
3194 if (e.getEventType() == EventType.ACTIVATED)
3199 url = e.getURL().toString();
3200 Desktop.showUrl(url);
3201 } catch (Exception x)
3205 if (Cache.log != null)
3207 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3212 "Couldn't handle string " + url + " as a URL.");
3215 // ignore any exceptions due to dud links.
3222 * single thread that handles display of dialogs to user.
3224 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3227 * flag indicating if dialogExecutor should try to acquire a permit
3229 private volatile boolean dialogPause = true;
3234 private java.util.concurrent.Semaphore block = new Semaphore(0);
3236 private static groovy.ui.Console groovyConsole;
3239 * add another dialog thread to the queue
3243 public void addDialogThread(final Runnable prompter)
3245 dialogExecutor.submit(new Runnable()
3255 } catch (InterruptedException x)
3260 if (instance == null)
3266 SwingUtilities.invokeAndWait(prompter);
3267 } catch (Exception q)
3269 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3275 public void startDialogQueue()
3277 // set the flag so we don't pause waiting for another permit and semaphore
3278 // the current task to begin
3279 dialogPause = false;
3284 * Outputs an image of the desktop to file in EPS format, after prompting the
3285 * user for choice of Text or Lineart character rendering (unless a preference
3286 * has been set). The file name is generated as
3289 * Jalview_snapshot_nnnnn.eps where nnnnn is the current timestamp in milliseconds
3293 protected void snapShotWindow_actionPerformed(ActionEvent e)
3295 // currently the menu option to do this is not shown
3298 int width = getWidth();
3299 int height = getHeight();
3301 "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
3302 ImageWriterI writer = new ImageWriterI()
3305 public void exportImage(Graphics g) throws Exception
3308 Cache.log.info("Successfully written snapshot to file "
3309 + of.getAbsolutePath());
3312 String title = "View of desktop";
3313 ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
3315 exporter.doExport(of, this, width, height, title);
3319 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3320 * This respects (remembers) any previous 'exploded geometry' i.e. the size and
3321 * location last time the view was expanded (if any). However it does not
3322 * remember the split pane divider location - this is set to match the
3323 * 'exploding' frame.
3327 public void explodeViews(SplitFrame sf)
3329 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3330 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3331 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3333 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3335 int viewCount = topPanels.size();
3342 * Processing in reverse order works, forwards order leaves the first panels
3343 * not visible. I don't know why!
3345 for (int i = viewCount - 1; i >= 0; i--)
3348 * Make new top and bottom frames. These take over the respective
3349 * AlignmentPanel objects, including their AlignmentViewports, so the
3350 * cdna/protein relationships between the viewports is carried over to the
3353 * explodedGeometry holds the (x, y) position of the previously exploded
3354 * SplitFrame, and the (width, height) of the AlignFrame component
3356 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3357 AlignFrame newTopFrame = new AlignFrame(topPanel);
3358 newTopFrame.setSize(oldTopFrame.getSize());
3359 newTopFrame.setVisible(true);
3360 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3361 .getExplodedGeometry();
3362 if (geometry != null)
3364 newTopFrame.setSize(geometry.getSize());
3367 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3368 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3369 newBottomFrame.setSize(oldBottomFrame.getSize());
3370 newBottomFrame.setVisible(true);
3371 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3372 .getExplodedGeometry();
3373 if (geometry != null)
3375 newBottomFrame.setSize(geometry.getSize());
3378 topPanel.av.setGatherViewsHere(false);
3379 bottomPanel.av.setGatherViewsHere(false);
3380 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3382 if (geometry != null)
3384 splitFrame.setLocation(geometry.getLocation());
3386 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3390 * Clear references to the panels (now relocated in the new SplitFrames)
3391 * before closing the old SplitFrame.
3394 bottomPanels.clear();
3399 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3400 * back into the given SplitFrame as additional views. Note that the gathered
3401 * frames may themselves have multiple views.
3405 public void gatherViews(GSplitFrame source)
3408 * special handling of explodedGeometry for a view within a SplitFrame: - it
3409 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3410 * height) of the AlignFrame component
3412 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3413 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3414 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3415 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3416 myBottomFrame.viewport
3417 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3418 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3419 myTopFrame.viewport.setGatherViewsHere(true);
3420 myBottomFrame.viewport.setGatherViewsHere(true);
3421 String topViewId = myTopFrame.viewport.getSequenceSetId();
3422 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3424 JInternalFrame[] frames = desktop.getAllFrames();
3425 for (JInternalFrame frame : frames)
3427 if (frame instanceof SplitFrame && frame != source)
3429 SplitFrame sf = (SplitFrame) frame;
3430 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3431 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3432 boolean gatherThis = false;
3433 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3435 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3436 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3437 if (topViewId.equals(topPanel.av.getSequenceSetId())
3438 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3441 topPanel.av.setGatherViewsHere(false);
3442 bottomPanel.av.setGatherViewsHere(false);
3443 topPanel.av.setExplodedGeometry(
3444 new Rectangle(sf.getLocation(), topFrame.getSize()));
3445 bottomPanel.av.setExplodedGeometry(
3446 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3447 myTopFrame.addAlignmentPanel(topPanel, false);
3448 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3454 topFrame.getAlignPanels().clear();
3455 bottomFrame.getAlignPanels().clear();
3462 * The dust settles...give focus to the tab we did this from.
3464 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3467 public static groovy.ui.Console getGroovyConsole()
3469 return groovyConsole;
3473 * handles the payload of a drag and drop event.
3475 * TODO refactor to desktop utilities class
3478 * - Data source strings extracted from the drop event
3480 * - protocol for each data source extracted from the drop event
3484 * - the payload from the drop event
3487 public static void transferFromDropTarget(List<Object> files,
3488 List<DataSourceType> protocols, DropTargetDropEvent evt,
3489 Transferable t) throws Exception
3492 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3494 // DataFlavor[] flavors = t.getTransferDataFlavors();
3495 // for (int i = 0; i < flavors.length; i++) {
3496 // if (flavors[i].isFlavorJavaFileListType()) {
3497 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3498 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3499 // for (int j = 0; j < list.size(); j++) {
3500 // File file = (File) list.get(j);
3501 // byte[] data = getDroppedFileBytes(file);
3502 // fileName.setText(file.getName() + " - " + data.length + " " +
3503 // evt.getLocation());
3504 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3505 // target.setText(new String(data));
3507 // dtde.dropComplete(true);
3512 DataFlavor uriListFlavor = new DataFlavor(
3513 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3516 urlFlavour = new DataFlavor(
3517 "application/x-java-url; class=java.net.URL");
3518 } catch (ClassNotFoundException cfe)
3520 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3523 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3528 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3529 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3530 // means url may be null.
3533 protocols.add(DataSourceType.URL);
3534 files.add(url.toString());
3535 Cache.log.debug("Drop handled as URL dataflavor "
3536 + files.get(files.size() - 1));
3541 if (Platform.isAMac())
3544 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3548 } catch (Throwable ex)
3550 Cache.log.debug("URL drop handler failed.", ex);
3553 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3555 // Works on Windows and MacOSX
3556 Cache.log.debug("Drop handled as javaFileListFlavor");
3557 for (Object file : (List) t
3558 .getTransferData(DataFlavor.javaFileListFlavor))
3561 protocols.add(DataSourceType.FILE);
3566 // Unix like behaviour
3567 boolean added = false;
3569 if (t.isDataFlavorSupported(uriListFlavor))
3571 Cache.log.debug("Drop handled as uriListFlavor");
3572 // This is used by Unix drag system
3573 data = (String) t.getTransferData(uriListFlavor);
3577 // fallback to text: workaround - on OSX where there's a JVM bug
3578 Cache.log.debug("standard URIListFlavor failed. Trying text");
3579 // try text fallback
3580 DataFlavor textDf = new DataFlavor(
3581 "text/plain;class=java.lang.String");
3582 if (t.isDataFlavorSupported(textDf))
3584 data = (String) t.getTransferData(textDf);
3587 Cache.log.debug("Plain text drop content returned "
3588 + (data == null ? "Null - failed" : data));
3593 while (protocols.size() < files.size())
3595 Cache.log.debug("Adding missing FILE protocol for "
3596 + files.get(protocols.size()));
3597 protocols.add(DataSourceType.FILE);
3599 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3600 data, "\r\n"); st.hasMoreTokens();)
3603 String s = st.nextToken();
3604 if (s.startsWith("#"))
3606 // the line is a comment (as per the RFC 2483)
3609 java.net.URI uri = new java.net.URI(s);
3610 if (uri.getScheme().toLowerCase().startsWith("http"))
3612 protocols.add(DataSourceType.URL);
3613 files.add(uri.toString());
3617 // otherwise preserve old behaviour: catch all for file objects
3618 java.io.File file = new java.io.File(uri);
3619 protocols.add(DataSourceType.FILE);
3620 files.add(file.toString());
3625 if (Cache.log.isDebugEnabled())
3627 if (data == null || !added)
3630 if (t.getTransferDataFlavors() != null
3631 && t.getTransferDataFlavors().length > 0)
3634 "Couldn't resolve drop data. Here are the supported flavors:");
3635 for (DataFlavor fl : t.getTransferDataFlavors())
3638 "Supported transfer dataflavor: " + fl.toString());
3639 Object df = t.getTransferData(fl);
3642 Cache.log.debug("Retrieves: " + df);
3646 Cache.log.debug("Retrieved nothing");
3652 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3658 if (Platform.isWindows())
3661 Cache.log.debug("Scanning dropped content for Windows Link Files");
3663 // resolve any .lnk files in the file drop
3664 for (int f = 0; f < files.size(); f++)
3666 String source = files.get(f).toString().toLowerCase();
3667 if (protocols.get(f).equals(DataSourceType.FILE)
3668 && (source.endsWith(".lnk") || source.endsWith(".url")
3669 || source.endsWith(".site")))
3673 Object obj = files.get(f);
3674 File lf = (obj instanceof File ? (File) obj
3675 : new File((String) obj));
3676 // process link file to get a URL
3677 Cache.log.debug("Found potential link file: " + lf);
3678 WindowsShortcut wscfile = new WindowsShortcut(lf);
3679 String fullname = wscfile.getRealFilename();
3680 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3681 files.set(f, fullname);
3682 Cache.log.debug("Parsed real filename " + fullname
3683 + " to extract protocol: " + protocols.get(f));
3684 } catch (Exception ex)
3687 "Couldn't parse " + files.get(f) + " as a link file.",
3696 * Sets the Preferences property for experimental features to True or False
3697 * depending on the state of the controlling menu item
3700 protected void showExperimental_actionPerformed(boolean selected)
3702 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3706 * Answers a (possibly empty) list of any structure viewer frames (currently for
3707 * either Jmol or Chimera) which are currently open. This may optionally be
3708 * restricted to viewers of a specified class, or viewers linked to a specified
3712 * if not null, only return viewers linked to this panel
3713 * @param structureViewerClass
3714 * if not null, only return viewers of this class
3717 public List<StructureViewerBase> getStructureViewers(
3718 AlignmentPanel apanel,
3719 Class<? extends StructureViewerBase> structureViewerClass)
3721 List<StructureViewerBase> result = new ArrayList<>();
3722 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3724 for (JInternalFrame frame : frames)
3726 if (frame instanceof StructureViewerBase)
3728 if (structureViewerClass == null
3729 || structureViewerClass.isInstance(frame))
3732 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3734 result.add((StructureViewerBase) frame);