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);
398 boolean doFullLoad = /** @j2sNative ! */true;
402 jconsole = new Console(this, showjconsole);
403 // add essential build information
404 jconsole.setHeader("Jalview Version: "
405 + jalview.bin.Cache.getProperty("VERSION") + "\n"
406 + "Jalview Installation: "
407 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
408 + "\n" + "Build Date: "
409 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
410 + "Java version: " + System.getProperty("java.version") + "\n"
411 + System.getProperty("os.arch") + " "
412 + System.getProperty("os.name") + " "
413 + System.getProperty("os.version"));
415 showConsole(showjconsole);
417 showNews.setVisible(false);
419 experimentalFeatures.setSelected(showExperimental());
421 getIdentifiersOrgData();
425 // Spawn a thread that shows the splashscreen
427 SwingUtilities.invokeLater(new Runnable()
436 // Thread off a new instance of the file chooser - this reduces the time it
437 // takes to open it later on.
438 new Thread(new Runnable()
443 Cache.log.debug("Filechooser init thread started.");
444 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
445 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
447 Cache.log.debug("Filechooser init thread finished.");
450 // Add the service change listener
451 changeSupport.addJalviewPropertyChangeListener("services",
452 new PropertyChangeListener()
456 public void propertyChange(PropertyChangeEvent evt)
458 Cache.log.debug("Firing service changed event for "
459 + evt.getNewValue());
460 JalviewServicesChanged(evt);
467 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
469 this.addWindowListener(new WindowAdapter()
472 public void windowClosing(WindowEvent evt)
479 this.addMouseListener(ma = new MouseAdapter()
482 public void mousePressed(MouseEvent evt)
484 if (evt.isPopupTrigger()) // Mac
486 showPasteMenu(evt.getX(), evt.getY());
491 public void mouseReleased(MouseEvent evt)
493 if (evt.isPopupTrigger()) // Windows
495 showPasteMenu(evt.getX(), evt.getY());
499 desktop.addMouseListener(ma);
504 * Answers true if user preferences to enable experimental features is True
509 public boolean showExperimental()
511 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
512 Boolean.FALSE.toString());
513 return Boolean.valueOf(experimental).booleanValue();
516 public void doConfigureStructurePrefs()
518 // configure services
519 StructureSelectionManager ssm = StructureSelectionManager
520 .getStructureSelectionManager(this);
521 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
523 ssm.setAddTempFacAnnot(jalview.bin.Cache
524 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
525 ssm.setProcessSecondaryStructure(jalview.bin.Cache
526 .getDefault(Preferences.STRUCT_FROM_PDB, true));
527 ssm.setSecStructServices(
528 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
532 ssm.setAddTempFacAnnot(false);
533 ssm.setProcessSecondaryStructure(false);
534 ssm.setSecStructServices(false);
538 public void checkForNews()
540 final Desktop me = this;
541 // Thread off the news reader, in case there are connection problems.
542 addDialogThread(new Runnable()
547 Cache.log.debug("Starting news thread.");
548 jvnews = new BlogReader(me);
549 showNews.setVisible(true);
550 Cache.log.debug("Completed news thread.");
555 public void getIdentifiersOrgData()
557 // Thread off the identifiers fetcher
558 addDialogThread(new Runnable()
563 Cache.log.debug("Downloading data from identifiers.org");
564 UrlDownloadClient client = new UrlDownloadClient();
567 client.download(IdOrgSettings.getUrl(),
568 IdOrgSettings.getDownloadLocation());
569 } catch (IOException e)
571 Cache.log.debug("Exception downloading identifiers.org data"
579 protected void showNews_actionPerformed(ActionEvent e)
581 showNews(showNews.isSelected());
584 void showNews(boolean visible)
586 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
587 showNews.setSelected(visible);
588 if (visible && !jvnews.isVisible())
590 new Thread(new Runnable()
595 long now = System.currentTimeMillis();
596 Desktop.instance.setProgressBar(
597 MessageManager.getString("status.refreshing_news"), now);
598 jvnews.refreshNews();
599 Desktop.instance.setProgressBar(null, now);
607 * recover the last known dimensions for a jalview window
610 * - empty string is desktop, all other windows have unique prefix
611 * @return null or last known dimensions scaled to current geometry (if last
612 * window geom was known)
614 Rectangle getLastKnownDimensions(String windowName)
616 // TODO: lock aspect ratio for scaling desktop Bug #0058199
617 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
618 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
619 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
620 String width = jalview.bin.Cache
621 .getProperty(windowName + "SCREEN_WIDTH");
622 String height = jalview.bin.Cache
623 .getProperty(windowName + "SCREEN_HEIGHT");
624 if ((x != null) && (y != null) && (width != null) && (height != null))
626 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
627 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
628 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
630 // attempt #1 - try to cope with change in screen geometry - this
631 // version doesn't preserve original jv aspect ratio.
632 // take ratio of current screen size vs original screen size.
633 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
634 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
635 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
636 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
637 // rescale the bounds depending upon the current screen geometry.
638 ix = (int) (ix * sw);
639 iw = (int) (iw * sw);
640 iy = (int) (iy * sh);
641 ih = (int) (ih * sh);
642 while (ix >= screenSize.width)
644 jalview.bin.Cache.log.debug(
645 "Window geometry location recall error: shifting horizontal to within screenbounds.");
646 ix -= screenSize.width;
648 while (iy >= screenSize.height)
650 jalview.bin.Cache.log.debug(
651 "Window geometry location recall error: shifting vertical to within screenbounds.");
652 iy -= screenSize.height;
654 jalview.bin.Cache.log.debug(
655 "Got last known dimensions for " + windowName + ": x:" + ix
656 + " y:" + iy + " width:" + iw + " height:" + ih);
658 // return dimensions for new instance
659 return new Rectangle(ix, iy, iw, ih);
664 private void doVamsasClientCheck()
666 if (Cache.vamsasJarsPresent())
668 setupVamsasDisconnectedGui();
669 VamsasMenu.setVisible(true);
670 final Desktop us = this;
671 VamsasMenu.addMenuListener(new MenuListener()
673 // this listener remembers when the menu was first selected, and
674 // doesn't rebuild the session list until it has been cleared and
676 boolean refresh = true;
679 public void menuCanceled(MenuEvent e)
685 public void menuDeselected(MenuEvent e)
691 public void menuSelected(MenuEvent e)
695 us.buildVamsasStMenu();
700 vamsasStart.setVisible(true);
704 void showPasteMenu(int x, int y)
706 JPopupMenu popup = new JPopupMenu();
707 JMenuItem item = new JMenuItem(
708 MessageManager.getString("label.paste_new_window"));
709 item.addActionListener(new ActionListener()
712 public void actionPerformed(ActionEvent evt)
719 popup.show(this, x, y);
726 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
727 Transferable contents = c.getContents(this);
729 if (contents != null)
731 String file = (String) contents
732 .getTransferData(DataFlavor.stringFlavor);
734 FileFormatI format = new IdentifyFile().identify(file,
735 DataSourceType.PASTE);
737 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
740 } catch (Exception ex)
743 "Unable to paste alignment from system clipboard:\n" + ex);
748 * Adds and opens the given frame to the desktop
759 public static synchronized void addInternalFrame(
760 final JInternalFrame frame, String title, int w, int h)
762 addInternalFrame(frame, title, true, w, h, true, false);
766 * Add an internal frame to the Jalview desktop
773 * When true, display frame immediately, otherwise, caller must call
774 * setVisible themselves.
780 public static synchronized void addInternalFrame(
781 final JInternalFrame frame, String title, boolean makeVisible,
784 addInternalFrame(frame, title, makeVisible, w, h, true, false);
788 * Add an internal frame to the Jalview desktop and make it visible
801 public static synchronized void addInternalFrame(
802 final JInternalFrame frame, String title, int w, int h,
805 addInternalFrame(frame, title, true, w, h, resizable, false);
809 * Add an internal frame to the Jalview desktop
816 * When true, display frame immediately, otherwise, caller must call
817 * setVisible themselves.
824 * @param ignoreMinSize
825 * Do not set the default minimum size for frame
827 public static synchronized void addInternalFrame(
828 final JInternalFrame frame, String title, boolean makeVisible,
829 int w, int h, boolean resizable, boolean ignoreMinSize)
832 // TODO: allow callers to determine X and Y position of frame (eg. via
834 // TODO: consider fixing method to update entries in the window submenu with
835 // the current window title
837 frame.setTitle(title);
838 if (frame.getWidth() < 1 || frame.getHeight() < 1)
842 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
843 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
844 // IF JALVIEW IS RUNNING HEADLESS
845 // ///////////////////////////////////////////////
846 if (instance == null || (System.getProperty("java.awt.headless") != null
847 && System.getProperty("java.awt.headless").equals("true")))
856 frame.setMinimumSize(
857 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
859 // Set default dimension for Alignment Frame window.
860 // The Alignment Frame window could be added from a number of places,
862 // I did this here in order not to miss out on any Alignment frame.
863 if (frame instanceof AlignFrame)
865 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
866 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
870 frame.setVisible(makeVisible);
871 frame.setClosable(true);
872 frame.setResizable(resizable);
873 frame.setMaximizable(resizable);
874 frame.setIconifiable(resizable);
875 frame.setOpaque(/** @j2sNative true || */
878 if (frame.getX() < 1 && frame.getY() < 1)
880 frame.setLocation(xOffset * openFrameCount,
881 yOffset * ((openFrameCount - 1) % 10) + yOffset);
885 * add an entry for the new frame in the Window menu
886 * (and remove it when the frame is closed)
888 final JMenuItem menuItem = new JMenuItem(title);
889 frame.addInternalFrameListener(new InternalFrameAdapter()
892 public void internalFrameActivated(InternalFrameEvent evt)
894 JInternalFrame itf = desktop.getSelectedFrame();
897 if (itf instanceof AlignFrame)
899 Jalview.setCurrentAlignFrame((AlignFrame) itf);
906 public void internalFrameClosed(InternalFrameEvent evt)
908 PaintRefresher.RemoveComponent(frame);
911 * defensive check to prevent frames being
912 * added half off the window
914 if (openFrameCount > 0)
920 * ensure no reference to alignFrame retained by menu item listener
922 if (menuItem.getActionListeners().length > 0)
924 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
926 windowMenu.remove(menuItem);
930 menuItem.addActionListener(new ActionListener()
933 public void actionPerformed(ActionEvent e)
937 frame.setSelected(true);
938 frame.setIcon(false);
939 } catch (java.beans.PropertyVetoException ex)
941 // System.err.println(ex.toString());
946 setKeyBindings(frame);
950 windowMenu.add(menuItem);
955 frame.setSelected(true);
956 frame.requestFocus();
957 } catch (java.beans.PropertyVetoException ve)
959 } catch (java.lang.ClassCastException cex)
962 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
968 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
973 private static void setKeyBindings(JInternalFrame frame)
975 @SuppressWarnings("serial")
976 final Action closeAction = new AbstractAction()
979 public void actionPerformed(ActionEvent e)
986 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
988 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
989 InputEvent.CTRL_DOWN_MASK);
990 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
991 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
993 InputMap inputMap = frame
994 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
995 String ctrlW = ctrlWKey.toString();
996 inputMap.put(ctrlWKey, ctrlW);
997 inputMap.put(cmdWKey, ctrlW);
999 ActionMap actionMap = frame.getActionMap();
1000 actionMap.put(ctrlW, closeAction);
1004 public void lostOwnership(Clipboard clipboard, Transferable contents)
1008 Desktop.jalviewClipboard = null;
1011 internalCopy = false;
1015 public void dragEnter(DropTargetDragEvent evt)
1020 public void dragExit(DropTargetEvent evt)
1025 public void dragOver(DropTargetDragEvent evt)
1030 public void dropActionChanged(DropTargetDragEvent evt)
1041 public void drop(DropTargetDropEvent evt)
1043 boolean success = true;
1044 // JAL-1552 - acceptDrop required before getTransferable call for
1045 // Java's Transferable for native dnd
1046 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1047 Transferable t = evt.getTransferable();
1048 List<Object> files = new ArrayList<>();
1049 List<DataSourceType> protocols = new ArrayList<>();
1053 Desktop.transferFromDropTarget(files, protocols, evt, t);
1054 } catch (Exception e)
1056 e.printStackTrace();
1064 for (int i = 0; i < files.size(); i++)
1066 // BH 2018 File or String
1067 Object file = files.get(i);
1068 String fileName = file.toString();
1069 DataSourceType protocol = (protocols == null)
1070 ? DataSourceType.FILE
1072 FileFormatI format = null;
1074 if (fileName.endsWith(".jar"))
1076 format = FileFormat.Jalview;
1081 format = new IdentifyFile().identify(file, protocol);
1084 new FileLoader().LoadFile(null, file, protocol, format);
1087 } catch (Exception ex)
1092 evt.dropComplete(success); // need this to ensure input focus is properly
1093 // transfered to any new windows created
1103 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1105 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1106 JalviewFileChooser chooser = JalviewFileChooser
1107 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1109 chooser.setFileView(new JalviewFileView());
1110 chooser.setDialogTitle(
1111 MessageManager.getString("label.open_local_file"));
1112 chooser.setToolTipText(MessageManager.getString("action.open"));
1114 chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION)
1120 File selectedFile = chooser.getSelectedFile();
1121 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1123 FileFormatI format = chooser.getSelectedFormat();
1126 * Call IdentifyFile to verify the file contains what its extension implies.
1127 * Skip this step for dynamically added file formats, because
1128 * IdentifyFile does not know how to recognise them.
1130 if (FileFormats.getInstance().isIdentifiable(format))
1134 format = new IdentifyFile().identify(selectedFile,
1135 DataSourceType.FILE);
1136 } catch (FileFormatException e)
1138 // format = null; //??
1142 new FileLoader().LoadFile(viewport, selectedFile,
1143 DataSourceType.FILE, format);
1145 }).openDialog(this);
1155 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1157 // This construct allows us to have a wider textfield
1159 JLabel label = new JLabel(
1160 MessageManager.getString("label.input_file_url"));
1162 JComboBox history = new JComboBox();
1163 JPanel panel = new JPanel(new GridLayout(2, 1));
1166 history.setPreferredSize(new Dimension(400, 20));
1167 history.setEditable(true);
1168 history.addItem("http://www.");
1170 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1174 if (historyItems != null)
1176 st = new StringTokenizer(historyItems, "\t");
1178 while (st.hasMoreTokens())
1180 history.addItem(st.nextElement());
1184 // BH 2018 -- providing a callback for SwingJS
1185 // dialogOption is just a simple way to provide
1186 // context for the modal-like response.
1187 // The only requirement is that desktop implement
1188 // PropertyChangeListener, which is used already in Java
1189 // for changes in input value and such within the dialogs.
1191 String dialogOption = "label.input_alignment_from_url";
1192 desktop.dialogData = new Object[] { dialogOption, viewport, history };
1193 desktop.onDialogReturn(JvOptionPane.showInternalConfirmDialog(desktop,
1194 panel, MessageManager.getString(dialogOption),
1195 JvOptionPane.OK_CANCEL_OPTION));
1197 // no code may follow this, as SwingJS will not block
1198 // callback in JavaScript comes via a property change event,
1199 // thus going into desktop.onDialogReturn(int) just the same as
1205 * Opens the CutAndPaste window for the user to paste an alignment in to
1208 * - if not null, the pasted alignment is added to the current
1209 * alignment; if null, to a new alignment window
1212 public void inputTextboxMenuItem_actionPerformed(
1213 AlignmentViewPanel viewPanel)
1215 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1216 cap.setForInput(viewPanel);
1217 Desktop.addInternalFrame(cap,
1218 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1228 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1229 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1231 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1232 screen.height + "");
1233 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1234 getWidth(), getHeight()));
1236 if (jconsole != null)
1238 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1239 jconsole.stopConsole();
1243 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1246 if (dialogExecutor != null)
1248 dialogExecutor.shutdownNow();
1250 closeAll_actionPerformed(null);
1252 if (groovyConsole != null)
1254 // suppress a possible repeat prompt to save script
1255 groovyConsole.setDirty(false);
1256 groovyConsole.exit();
1261 private void storeLastKnownDimensions(String string, Rectangle jc)
1263 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1264 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1265 + " height:" + jc.height);
1267 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1268 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1269 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1270 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1280 public void aboutMenuItem_actionPerformed(ActionEvent e)
1282 // StringBuffer message = getAboutMessage(false);
1283 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1285 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1286 new Thread(new Runnable()
1291 new SplashScreen(true);
1296 public StringBuffer getAboutMessage(boolean shortv)
1298 StringBuffer message = new StringBuffer();
1299 message.append("<html>");
1302 message.append("<h1><strong>Version: "
1303 + jalview.bin.Cache.getProperty("VERSION")
1304 + "</strong></h1>");
1305 message.append("<strong>Last Updated: <em>"
1306 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1307 + "</em></strong>");
1313 message.append("<strong>Version "
1314 + jalview.bin.Cache.getProperty("VERSION")
1315 + "; last updated: "
1316 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1319 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1320 .equals("Checking"))
1322 message.append("<br>...Checking latest version...</br>");
1324 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1325 .equals(jalview.bin.Cache.getProperty("VERSION")))
1327 boolean red = false;
1328 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1329 .indexOf("automated build") == -1)
1332 // Displayed when code version and jnlp version do not match and code
1333 // version is not a development build
1334 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1337 message.append("<br>!! Version "
1338 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1340 + " is available for download from "
1341 + jalview.bin.Cache.getDefault("www.jalview.org",
1342 "http://www.jalview.org")
1346 message.append("</div>");
1349 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1351 "The Jalview Authors (See AUTHORS file for current list)")
1352 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1353 + "<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"
1354 + "<br><br>If you use Jalview, please cite:"
1355 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1356 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1357 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1363 * Action on requesting Help documentation
1366 public void documentationMenuItem_actionPerformed()
1372 BrowserLauncher.openURL("http://www.jalview.org/help.html");
1376 Help.showHelpWindow();
1378 } catch (Exception ex)
1380 System.err.println("Error opening help: " + ex.getMessage());
1385 public void closeAll_actionPerformed(ActionEvent e)
1387 // TODO show a progress bar while closing?
1388 JInternalFrame[] frames = desktop.getAllFrames();
1389 for (int i = 0; i < frames.length; i++)
1393 frames[i].setClosed(true);
1394 } catch (java.beans.PropertyVetoException ex)
1398 Jalview.setCurrentAlignFrame(null);
1399 System.out.println("ALL CLOSED");
1400 if (v_client != null)
1402 // TODO clear binding to vamsas document objects on close_all
1406 * reset state of singleton objects as appropriate (clear down session state
1407 * when all windows are closed)
1409 StructureSelectionManager ssm = StructureSelectionManager
1410 .getStructureSelectionManager(this);
1418 public void raiseRelated_actionPerformed(ActionEvent e)
1420 reorderAssociatedWindows(false, false);
1424 public void minimizeAssociated_actionPerformed(ActionEvent e)
1426 reorderAssociatedWindows(true, false);
1429 void closeAssociatedWindows()
1431 reorderAssociatedWindows(false, true);
1437 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1441 protected void garbageCollect_actionPerformed(ActionEvent e)
1443 // We simply collect the garbage
1444 jalview.bin.Cache.log.debug("Collecting garbage...");
1446 jalview.bin.Cache.log.debug("Finished garbage collection.");
1453 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1457 protected void showMemusage_actionPerformed(ActionEvent e)
1459 desktop.showMemoryUsage(showMemusage.isSelected());
1466 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1470 protected void showConsole_actionPerformed(ActionEvent e)
1472 showConsole(showConsole.isSelected());
1475 Console jconsole = null;
1478 * control whether the java console is visible or not
1482 void showConsole(boolean selected)
1484 // TODO: decide if we should update properties file
1485 if (jconsole != null) // BH 2018
1487 showConsole.setSelected(selected);
1488 Cache.setProperty("SHOW_JAVA_CONSOLE",
1489 Boolean.valueOf(selected).toString());
1490 jconsole.setVisible(selected);
1494 void reorderAssociatedWindows(boolean minimize, boolean close)
1496 JInternalFrame[] frames = desktop.getAllFrames();
1497 if (frames == null || frames.length < 1)
1502 AlignmentViewport source = null, target = null;
1503 if (frames[0] instanceof AlignFrame)
1505 source = ((AlignFrame) frames[0]).getCurrentView();
1507 else if (frames[0] instanceof TreePanel)
1509 source = ((TreePanel) frames[0]).getViewPort();
1511 else if (frames[0] instanceof PCAPanel)
1513 source = ((PCAPanel) frames[0]).av;
1515 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1517 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1522 for (int i = 0; i < frames.length; i++)
1525 if (frames[i] == null)
1529 if (frames[i] instanceof AlignFrame)
1531 target = ((AlignFrame) frames[i]).getCurrentView();
1533 else if (frames[i] instanceof TreePanel)
1535 target = ((TreePanel) frames[i]).getViewPort();
1537 else if (frames[i] instanceof PCAPanel)
1539 target = ((PCAPanel) frames[i]).av;
1541 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1543 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1546 if (source == target)
1552 frames[i].setClosed(true);
1556 frames[i].setIcon(minimize);
1559 frames[i].toFront();
1563 } catch (java.beans.PropertyVetoException ex)
1578 protected void preferences_actionPerformed(ActionEvent e)
1584 * Prompts the user to choose a file and then saves the Jalview state as a
1585 * Jalview project file
1588 public void saveState_actionPerformed()
1590 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1593 chooser.setFileView(new JalviewFileView());
1594 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1596 int value = chooser.showSaveDialog(this);
1598 if (value == JalviewFileChooser.APPROVE_OPTION)
1600 final Desktop me = this;
1601 final java.io.File choice = chooser.getSelectedFile();
1602 setProjectFile(choice);
1604 new Thread(new Runnable()
1609 // TODO: refactor to Jalview desktop session controller action.
1610 setProgressBar(MessageManager.formatMessage(
1611 "label.saving_jalview_project", new Object[]
1612 { choice.getName() }), choice.hashCode());
1613 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1614 choice.getParent());
1615 // TODO catch and handle errors for savestate
1616 // TODO prevent user from messing with the Desktop whilst we're saving
1619 new Jalview2XML().saveState(choice);
1620 } catch (OutOfMemoryError oom)
1623 "Whilst saving current state to " + choice.getName(),
1625 } catch (Exception ex)
1628 "Problems whilst trying to save to " + choice.getName(),
1630 JvOptionPane.showMessageDialog(me,
1631 MessageManager.formatMessage(
1632 "label.error_whilst_saving_current_state_to",
1634 { choice.getName() }),
1635 MessageManager.getString("label.couldnt_save_project"),
1636 JvOptionPane.WARNING_MESSAGE);
1638 setProgressBar(null, choice.hashCode());
1644 private void setProjectFile(File choice)
1646 this.projectFile = choice;
1649 public File getProjectFile()
1651 return this.projectFile;
1655 * Prompts the user to choose a file and loads in as a Jalview project file
1658 public void loadState_actionPerformed()
1660 JalviewFileChooser chooser = new JalviewFileChooser(
1661 Cache.getProperty("LAST_DIRECTORY"), new String[]
1664 { "Jalview Project", "Jalview Project (old)" },
1666 chooser.setFileView(new JalviewFileView());
1667 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1669 int value = chooser.showOpenDialog(this);
1671 if (value == JalviewFileChooser.APPROVE_OPTION)
1673 final File selectedFile = chooser.getSelectedFile();
1674 setProjectFile(selectedFile);
1675 final String choice = selectedFile.getAbsolutePath();
1676 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1677 new Thread(new Runnable()
1682 setProgressBar(MessageManager.formatMessage(
1683 "label.loading_jalview_project", new Object[]
1684 { choice }), choice.hashCode());
1687 new Jalview2XML().loadJalviewAlign(choice);
1688 } catch (OutOfMemoryError oom)
1690 new OOMWarning("Whilst loading project from " + choice, oom);
1691 } catch (Exception ex)
1694 "Problems whilst loading project from " + choice, ex);
1695 JvOptionPane.showMessageDialog(Desktop.desktop,
1696 MessageManager.formatMessage(
1697 "label.error_whilst_loading_project_from",
1700 MessageManager.getString("label.couldnt_load_project"),
1701 JvOptionPane.WARNING_MESSAGE);
1703 setProgressBar(null, choice.hashCode());
1710 public void inputSequence_actionPerformed(ActionEvent e)
1712 new SequenceFetcher(this);
1715 JPanel progressPanel;
1717 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1719 public void startLoading(final Object fileName)
1721 if (fileLoadingCount == 0)
1723 fileLoadingPanels.add(addProgressPanel(MessageManager
1724 .formatMessage("label.loading_file", new Object[]
1730 private JPanel addProgressPanel(String string)
1732 if (progressPanel == null)
1734 progressPanel = new JPanel(new GridLayout(1, 1));
1735 totalProgressCount = 0;
1736 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1738 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1739 JProgressBar progressBar = new JProgressBar();
1740 progressBar.setIndeterminate(true);
1742 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1744 thisprogress.add(progressBar, BorderLayout.CENTER);
1745 progressPanel.add(thisprogress);
1746 ((GridLayout) progressPanel.getLayout()).setRows(
1747 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1748 ++totalProgressCount;
1749 instance.validate();
1750 return thisprogress;
1753 int totalProgressCount = 0;
1755 private void removeProgressPanel(JPanel progbar)
1757 if (progressPanel != null)
1759 synchronized (progressPanel)
1761 progressPanel.remove(progbar);
1762 GridLayout gl = (GridLayout) progressPanel.getLayout();
1763 gl.setRows(gl.getRows() - 1);
1764 if (--totalProgressCount < 1)
1766 this.getContentPane().remove(progressPanel);
1767 progressPanel = null;
1774 public void stopLoading()
1777 if (fileLoadingCount < 1)
1779 while (fileLoadingPanels.size() > 0)
1781 removeProgressPanel(fileLoadingPanels.remove(0));
1783 fileLoadingPanels.clear();
1784 fileLoadingCount = 0;
1789 public static int getViewCount(String alignmentId)
1791 AlignmentViewport[] aps = getViewports(alignmentId);
1792 return (aps == null) ? 0 : aps.length;
1797 * @param alignmentId
1798 * - if null, all sets are returned
1799 * @return all AlignmentPanels concerning the alignmentId sequence set
1801 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1803 if (Desktop.desktop == null)
1805 // no frames created and in headless mode
1806 // TODO: verify that frames are recoverable when in headless mode
1809 List<AlignmentPanel> aps = new ArrayList<>();
1810 AlignFrame[] frames = getAlignFrames();
1815 for (AlignFrame af : frames)
1817 for (AlignmentPanel ap : af.alignPanels)
1819 if (alignmentId == null
1820 || alignmentId.equals(ap.av.getSequenceSetId()))
1826 if (aps.size() == 0)
1830 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1835 * get all the viewports on an alignment.
1837 * @param sequenceSetId
1838 * unique alignment id (may be null - all viewports returned in that
1840 * @return all viewports on the alignment bound to sequenceSetId
1842 public static AlignmentViewport[] getViewports(String sequenceSetId)
1844 List<AlignmentViewport> viewp = new ArrayList<>();
1845 if (desktop != null)
1847 AlignFrame[] frames = Desktop.getAlignFrames();
1849 for (AlignFrame afr : frames)
1851 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1852 .equals(sequenceSetId))
1854 if (afr.alignPanels != null)
1856 for (AlignmentPanel ap : afr.alignPanels)
1858 if (sequenceSetId == null
1859 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1867 viewp.add(afr.getViewport());
1871 if (viewp.size() > 0)
1873 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1880 * Explode the views in the given frame into separate AlignFrame
1884 public static void explodeViews(AlignFrame af)
1886 int size = af.alignPanels.size();
1892 for (int i = 0; i < size; i++)
1894 AlignmentPanel ap = af.alignPanels.get(i);
1895 AlignFrame newaf = new AlignFrame(ap);
1898 * Restore the view's last exploded frame geometry if known. Multiple
1899 * views from one exploded frame share and restore the same (frame)
1900 * position and size.
1902 Rectangle geometry = ap.av.getExplodedGeometry();
1903 if (geometry != null)
1905 newaf.setBounds(geometry);
1908 ap.av.setGatherViewsHere(false);
1910 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1911 AlignFrame.DEFAULT_HEIGHT);
1914 af.alignPanels.clear();
1915 af.closeMenuItem_actionPerformed(true);
1920 * Gather expanded views (separate AlignFrame's) with the same sequence set
1921 * identifier back in to this frame as additional views, and close the expanded
1922 * views. Note the expanded frames may themselves have multiple views. We take
1927 public void gatherViews(AlignFrame source)
1929 source.viewport.setGatherViewsHere(true);
1930 source.viewport.setExplodedGeometry(source.getBounds());
1931 JInternalFrame[] frames = desktop.getAllFrames();
1932 String viewId = source.viewport.getSequenceSetId();
1934 for (int t = 0; t < frames.length; t++)
1936 if (frames[t] instanceof AlignFrame && frames[t] != source)
1938 AlignFrame af = (AlignFrame) frames[t];
1939 boolean gatherThis = false;
1940 for (int a = 0; a < af.alignPanels.size(); a++)
1942 AlignmentPanel ap = af.alignPanels.get(a);
1943 if (viewId.equals(ap.av.getSequenceSetId()))
1946 ap.av.setGatherViewsHere(false);
1947 ap.av.setExplodedGeometry(af.getBounds());
1948 source.addAlignmentPanel(ap, false);
1954 af.alignPanels.clear();
1955 af.closeMenuItem_actionPerformed(true);
1962 jalview.gui.VamsasApplication v_client = null;
1965 public void vamsasImport_actionPerformed(ActionEvent e)
1967 // TODO: JAL-3048 not needed for Jalview-JS
1969 if (v_client == null)
1971 // Load and try to start a session.
1972 JalviewFileChooser chooser = new JalviewFileChooser(
1973 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
1975 chooser.setFileView(new JalviewFileView());
1976 chooser.setDialogTitle(
1977 MessageManager.getString("label.open_saved_vamsas_session"));
1978 chooser.setToolTipText(MessageManager.getString(
1979 "label.select_vamsas_session_opened_as_new_vamsas_session"));
1981 int value = chooser.showOpenDialog(this);
1983 if (value == JalviewFileChooser.APPROVE_OPTION)
1985 String fle = chooser.getSelectedFile().toString();
1986 if (!vamsasImport(chooser.getSelectedFile()))
1988 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1989 MessageManager.formatMessage(
1990 "label.couldnt_import_as_vamsas_session",
1994 .getString("label.vamsas_document_import_failed"),
1995 JvOptionPane.ERROR_MESSAGE);
2001 jalview.bin.Cache.log.error(
2002 "Implementation error - load session from a running session is not supported.");
2007 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2010 * @return true if import was a success and a session was started.
2012 public boolean vamsasImport(URL url)
2014 // TODO: create progress bar
2015 if (v_client != null)
2018 jalview.bin.Cache.log.error(
2019 "Implementation error - load session from a running session is not supported.");
2025 // copy the URL content to a temporary local file
2026 // TODO: be a bit cleverer here with nio (?!)
2027 File file = File.createTempFile("vdocfromurl", ".vdj");
2028 FileOutputStream fos = new FileOutputStream(file);
2029 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2030 byte[] buffer = new byte[2048];
2032 while ((ln = bis.read(buffer)) > -1)
2034 fos.write(buffer, 0, ln);
2038 v_client = new jalview.gui.VamsasApplication(this, file,
2039 url.toExternalForm());
2040 } catch (Exception ex)
2042 jalview.bin.Cache.log.error(
2043 "Failed to create new vamsas session from contents of URL "
2048 setupVamsasConnectedGui();
2049 v_client.initial_update(); // TODO: thread ?
2050 return v_client.inSession();
2054 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2057 * @return true if import was a success and a session was started.
2059 public boolean vamsasImport(File file)
2061 if (v_client != null)
2064 jalview.bin.Cache.log.error(
2065 "Implementation error - load session from a running session is not supported.");
2069 setProgressBar(MessageManager.formatMessage(
2070 "status.importing_vamsas_session_from", new Object[]
2071 { file.getName() }), file.hashCode());
2074 v_client = new jalview.gui.VamsasApplication(this, file, null);
2075 } catch (Exception ex)
2077 setProgressBar(MessageManager.formatMessage(
2078 "status.importing_vamsas_session_from", new Object[]
2079 { file.getName() }), file.hashCode());
2080 jalview.bin.Cache.log.error(
2081 "New vamsas session from existing session file failed:", ex);
2084 setupVamsasConnectedGui();
2085 v_client.initial_update(); // TODO: thread ?
2086 setProgressBar(MessageManager.formatMessage(
2087 "status.importing_vamsas_session_from", new Object[]
2088 { file.getName() }), file.hashCode());
2089 return v_client.inSession();
2092 public boolean joinVamsasSession(String mysesid)
2094 if (v_client != null)
2096 throw new Error(MessageManager
2097 .getString("error.try_join_vamsas_session_another"));
2099 if (mysesid == null)
2102 MessageManager.getString("error.invalid_vamsas_session_id"));
2104 v_client = new VamsasApplication(this, mysesid);
2105 setupVamsasConnectedGui();
2106 v_client.initial_update();
2107 return (v_client.inSession());
2111 public void vamsasStart_actionPerformed(ActionEvent e)
2113 if (v_client == null)
2116 // we just start a default session for moment.
2118 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2119 * getProperty("LAST_DIRECTORY"));
2121 * chooser.setFileView(new JalviewFileView());
2122 * chooser.setDialogTitle("Load Vamsas file");
2123 * chooser.setToolTipText("Import");
2125 * int value = chooser.showOpenDialog(this);
2127 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2128 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2130 v_client = new VamsasApplication(this);
2131 setupVamsasConnectedGui();
2132 v_client.initial_update(); // TODO: thread ?
2136 // store current data in session.
2137 v_client.push_update(); // TODO: thread
2141 protected void setupVamsasConnectedGui()
2143 vamsasStart.setText(MessageManager.getString("label.session_update"));
2144 vamsasSave.setVisible(true);
2145 vamsasStop.setVisible(true);
2146 vamsasImport.setVisible(false); // Document import to existing session is
2147 // not possible for vamsas-client-1.0.
2150 protected void setupVamsasDisconnectedGui()
2152 vamsasSave.setVisible(false);
2153 vamsasStop.setVisible(false);
2154 vamsasImport.setVisible(true);
2156 .setText(MessageManager.getString("label.new_vamsas_session"));
2160 public void vamsasStop_actionPerformed(ActionEvent e)
2162 if (v_client != null)
2164 v_client.end_session();
2166 setupVamsasDisconnectedGui();
2170 protected void buildVamsasStMenu()
2172 if (v_client == null)
2174 String[] sess = null;
2177 sess = VamsasApplication.getSessionList();
2178 } catch (Exception e)
2180 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2186 jalview.bin.Cache.log.debug(
2187 "Got current sessions list: " + sess.length + " entries.");
2188 VamsasStMenu.removeAll();
2189 for (int i = 0; i < sess.length; i++)
2191 JMenuItem sessit = new JMenuItem();
2192 sessit.setText(sess[i]);
2193 sessit.setToolTipText(MessageManager
2194 .formatMessage("label.connect_to_session", new Object[]
2196 final Desktop dsktp = this;
2197 final String mysesid = sess[i];
2198 sessit.addActionListener(new ActionListener()
2202 public void actionPerformed(ActionEvent e)
2204 if (dsktp.v_client == null)
2206 Thread rthr = new Thread(new Runnable()
2212 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2213 dsktp.setupVamsasConnectedGui();
2214 dsktp.v_client.initial_update();
2222 VamsasStMenu.add(sessit);
2224 // don't show an empty menu.
2225 VamsasStMenu.setVisible(sess.length > 0);
2230 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2231 VamsasStMenu.removeAll();
2232 VamsasStMenu.setVisible(false);
2237 // Not interested in the content. Just hide ourselves.
2238 VamsasStMenu.setVisible(false);
2243 public void vamsasSave_actionPerformed(ActionEvent e)
2245 // TODO: JAL-3048 not needed for Jalview-JS
2247 if (v_client != null)
2249 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2250 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2253 chooser.setFileView(new JalviewFileView());
2254 chooser.setDialogTitle(MessageManager
2255 .getString("label.save_vamsas_document_archive"));
2257 int value = chooser.showSaveDialog(this);
2259 if (value == JalviewFileChooser.APPROVE_OPTION)
2261 java.io.File choice = chooser.getSelectedFile();
2262 JPanel progpanel = addProgressPanel(MessageManager
2263 .formatMessage("label.saving_vamsas_doc", new Object[]
2264 { choice.getName() }));
2265 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2266 String warnmsg = null;
2267 String warnttl = null;
2270 v_client.vclient.storeDocument(choice);
2273 warnttl = "Serious Problem saving Vamsas Document";
2274 warnmsg = ex.toString();
2275 jalview.bin.Cache.log
2276 .error("Error Whilst saving document to " + choice, ex);
2278 } catch (Exception ex)
2280 warnttl = "Problem saving Vamsas Document.";
2281 warnmsg = ex.toString();
2282 jalview.bin.Cache.log.warn(
2283 "Exception Whilst saving document to " + choice, ex);
2286 removeProgressPanel(progpanel);
2287 if (warnmsg != null)
2289 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2291 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2297 JPanel vamUpdate = null;
2300 * hide vamsas user gui bits when a vamsas document event is being handled.
2303 * true to hide gui, false to reveal gui
2305 public void setVamsasUpdate(boolean b)
2307 Cache.log.debug("Setting gui for Vamsas update "
2308 + (b ? "in progress" : "finished"));
2310 if (vamUpdate != null)
2312 this.removeProgressPanel(vamUpdate);
2316 vamUpdate = this.addProgressPanel(
2317 MessageManager.getString("label.updating_vamsas_session"));
2319 vamsasStart.setVisible(!b);
2320 vamsasStop.setVisible(!b);
2321 vamsasSave.setVisible(!b);
2324 public JInternalFrame[] getAllFrames()
2326 return desktop.getAllFrames();
2330 * Checks the given url to see if it gives a response indicating that the user
2331 * should be informed of a new questionnaire.
2335 public void checkForQuestionnaire(String url)
2337 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2338 // javax.swing.SwingUtilities.invokeLater(jvq);
2339 new Thread(jvq).start();
2342 public void checkURLLinks()
2344 // Thread off the URL link checker
2345 addDialogThread(new Runnable()
2350 if (Cache.getDefault("CHECKURLLINKS", true))
2352 // check what the actual links are - if it's just the default don't
2353 // bother with the warning
2354 List<String> links = Preferences.sequenceUrlLinks
2357 // only need to check links if there is one with a
2358 // SEQUENCE_ID which is not the default EMBL_EBI link
2359 ListIterator<String> li = links.listIterator();
2360 boolean check = false;
2361 List<JLabel> urls = new ArrayList<>();
2362 while (li.hasNext())
2364 String link = li.next();
2365 if (link.contains(SEQUENCE_ID)
2366 && !UrlConstants.isDefaultString(link))
2369 int barPos = link.indexOf("|");
2370 String urlMsg = barPos == -1 ? link
2371 : link.substring(0, barPos) + ": "
2372 + link.substring(barPos + 1);
2373 urls.add(new JLabel(urlMsg));
2381 // ask user to check in case URL links use old style tokens
2382 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2383 JPanel msgPanel = new JPanel();
2384 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2385 msgPanel.add(Box.createVerticalGlue());
2386 JLabel msg = new JLabel(MessageManager
2387 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2388 JLabel msg2 = new JLabel(MessageManager
2389 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2391 for (JLabel url : urls)
2397 final JCheckBox jcb = new JCheckBox(
2398 MessageManager.getString("label.do_not_display_again"));
2399 jcb.addActionListener(new ActionListener()
2402 public void actionPerformed(ActionEvent e)
2404 // update Cache settings for "don't show this again"
2405 boolean showWarningAgain = !jcb.isSelected();
2406 Cache.setProperty("CHECKURLLINKS",
2407 Boolean.valueOf(showWarningAgain).toString());
2412 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2414 .getString("label.SEQUENCE_ID_no_longer_used"),
2415 JvOptionPane.WARNING_MESSAGE);
2422 * Proxy class for JDesktopPane which optionally displays the current memory
2423 * usage and highlights the desktop area with a red bar if free memory runs low.
2427 public class MyDesktopPane extends JDesktopPane
2428 implements Runnable, PropertyChangeListener
2431 public Object[] dialogData;
2435 public void propertyChange(PropertyChangeEvent event)
2437 // TODO this is obsolete with JAL-3048 - delete?
2438 Object val = event.getNewValue();
2439 String name = event.getPropertyName();
2440 System.out.println(name);
2441 switch (event.getSource().getClass().getName())
2443 case "javax.swing.JOptionPane":
2447 onDialogReturn(val);
2450 if (val instanceof Integer)
2452 onDialogReturn(((Integer) val).intValue());
2456 onDialogReturn(val);
2461 case "javax.swing.JFileChooser":
2464 case "SelectedFile":
2465 // in JavaScript, this File object will have a _bytes property,
2466 // because the file data has already been loaded
2467 onDialogReturn(new Object[] { (File) val });
2472 System.out.println(event.getSource().getClass().getName() + " "
2473 + event.getPropertyName() + ": " + event.getNewValue());
2476 // JSCOmponent.DialogCaller interface
2477 void onDialogReturn(Object value)
2479 switch ((String) dialogData[0])
2481 case "SelectedFile":
2483 dialogData[0] = value;
2484 ((Runnable) dialogData[1]).run();
2490 // JSCOmponent.DialogCaller interface
2491 void onDialogReturn(int value)
2493 if (value != Math.floor(value))
2495 // in JavaScript, this will be NaN, oddly enough
2499 switch ((String) dialogData[0])
2502 dialogData[0] = Integer.valueOf(value);
2503 ((Runnable) dialogData[1]).run();
2505 case "label.input_alignment_from_url":
2506 // reconstruct the parameter data
2508 AlignViewport viewport = (AlignViewport) dialogData[1];
2509 JComboBox history = (JComboBox) dialogData[2];
2510 // the rest of this is unchangaed
2511 if (reply != JvOptionPane.OK_OPTION)
2516 String url = history.getSelectedItem().toString();
2518 if (url.toLowerCase().endsWith(".jar"))
2520 if (viewport != null)
2522 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2523 FileFormat.Jalview);
2527 new FileLoader().LoadFile(url, DataSourceType.URL,
2528 FileFormat.Jalview);
2533 FileFormatI format = null;
2536 format = new IdentifyFile().identify(url, DataSourceType.URL);
2537 } catch (FileFormatException e)
2539 // TODO revise error handling, distinguish between
2540 // URL not found and response not valid
2545 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2546 MessageManager.formatMessage("label.couldnt_locate",
2549 MessageManager.getString("label.url_not_found"),
2550 JvOptionPane.WARNING_MESSAGE);
2555 if (viewport != null)
2557 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2562 new FileLoader().LoadFile(url, DataSourceType.URL, format);
2571 private static final float ONE_MB = 1048576f;
2573 boolean showMemoryUsage = false;
2577 java.text.NumberFormat df;
2579 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2582 public MyDesktopPane(boolean showMemoryUsage)
2584 showMemoryUsage(showMemoryUsage);
2587 public void showMemoryUsage(boolean showMemory)
2589 this.showMemoryUsage = showMemory;
2592 Thread worker = new Thread(this);
2598 public boolean isShowMemoryUsage()
2600 return showMemoryUsage;
2606 df = java.text.NumberFormat.getNumberInstance();
2607 df.setMaximumFractionDigits(2);
2608 runtime = Runtime.getRuntime();
2610 while (showMemoryUsage)
2614 maxMemory = runtime.maxMemory() / ONE_MB;
2615 allocatedMemory = runtime.totalMemory() / ONE_MB;
2616 freeMemory = runtime.freeMemory() / ONE_MB;
2617 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2619 percentUsage = (totalFreeMemory / maxMemory) * 100;
2621 // if (percentUsage < 20)
2623 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2625 // instance.set.setBorder(border1);
2628 // sleep after showing usage
2630 } catch (Exception ex)
2632 ex.printStackTrace();
2638 public void paintComponent(Graphics g)
2640 if (showMemoryUsage && g != null && df != null)
2642 if (percentUsage < 20)
2644 g.setColor(Color.red);
2646 FontMetrics fm = g.getFontMetrics();
2649 g.drawString(MessageManager.formatMessage("label.memory_stats",
2651 { df.format(totalFreeMemory), df.format(maxMemory),
2652 df.format(percentUsage) }),
2653 10, getHeight() - fm.getHeight());
2660 * Accessor method to quickly get all the AlignmentFrames loaded.
2662 * @return an array of AlignFrame, or null if none found
2664 public static AlignFrame[] getAlignFrames()
2666 if (Jalview.isHeadlessMode())
2668 // Desktop.desktop is null in headless mode
2669 return new AlignFrame[] { Jalview.currentAlignFrame };
2672 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2678 List<AlignFrame> avp = new ArrayList<>();
2680 for (int i = frames.length - 1; i > -1; i--)
2682 if (frames[i] instanceof AlignFrame)
2684 avp.add((AlignFrame) frames[i]);
2686 else if (frames[i] instanceof SplitFrame)
2689 * Also check for a split frame containing an AlignFrame
2691 GSplitFrame sf = (GSplitFrame) frames[i];
2692 if (sf.getTopFrame() instanceof AlignFrame)
2694 avp.add((AlignFrame) sf.getTopFrame());
2696 if (sf.getBottomFrame() instanceof AlignFrame)
2698 avp.add((AlignFrame) sf.getBottomFrame());
2702 if (avp.size() == 0)
2706 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2711 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2715 public GStructureViewer[] getJmols()
2717 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2723 List<GStructureViewer> avp = new ArrayList<>();
2725 for (int i = frames.length - 1; i > -1; i--)
2727 if (frames[i] instanceof AppJmol)
2729 GStructureViewer af = (GStructureViewer) frames[i];
2733 if (avp.size() == 0)
2737 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2742 * Add Groovy Support to Jalview
2745 public void groovyShell_actionPerformed()
2749 openGroovyConsole();
2750 } catch (Exception ex)
2752 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2753 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2755 MessageManager.getString("label.couldnt_create_groovy_shell"),
2756 MessageManager.getString("label.groovy_support_failed"),
2757 JvOptionPane.ERROR_MESSAGE);
2762 * Open the Groovy console
2764 void openGroovyConsole()
2766 if (groovyConsole == null)
2768 groovyConsole = new groovy.ui.Console();
2769 groovyConsole.setVariable("Jalview", this);
2770 groovyConsole.run();
2773 * We allow only one console at a time, so that AlignFrame menu option
2774 * 'Calculate | Run Groovy script' is unambiguous.
2775 * Disable 'Groovy Console', and enable 'Run script', when the console is
2776 * opened, and the reverse when it is closed
2778 Window window = (Window) groovyConsole.getFrame();
2779 window.addWindowListener(new WindowAdapter()
2782 public void windowClosed(WindowEvent e)
2785 * rebind CMD-Q from Groovy Console to Jalview Quit
2788 enableExecuteGroovy(false);
2794 * show Groovy console window (after close and reopen)
2796 ((Window) groovyConsole.getFrame()).setVisible(true);
2799 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2800 * and disable opening a second console
2802 enableExecuteGroovy(true);
2806 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
2809 protected void addQuitHandler()
2811 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2812 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2813 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2815 getRootPane().getActionMap().put("Quit", new AbstractAction()
2818 public void actionPerformed(ActionEvent e)
2826 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2829 * true if Groovy console is open
2831 public void enableExecuteGroovy(boolean enabled)
2834 * disable opening a second Groovy console
2835 * (or re-enable when the console is closed)
2837 groovyShell.setEnabled(!enabled);
2839 AlignFrame[] alignFrames = getAlignFrames();
2840 if (alignFrames != null)
2842 for (AlignFrame af : alignFrames)
2844 af.setGroovyEnabled(enabled);
2850 * Progress bars managed by the IProgressIndicator method.
2852 private Hashtable<Long, JPanel> progressBars;
2854 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2859 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2862 public void setProgressBar(String message, long id)
2864 if (progressBars == null)
2866 progressBars = new Hashtable<>();
2867 progressBarHandlers = new Hashtable<>();
2870 if (progressBars.get(new Long(id)) != null)
2872 JPanel panel = progressBars.remove(new Long(id));
2873 if (progressBarHandlers.contains(new Long(id)))
2875 progressBarHandlers.remove(new Long(id));
2877 removeProgressPanel(panel);
2881 progressBars.put(new Long(id), addProgressPanel(message));
2888 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2889 * jalview.gui.IProgressIndicatorHandler)
2892 public void registerHandler(final long id,
2893 final IProgressIndicatorHandler handler)
2895 if (progressBarHandlers == null
2896 || !progressBars.containsKey(new Long(id)))
2898 throw new Error(MessageManager.getString(
2899 "error.call_setprogressbar_before_registering_handler"));
2901 progressBarHandlers.put(new Long(id), handler);
2902 final JPanel progressPanel = progressBars.get(new Long(id));
2903 if (handler.canCancel())
2905 JButton cancel = new JButton(
2906 MessageManager.getString("action.cancel"));
2907 final IProgressIndicator us = this;
2908 cancel.addActionListener(new ActionListener()
2912 public void actionPerformed(ActionEvent e)
2914 handler.cancelActivity(id);
2915 us.setProgressBar(MessageManager
2916 .formatMessage("label.cancelled_params", new Object[]
2917 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2921 progressPanel.add(cancel, BorderLayout.EAST);
2927 * @return true if any progress bars are still active
2930 public boolean operationInProgress()
2932 if (progressBars != null && progressBars.size() > 0)
2940 * This will return the first AlignFrame holding the given viewport instance. It
2941 * will break if there are more than one AlignFrames viewing a particular av.
2944 * @return alignFrame for viewport
2946 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2948 if (desktop != null)
2950 AlignmentPanel[] aps = getAlignmentPanels(
2951 viewport.getSequenceSetId());
2952 for (int panel = 0; aps != null && panel < aps.length; panel++)
2954 if (aps[panel] != null && aps[panel].av == viewport)
2956 return aps[panel].alignFrame;
2963 public VamsasApplication getVamsasApplication()
2970 * flag set if jalview GUI is being operated programmatically
2972 private boolean inBatchMode = false;
2975 * check if jalview GUI is being operated programmatically
2977 * @return inBatchMode
2979 public boolean isInBatchMode()
2985 * set flag if jalview GUI is being operated programmatically
2987 * @param inBatchMode
2989 public void setInBatchMode(boolean inBatchMode)
2991 this.inBatchMode = inBatchMode;
2994 public void startServiceDiscovery()
2996 startServiceDiscovery(false);
2999 public void startServiceDiscovery(boolean blocking)
3001 boolean alive = true;
3002 Thread t0 = null, t1 = null, t2 = null;
3003 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3006 // todo: changesupport handlers need to be transferred
3007 if (discoverer == null)
3009 discoverer = new jalview.ws.jws1.Discoverer();
3010 // register PCS handler for desktop.
3011 discoverer.addPropertyChangeListener(changeSupport);
3013 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3014 // until we phase out completely
3015 (t0 = new Thread(discoverer)).start();
3018 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3020 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3021 .startDiscoverer(changeSupport);
3025 // TODO: do rest service discovery
3034 } catch (Exception e)
3037 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3038 || (t3 != null && t3.isAlive())
3039 || (t0 != null && t0.isAlive());
3045 * called to check if the service discovery process completed successfully.
3049 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3051 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3053 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3054 .getErrorMessages();
3057 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3059 if (serviceChangedDialog == null)
3061 // only run if we aren't already displaying one of these.
3062 addDialogThread(serviceChangedDialog = new Runnable()
3069 * JalviewDialog jd =new JalviewDialog() {
3071 * @Override protected void cancelPressed() { // TODO
3072 * Auto-generated method stub
3074 * }@Override protected void okPressed() { // TODO
3075 * Auto-generated method stub
3077 * }@Override protected void raiseClosed() { // TODO
3078 * Auto-generated method stub
3080 * } }; jd.initDialogFrame(new
3081 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3082 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3083 * + " or mis-configured HTTP proxy settings.<br/>" +
3084 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3086 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3087 * ), true, true, "Web Service Configuration Problem", 450,
3090 * jd.waitForInput();
3092 JvOptionPane.showConfirmDialog(Desktop.desktop,
3093 new JLabel("<html><table width=\"450\"><tr><td>"
3094 + ermsg + "</td></tr></table>"
3095 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3096 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3097 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3098 + " Tools->Preferences dialog box to change them.</p></html>"),
3099 "Web Service Configuration Problem",
3100 JvOptionPane.DEFAULT_OPTION,
3101 JvOptionPane.ERROR_MESSAGE);
3102 serviceChangedDialog = null;
3111 "Errors reported by JABA discovery service. Check web services preferences.\n"
3118 private Runnable serviceChangedDialog = null;
3121 * start a thread to open a URL in the configured browser. Pops up a warning
3122 * dialog to the user if there is an exception when calling out to the browser
3127 public static void showUrl(final String url)
3129 showUrl(url, Desktop.instance);
3133 * Like showUrl but allows progress handler to be specified
3137 * (null) or object implementing IProgressIndicator
3139 public static void showUrl(final String url,
3140 final IProgressIndicator progress)
3142 new Thread(new Runnable()
3149 if (progress != null)
3151 progress.setProgressBar(MessageManager
3152 .formatMessage("status.opening_params", new Object[]
3153 { url }), this.hashCode());
3155 jalview.util.BrowserLauncher.openURL(url);
3156 } catch (Exception ex)
3158 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3160 .getString("label.web_browser_not_found_unix"),
3161 MessageManager.getString("label.web_browser_not_found"),
3162 JvOptionPane.WARNING_MESSAGE);
3164 ex.printStackTrace();
3166 if (progress != null)
3168 progress.setProgressBar(null, this.hashCode());
3174 public static WsParamSetManager wsparamManager = null;
3176 public static ParamManager getUserParameterStore()
3178 if (wsparamManager == null)
3180 wsparamManager = new WsParamSetManager();
3182 return wsparamManager;
3186 * static hyperlink handler proxy method for use by Jalview's internal windows
3190 public static void hyperlinkUpdate(HyperlinkEvent e)
3192 if (e.getEventType() == EventType.ACTIVATED)
3197 url = e.getURL().toString();
3198 Desktop.showUrl(url);
3199 } catch (Exception x)
3203 if (Cache.log != null)
3205 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3210 "Couldn't handle string " + url + " as a URL.");
3213 // ignore any exceptions due to dud links.
3220 * single thread that handles display of dialogs to user.
3222 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3225 * flag indicating if dialogExecutor should try to acquire a permit
3227 private volatile boolean dialogPause = true;
3232 private java.util.concurrent.Semaphore block = new Semaphore(0);
3234 private static groovy.ui.Console groovyConsole;
3237 * add another dialog thread to the queue
3241 public void addDialogThread(final Runnable prompter)
3243 dialogExecutor.submit(new Runnable()
3253 } catch (InterruptedException x)
3258 if (instance == null)
3264 SwingUtilities.invokeAndWait(prompter);
3265 } catch (Exception q)
3267 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3273 public void startDialogQueue()
3275 // set the flag so we don't pause waiting for another permit and semaphore
3276 // the current task to begin
3277 dialogPause = false;
3282 * Outputs an image of the desktop to file in EPS format, after prompting the
3283 * user for choice of Text or Lineart character rendering (unless a preference
3284 * has been set). The file name is generated as
3287 * Jalview_snapshot_nnnnn.eps where nnnnn is the current timestamp in milliseconds
3291 protected void snapShotWindow_actionPerformed(ActionEvent e)
3293 // currently the menu option to do this is not shown
3296 int width = getWidth();
3297 int height = getHeight();
3299 "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
3300 ImageWriterI writer = new ImageWriterI()
3303 public void exportImage(Graphics g) throws Exception
3306 Cache.log.info("Successfully written snapshot to file "
3307 + of.getAbsolutePath());
3310 String title = "View of desktop";
3311 ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
3313 exporter.doExport(of, this, width, height, title);
3317 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3318 * This respects (remembers) any previous 'exploded geometry' i.e. the size and
3319 * location last time the view was expanded (if any). However it does not
3320 * remember the split pane divider location - this is set to match the
3321 * 'exploding' frame.
3325 public void explodeViews(SplitFrame sf)
3327 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3328 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3329 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3331 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3333 int viewCount = topPanels.size();
3340 * Processing in reverse order works, forwards order leaves the first panels
3341 * not visible. I don't know why!
3343 for (int i = viewCount - 1; i >= 0; i--)
3346 * Make new top and bottom frames. These take over the respective
3347 * AlignmentPanel objects, including their AlignmentViewports, so the
3348 * cdna/protein relationships between the viewports is carried over to the
3351 * explodedGeometry holds the (x, y) position of the previously exploded
3352 * SplitFrame, and the (width, height) of the AlignFrame component
3354 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3355 AlignFrame newTopFrame = new AlignFrame(topPanel);
3356 newTopFrame.setSize(oldTopFrame.getSize());
3357 newTopFrame.setVisible(true);
3358 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3359 .getExplodedGeometry();
3360 if (geometry != null)
3362 newTopFrame.setSize(geometry.getSize());
3365 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3366 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3367 newBottomFrame.setSize(oldBottomFrame.getSize());
3368 newBottomFrame.setVisible(true);
3369 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3370 .getExplodedGeometry();
3371 if (geometry != null)
3373 newBottomFrame.setSize(geometry.getSize());
3376 topPanel.av.setGatherViewsHere(false);
3377 bottomPanel.av.setGatherViewsHere(false);
3378 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3380 if (geometry != null)
3382 splitFrame.setLocation(geometry.getLocation());
3384 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3388 * Clear references to the panels (now relocated in the new SplitFrames)
3389 * before closing the old SplitFrame.
3392 bottomPanels.clear();
3397 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3398 * back into the given SplitFrame as additional views. Note that the gathered
3399 * frames may themselves have multiple views.
3403 public void gatherViews(GSplitFrame source)
3406 * special handling of explodedGeometry for a view within a SplitFrame: - it
3407 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3408 * height) of the AlignFrame component
3410 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3411 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3412 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3413 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3414 myBottomFrame.viewport
3415 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3416 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3417 myTopFrame.viewport.setGatherViewsHere(true);
3418 myBottomFrame.viewport.setGatherViewsHere(true);
3419 String topViewId = myTopFrame.viewport.getSequenceSetId();
3420 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3422 JInternalFrame[] frames = desktop.getAllFrames();
3423 for (JInternalFrame frame : frames)
3425 if (frame instanceof SplitFrame && frame != source)
3427 SplitFrame sf = (SplitFrame) frame;
3428 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3429 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3430 boolean gatherThis = false;
3431 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3433 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3434 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3435 if (topViewId.equals(topPanel.av.getSequenceSetId())
3436 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3439 topPanel.av.setGatherViewsHere(false);
3440 bottomPanel.av.setGatherViewsHere(false);
3441 topPanel.av.setExplodedGeometry(
3442 new Rectangle(sf.getLocation(), topFrame.getSize()));
3443 bottomPanel.av.setExplodedGeometry(
3444 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3445 myTopFrame.addAlignmentPanel(topPanel, false);
3446 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3452 topFrame.getAlignPanels().clear();
3453 bottomFrame.getAlignPanels().clear();
3460 * The dust settles...give focus to the tab we did this from.
3462 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3465 public static groovy.ui.Console getGroovyConsole()
3467 return groovyConsole;
3471 * handles the payload of a drag and drop event.
3473 * TODO refactor to desktop utilities class
3476 * - Data source strings extracted from the drop event
3478 * - protocol for each data source extracted from the drop event
3482 * - the payload from the drop event
3485 public static void transferFromDropTarget(List<Object> files,
3486 List<DataSourceType> protocols, DropTargetDropEvent evt,
3487 Transferable t) throws Exception
3490 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3492 // DataFlavor[] flavors = t.getTransferDataFlavors();
3493 // for (int i = 0; i < flavors.length; i++) {
3494 // if (flavors[i].isFlavorJavaFileListType()) {
3495 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3496 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3497 // for (int j = 0; j < list.size(); j++) {
3498 // File file = (File) list.get(j);
3499 // byte[] data = getDroppedFileBytes(file);
3500 // fileName.setText(file.getName() + " - " + data.length + " " +
3501 // evt.getLocation());
3502 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3503 // target.setText(new String(data));
3505 // dtde.dropComplete(true);
3510 DataFlavor uriListFlavor = new DataFlavor(
3511 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3514 urlFlavour = new DataFlavor(
3515 "application/x-java-url; class=java.net.URL");
3516 } catch (ClassNotFoundException cfe)
3518 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3521 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3526 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3527 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3528 // means url may be null.
3531 protocols.add(DataSourceType.URL);
3532 files.add(url.toString());
3533 Cache.log.debug("Drop handled as URL dataflavor "
3534 + files.get(files.size() - 1));
3539 if (Platform.isAMac())
3542 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3546 } catch (Throwable ex)
3548 Cache.log.debug("URL drop handler failed.", ex);
3551 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3553 // Works on Windows and MacOSX
3554 Cache.log.debug("Drop handled as javaFileListFlavor");
3555 for (Object file : (List) t
3556 .getTransferData(DataFlavor.javaFileListFlavor))
3559 protocols.add(DataSourceType.FILE);
3564 // Unix like behaviour
3565 boolean added = false;
3567 if (t.isDataFlavorSupported(uriListFlavor))
3569 Cache.log.debug("Drop handled as uriListFlavor");
3570 // This is used by Unix drag system
3571 data = (String) t.getTransferData(uriListFlavor);
3575 // fallback to text: workaround - on OSX where there's a JVM bug
3576 Cache.log.debug("standard URIListFlavor failed. Trying text");
3577 // try text fallback
3578 DataFlavor textDf = new DataFlavor(
3579 "text/plain;class=java.lang.String");
3580 if (t.isDataFlavorSupported(textDf))
3582 data = (String) t.getTransferData(textDf);
3585 Cache.log.debug("Plain text drop content returned "
3586 + (data == null ? "Null - failed" : data));
3591 while (protocols.size() < files.size())
3593 Cache.log.debug("Adding missing FILE protocol for "
3594 + files.get(protocols.size()));
3595 protocols.add(DataSourceType.FILE);
3597 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3598 data, "\r\n"); st.hasMoreTokens();)
3601 String s = st.nextToken();
3602 if (s.startsWith("#"))
3604 // the line is a comment (as per the RFC 2483)
3607 java.net.URI uri = new java.net.URI(s);
3608 if (uri.getScheme().toLowerCase().startsWith("http"))
3610 protocols.add(DataSourceType.URL);
3611 files.add(uri.toString());
3615 // otherwise preserve old behaviour: catch all for file objects
3616 java.io.File file = new java.io.File(uri);
3617 protocols.add(DataSourceType.FILE);
3618 files.add(file.toString());
3623 if (Cache.log.isDebugEnabled())
3625 if (data == null || !added)
3628 if (t.getTransferDataFlavors() != null
3629 && t.getTransferDataFlavors().length > 0)
3632 "Couldn't resolve drop data. Here are the supported flavors:");
3633 for (DataFlavor fl : t.getTransferDataFlavors())
3636 "Supported transfer dataflavor: " + fl.toString());
3637 Object df = t.getTransferData(fl);
3640 Cache.log.debug("Retrieves: " + df);
3644 Cache.log.debug("Retrieved nothing");
3650 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3656 if (Platform.isWindows())
3659 Cache.log.debug("Scanning dropped content for Windows Link Files");
3661 // resolve any .lnk files in the file drop
3662 for (int f = 0; f < files.size(); f++)
3664 String source = files.get(f).toString().toLowerCase();
3665 if (protocols.get(f).equals(DataSourceType.FILE)
3666 && (source.endsWith(".lnk") || source.endsWith(".url")
3667 || source.endsWith(".site")))
3671 Object obj = files.get(f);
3672 File lf = (obj instanceof File ? (File) obj
3673 : new File((String) obj));
3674 // process link file to get a URL
3675 Cache.log.debug("Found potential link file: " + lf);
3676 WindowsShortcut wscfile = new WindowsShortcut(lf);
3677 String fullname = wscfile.getRealFilename();
3678 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3679 files.set(f, fullname);
3680 Cache.log.debug("Parsed real filename " + fullname
3681 + " to extract protocol: " + protocols.get(f));
3682 } catch (Exception ex)
3685 "Couldn't parse " + files.get(f) + " as a link file.",
3694 * Sets the Preferences property for experimental features to True or False
3695 * depending on the state of the controlling menu item
3698 protected void showExperimental_actionPerformed(boolean selected)
3700 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3704 * Answers a (possibly empty) list of any structure viewer frames (currently for
3705 * either Jmol or Chimera) which are currently open. This may optionally be
3706 * restricted to viewers of a specified class, or viewers linked to a specified
3710 * if not null, only return viewers linked to this panel
3711 * @param structureViewerClass
3712 * if not null, only return viewers of this class
3715 public List<StructureViewerBase> getStructureViewers(
3716 AlignmentPanel apanel,
3717 Class<? extends StructureViewerBase> structureViewerClass)
3719 List<StructureViewerBase> result = new ArrayList<>();
3720 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3722 for (JInternalFrame frame : frames)
3724 if (frame instanceof StructureViewerBase)
3726 if (structureViewerClass == null
3727 || structureViewerClass.isInstance(frame))
3730 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3732 result.add((StructureViewerBase) frame);