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.io.DataSourceType;
30 import jalview.io.FileFormat;
31 import jalview.io.FileFormatException;
32 import jalview.io.FileFormatI;
33 import jalview.io.FileFormats;
34 import jalview.io.FileLoader;
35 import jalview.io.FormatAdapter;
36 import jalview.io.IdentifyFile;
37 import jalview.io.JalviewFileChooser;
38 import jalview.io.JalviewFileView;
39 import jalview.jbgui.GSplitFrame;
40 import jalview.jbgui.GStructureViewer;
41 import jalview.structure.StructureSelectionManager;
42 import jalview.urls.IdOrgSettings;
43 import jalview.util.ImageMaker;
44 import jalview.util.MessageManager;
45 import jalview.util.Platform;
46 import jalview.util.UrlConstants;
47 import jalview.util.dialogrunner.RunResponse;
48 import jalview.viewmodel.AlignmentViewport;
49 import jalview.ws.params.ParamManager;
50 import jalview.ws.utils.UrlDownloadClient;
52 import java.awt.BorderLayout;
53 import java.awt.Color;
54 import java.awt.Dimension;
55 import java.awt.FontMetrics;
56 import java.awt.Graphics;
57 import java.awt.GridLayout;
58 import java.awt.Point;
59 import java.awt.Rectangle;
60 import java.awt.Toolkit;
61 import java.awt.Window;
62 import java.awt.datatransfer.Clipboard;
63 import java.awt.datatransfer.ClipboardOwner;
64 import java.awt.datatransfer.DataFlavor;
65 import java.awt.datatransfer.Transferable;
66 import java.awt.dnd.DnDConstants;
67 import java.awt.dnd.DropTargetDragEvent;
68 import java.awt.dnd.DropTargetDropEvent;
69 import java.awt.dnd.DropTargetEvent;
70 import java.awt.dnd.DropTargetListener;
71 import java.awt.event.ActionEvent;
72 import java.awt.event.ActionListener;
73 import java.awt.event.InputEvent;
74 import java.awt.event.KeyEvent;
75 import java.awt.event.MouseAdapter;
76 import java.awt.event.MouseEvent;
77 import java.awt.event.WindowAdapter;
78 import java.awt.event.WindowEvent;
79 import java.beans.PropertyChangeEvent;
80 import java.beans.PropertyChangeListener;
81 import java.io.BufferedInputStream;
83 import java.io.FileOutputStream;
84 import java.io.IOException;
86 import java.util.ArrayList;
87 import java.util.Hashtable;
88 import java.util.List;
89 import java.util.ListIterator;
90 import java.util.StringTokenizer;
91 import java.util.Vector;
92 import java.util.concurrent.ExecutorService;
93 import java.util.concurrent.Executors;
94 import java.util.concurrent.Semaphore;
96 import javax.swing.AbstractAction;
97 import javax.swing.Action;
98 import javax.swing.ActionMap;
99 import javax.swing.Box;
100 import javax.swing.BoxLayout;
101 import javax.swing.DefaultDesktopManager;
102 import javax.swing.DesktopManager;
103 import javax.swing.InputMap;
104 import javax.swing.JButton;
105 import javax.swing.JCheckBox;
106 import javax.swing.JComboBox;
107 import javax.swing.JComponent;
108 import javax.swing.JDesktopPane;
109 import javax.swing.JFrame;
110 import javax.swing.JInternalFrame;
111 import javax.swing.JLabel;
112 import javax.swing.JMenuItem;
113 import javax.swing.JPanel;
114 import javax.swing.JPopupMenu;
115 import javax.swing.JProgressBar;
116 import javax.swing.KeyStroke;
117 import javax.swing.SwingUtilities;
118 import javax.swing.event.HyperlinkEvent;
119 import javax.swing.event.HyperlinkEvent.EventType;
120 import javax.swing.event.InternalFrameAdapter;
121 import javax.swing.event.InternalFrameEvent;
122 import javax.swing.event.MenuEvent;
123 import javax.swing.event.MenuListener;
125 import org.stackoverflowusers.file.WindowsShortcut;
132 * @version $Revision: 1.155 $
134 public class Desktop extends jalview.jbgui.GDesktop
135 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
136 jalview.api.StructureSelectionManagerProvider
138 private static int DEFAULT_MIN_WIDTH = 300;
140 private static int DEFAULT_MIN_HEIGHT = 250;
142 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
144 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
146 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
148 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
151 * news reader - null if it was never started.
153 private BlogReader jvnews = null;
155 private File projectFile;
159 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
161 public void addJalviewPropertyChangeListener(
162 PropertyChangeListener listener)
164 changeSupport.addJalviewPropertyChangeListener(listener);
168 * @param propertyName
170 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
171 * java.beans.PropertyChangeListener)
173 public void addJalviewPropertyChangeListener(String propertyName,
174 PropertyChangeListener listener)
176 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
180 * @param propertyName
182 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
183 * java.beans.PropertyChangeListener)
185 public void removeJalviewPropertyChangeListener(String propertyName,
186 PropertyChangeListener listener)
188 changeSupport.removeJalviewPropertyChangeListener(propertyName,
192 /** Singleton Desktop instance */
193 public static Desktop instance;
195 public static MyDesktopPane desktop;
197 public static MyDesktopPane getDesktop()
199 // BH 2018 could use currentThread() here as a reference to a
200 // Hashtable<Thread, MyDesktopPane> in JavaScript
204 static int openFrameCount = 0;
206 static final int xOffset = 30;
208 static final int yOffset = 30;
210 public static jalview.ws.jws1.Discoverer discoverer;
212 public static Object[] jalviewClipboard;
214 public static boolean internalCopy = false;
216 static int fileLoadingCount = 0;
218 class MyDesktopManager implements DesktopManager
221 private DesktopManager delegate;
223 public MyDesktopManager(DesktopManager delegate)
225 this.delegate = delegate;
229 public void activateFrame(JInternalFrame f)
233 delegate.activateFrame(f);
234 } catch (NullPointerException npe)
236 Point p = getMousePosition();
237 instance.showPasteMenu(p.x, p.y);
242 public void beginDraggingFrame(JComponent f)
244 delegate.beginDraggingFrame(f);
248 public void beginResizingFrame(JComponent f, int direction)
250 delegate.beginResizingFrame(f, direction);
254 public void closeFrame(JInternalFrame f)
256 delegate.closeFrame(f);
260 public void deactivateFrame(JInternalFrame f)
262 delegate.deactivateFrame(f);
266 public void deiconifyFrame(JInternalFrame f)
268 delegate.deiconifyFrame(f);
272 public void dragFrame(JComponent f, int newX, int newY)
278 delegate.dragFrame(f, newX, newY);
282 public void endDraggingFrame(JComponent f)
284 delegate.endDraggingFrame(f);
289 public void endResizingFrame(JComponent f)
291 delegate.endResizingFrame(f);
296 public void iconifyFrame(JInternalFrame f)
298 delegate.iconifyFrame(f);
302 public void maximizeFrame(JInternalFrame f)
304 delegate.maximizeFrame(f);
308 public void minimizeFrame(JInternalFrame f)
310 delegate.minimizeFrame(f);
314 public void openFrame(JInternalFrame f)
316 delegate.openFrame(f);
320 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
327 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
331 public void setBoundsForFrame(JComponent f, int newX, int newY,
332 int newWidth, int newHeight)
334 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
337 // All other methods, simply delegate
342 * Creates a new Desktop object.
347 * A note to implementors. It is ESSENTIAL that any activities that might
348 * block are spawned off as threads rather than waited for during this
352 doVamsasClientCheck();
354 doConfigureStructurePrefs();
355 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
356 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
357 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
359 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
361 desktop = new MyDesktopPane(selmemusage);
362 showMemusage.setSelected(selmemusage);
363 desktop.setBackground(Color.white);
364 getContentPane().setLayout(new BorderLayout());
365 // alternate config - have scrollbars - see notes in JAL-153
366 // JScrollPane sp = new JScrollPane();
367 // sp.getViewport().setView(desktop);
368 // getContentPane().add(sp, BorderLayout.CENTER);
369 getContentPane().add(desktop, BorderLayout.CENTER);
370 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
372 // This line prevents Windows Look&Feel resizing all new windows to maximum
373 // if previous window was maximised
374 desktop.setDesktopManager(
375 new MyDesktopManager(
376 (Platform.isWindows() ? new DefaultDesktopManager()
378 ? new AquaInternalFrameManager(
379 desktop.getDesktopManager())
380 : desktop.getDesktopManager())));
382 Rectangle dims = getLastKnownDimensions("");
389 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
390 int xPos = Math.max(5, (screenSize.width - 900) / 2);
391 int yPos = Math.max(5, (screenSize.height - 650) / 2);
392 setBounds(xPos, yPos, 900, 650);
401 jconsole = new Console(this, showjconsole);
402 // add essential build information
403 jconsole.setHeader("Jalview Version: "
404 + jalview.bin.Cache.getProperty("VERSION") + "\n"
405 + "Jalview Installation: "
406 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
407 + "\n" + "Build Date: "
408 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
409 + "Java version: " + System.getProperty("java.version") + "\n"
410 + System.getProperty("os.arch") + " "
411 + System.getProperty("os.name") + " "
412 + System.getProperty("os.version"));
414 showConsole(showjconsole);
416 showNews.setVisible(false);
418 experimentalFeatures.setSelected(showExperimental());
420 getIdentifiersOrgData();
424 // Spawn a thread that shows the splashscreen
426 SwingUtilities.invokeLater(new Runnable()
435 // Thread off a new instance of the file chooser - this reduces the time it
436 // takes to open it later on.
437 new Thread(new Runnable()
442 Cache.log.debug("Filechooser init thread started.");
443 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
444 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
446 Cache.log.debug("Filechooser init thread finished.");
449 // Add the service change listener
450 changeSupport.addJalviewPropertyChangeListener("services",
451 new PropertyChangeListener()
455 public void propertyChange(PropertyChangeEvent evt)
457 Cache.log.debug("Firing service changed event for "
458 + evt.getNewValue());
459 JalviewServicesChanged(evt);
464 } // end BH 2018 ignore
466 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
468 this.addWindowListener(new WindowAdapter()
471 public void windowClosing(WindowEvent evt)
478 this.addMouseListener(ma = new MouseAdapter()
481 public void mousePressed(MouseEvent evt)
483 if (evt.isPopupTrigger()) // Mac
485 showPasteMenu(evt.getX(), evt.getY());
490 public void mouseReleased(MouseEvent evt)
492 if (evt.isPopupTrigger()) // Windows
494 showPasteMenu(evt.getX(), evt.getY());
498 desktop.addMouseListener(ma);
503 * Answers true if user preferences to enable experimental features is True
508 public boolean showExperimental()
510 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
511 Boolean.FALSE.toString());
512 return Boolean.valueOf(experimental).booleanValue();
515 public void doConfigureStructurePrefs()
517 // configure services
518 StructureSelectionManager ssm = StructureSelectionManager
519 .getStructureSelectionManager(this);
520 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
522 ssm.setAddTempFacAnnot(jalview.bin.Cache
523 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
524 ssm.setProcessSecondaryStructure(jalview.bin.Cache
525 .getDefault(Preferences.STRUCT_FROM_PDB, true));
526 ssm.setSecStructServices(
527 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
531 ssm.setAddTempFacAnnot(false);
532 ssm.setProcessSecondaryStructure(false);
533 ssm.setSecStructServices(false);
537 public void checkForNews()
546 final Desktop me = this;
547 // Thread off the news reader, in case there are connection problems.
548 addDialogThread(new Runnable()
553 Cache.log.debug("Starting news thread.");
555 jvnews = new BlogReader(me);
556 showNews.setVisible(true);
557 Cache.log.debug("Completed news thread.");
563 public void getIdentifiersOrgData()
565 // Thread off the identifiers fetcher
566 addDialogThread(new Runnable()
571 Cache.log.debug("Downloading data from identifiers.org");
572 UrlDownloadClient client = new UrlDownloadClient();
575 client.download(IdOrgSettings.getUrl(),
576 IdOrgSettings.getDownloadLocation());
577 } catch (IOException e)
579 Cache.log.debug("Exception downloading identifiers.org data"
587 protected void showNews_actionPerformed(ActionEvent e)
589 showNews(showNews.isSelected());
592 void showNews(boolean visible)
601 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
602 showNews.setSelected(visible);
603 if (visible && !jvnews.isVisible())
605 new Thread(new Runnable()
610 long now = System.currentTimeMillis();
611 Desktop.instance.setProgressBar(
612 MessageManager.getString("status.refreshing_news"),
614 jvnews.refreshNews();
615 Desktop.instance.setProgressBar(null, now);
624 * recover the last known dimensions for a jalview window
627 * - empty string is desktop, all other windows have unique prefix
628 * @return null or last known dimensions scaled to current geometry (if last
629 * window geom was known)
631 Rectangle getLastKnownDimensions(String windowName)
633 // TODO: lock aspect ratio for scaling desktop Bug #0058199
634 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
635 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
636 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
637 String width = jalview.bin.Cache
638 .getProperty(windowName + "SCREEN_WIDTH");
639 String height = jalview.bin.Cache
640 .getProperty(windowName + "SCREEN_HEIGHT");
641 if ((x != null) && (y != null) && (width != null) && (height != null))
643 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
644 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
645 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
647 // attempt #1 - try to cope with change in screen geometry - this
648 // version doesn't preserve original jv aspect ratio.
649 // take ratio of current screen size vs original screen size.
650 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
651 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
652 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
653 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
654 // rescale the bounds depending upon the current screen geometry.
655 ix = (int) (ix * sw);
656 iw = (int) (iw * sw);
657 iy = (int) (iy * sh);
658 ih = (int) (ih * sh);
659 while (ix >= screenSize.width)
661 jalview.bin.Cache.log.debug(
662 "Window geometry location recall error: shifting horizontal to within screenbounds.");
663 ix -= screenSize.width;
665 while (iy >= screenSize.height)
667 jalview.bin.Cache.log.debug(
668 "Window geometry location recall error: shifting vertical to within screenbounds.");
669 iy -= screenSize.height;
671 jalview.bin.Cache.log.debug(
672 "Got last known dimensions for " + windowName + ": x:" + ix
673 + " y:" + iy + " width:" + iw + " height:" + ih);
675 // return dimensions for new instance
676 return new Rectangle(ix, iy, iw, ih);
681 private void doVamsasClientCheck()
683 if (/** @j2sNative false && */ // BH 2018
684 jalview.bin.Cache.vamsasJarsPresent())
686 setupVamsasDisconnectedGui();
687 VamsasMenu.setVisible(true);
688 final Desktop us = this;
689 VamsasMenu.addMenuListener(new MenuListener()
691 // this listener remembers when the menu was first selected, and
692 // doesn't rebuild the session list until it has been cleared and
694 boolean refresh = true;
697 public void menuCanceled(MenuEvent e)
703 public void menuDeselected(MenuEvent e)
709 public void menuSelected(MenuEvent e)
713 us.buildVamsasStMenu();
718 vamsasStart.setVisible(true);
722 void showPasteMenu(int x, int y)
724 JPopupMenu popup = new JPopupMenu();
725 JMenuItem item = new JMenuItem(
726 MessageManager.getString("label.paste_new_window"));
727 item.addActionListener(new ActionListener()
730 public void actionPerformed(ActionEvent evt)
737 popup.show(this, x, y);
744 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
745 Transferable contents = c.getContents(this);
747 if (contents != null)
749 String file = (String) contents
750 .getTransferData(DataFlavor.stringFlavor);
752 FileFormatI format = new IdentifyFile().identify(file,
753 DataSourceType.PASTE);
755 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
758 } catch (Exception ex)
761 "Unable to paste alignment from system clipboard:\n" + ex);
766 * Adds and opens the given frame to the desktop
777 public static synchronized void addInternalFrame(
778 final JInternalFrame frame, String title, int w, int h)
780 addInternalFrame(frame, title, true, w, h, true, false);
784 * Add an internal frame to the Jalview desktop
791 * When true, display frame immediately, otherwise, caller must call
792 * setVisible themselves.
798 public static synchronized void addInternalFrame(
799 final JInternalFrame frame, String title, boolean makeVisible,
802 addInternalFrame(frame, title, makeVisible, w, h, true, false);
806 * Add an internal frame to the Jalview desktop and make it visible
819 public static synchronized void addInternalFrame(
820 final JInternalFrame frame, String title, int w, int h,
823 addInternalFrame(frame, title, true, w, h, resizable, false);
827 * Add an internal frame to the Jalview desktop
834 * When true, display frame immediately, otherwise, caller must call
835 * setVisible themselves.
842 * @param ignoreMinSize
843 * Do not set the default minimum size for frame
845 public static synchronized void addInternalFrame(
846 final JInternalFrame frame, String title, boolean makeVisible,
847 int w, int h, boolean resizable, boolean ignoreMinSize)
850 // TODO: allow callers to determine X and Y position of frame (eg. via
852 // TODO: consider fixing method to update entries in the window submenu with
853 // the current window title
855 frame.setTitle(title);
856 if (frame.getWidth() < 1 || frame.getHeight() < 1)
860 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
861 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
862 // IF JALVIEW IS RUNNING HEADLESS
863 // ///////////////////////////////////////////////
864 if (instance == null || (System.getProperty("java.awt.headless") != null
865 && System.getProperty("java.awt.headless").equals("true")))
874 frame.setMinimumSize(
875 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
877 // Set default dimension for Alignment Frame window.
878 // The Alignment Frame window could be added from a number of places,
880 // I did this here in order not to miss out on any Alignment frame.
881 if (frame instanceof AlignFrame)
883 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
884 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
888 frame.setVisible(makeVisible);
889 frame.setClosable(true);
890 frame.setResizable(resizable);
891 frame.setMaximizable(resizable);
892 frame.setIconifiable(resizable);
893 frame.setOpaque(/** @j2sNative true || */
896 if (frame.getX() < 1 && frame.getY() < 1)
898 frame.setLocation(xOffset * openFrameCount,
899 yOffset * ((openFrameCount - 1) % 10) + yOffset);
903 * add an entry for the new frame in the Window menu
904 * (and remove it when the frame is closed)
906 final JMenuItem menuItem = new JMenuItem(title);
907 frame.addInternalFrameListener(new InternalFrameAdapter()
910 public void internalFrameActivated(InternalFrameEvent evt)
912 JInternalFrame itf = desktop.getSelectedFrame();
915 if (itf instanceof AlignFrame)
917 Jalview.setCurrentAlignFrame((AlignFrame) itf);
924 public void internalFrameClosed(InternalFrameEvent evt)
926 PaintRefresher.RemoveComponent(frame);
929 * defensive check to prevent frames being
930 * added half off the window
932 if (openFrameCount > 0)
938 * ensure no reference to alignFrame retained by menu item listener
940 if (menuItem.getActionListeners().length > 0)
942 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
944 windowMenu.remove(menuItem);
948 menuItem.addActionListener(new ActionListener()
951 public void actionPerformed(ActionEvent e)
955 frame.setSelected(true);
956 frame.setIcon(false);
957 } catch (java.beans.PropertyVetoException ex)
964 setKeyBindings(frame);
968 windowMenu.add(menuItem);
973 frame.setSelected(true);
974 frame.requestFocus();
975 } catch (java.beans.PropertyVetoException ve)
977 } catch (java.lang.ClassCastException cex)
980 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
986 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
991 private static void setKeyBindings(JInternalFrame frame)
993 @SuppressWarnings("serial")
994 final Action closeAction = new AbstractAction()
997 public void actionPerformed(ActionEvent e)
1004 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1006 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1007 InputEvent.CTRL_DOWN_MASK);
1008 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1009 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1011 InputMap inputMap = frame
1012 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1013 String ctrlW = ctrlWKey.toString();
1014 inputMap.put(ctrlWKey, ctrlW);
1015 inputMap.put(cmdWKey, ctrlW);
1017 ActionMap actionMap = frame.getActionMap();
1018 actionMap.put(ctrlW, closeAction);
1022 public void lostOwnership(Clipboard clipboard, Transferable contents)
1026 Desktop.jalviewClipboard = null;
1029 internalCopy = false;
1033 public void dragEnter(DropTargetDragEvent evt)
1038 public void dragExit(DropTargetEvent evt)
1043 public void dragOver(DropTargetDragEvent evt)
1048 public void dropActionChanged(DropTargetDragEvent evt)
1059 public void drop(DropTargetDropEvent evt)
1061 boolean success = true;
1062 // JAL-1552 - acceptDrop required before getTransferable call for
1063 // Java's Transferable for native dnd
1064 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1065 Transferable t = evt.getTransferable();
1066 List<Object> files = new ArrayList<>();
1067 List<DataSourceType> protocols = new ArrayList<>();
1071 Desktop.transferFromDropTarget(files, protocols, evt, t);
1072 } catch (Exception e)
1074 e.printStackTrace();
1082 for (int i = 0; i < files.size(); i++)
1084 // BH 2018 File or String
1085 Object file = files.get(i);
1086 String fileName = file.toString();
1087 DataSourceType protocol = (protocols == null)
1088 ? DataSourceType.FILE
1090 FileFormatI format = null;
1092 if (fileName.endsWith(".jar"))
1094 format = FileFormat.Jalview;
1099 format = new IdentifyFile().identify(file, protocol);
1102 new FileLoader().LoadFile(null, file, protocol, format);
1105 } catch (Exception ex)
1110 evt.dropComplete(success); // need this to ensure input focus is properly
1111 // transfered to any new windows created
1121 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1123 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1124 final JalviewFileChooser chooser = JalviewFileChooser
1125 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1127 chooser.setFileView(new JalviewFileView());
1128 chooser.setDialogTitle(
1129 MessageManager.getString("label.open_local_file"));
1130 chooser.setToolTipText(MessageManager.getString("action.open"));
1132 chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION)
1138 File selectedFile = chooser.getSelectedFile();
1139 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1141 FileFormatI format = chooser.getSelectedFormat();
1144 * Call IdentifyFile to verify the file contains what its extension implies.
1145 * Skip this step for dynamically added file formats, because
1146 * IdentifyFile does not know how to recognise them.
1148 if (FileFormats.getInstance().isIdentifiable(format))
1152 format = new IdentifyFile().identify(selectedFile,
1153 DataSourceType.FILE);
1154 } catch (FileFormatException e)
1156 // format = null; //??
1160 new FileLoader().LoadFile(viewport, selectedFile,
1161 DataSourceType.FILE, format);
1163 }).openDialog(this);
1173 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1175 // This construct allows us to have a wider textfield
1177 JLabel label = new JLabel(
1178 MessageManager.getString("label.input_file_url"));
1180 JComboBox history = new JComboBox();
1181 JPanel panel = new JPanel(new GridLayout(2, 1));
1184 history.setPreferredSize(new Dimension(400, 20));
1185 history.setEditable(true);
1186 history.addItem("http://www.");
1188 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1192 if (historyItems != null)
1194 st = new StringTokenizer(historyItems, "\t");
1196 while (st.hasMoreTokens())
1198 history.addItem(st.nextElement());
1202 // BH 2018 -- providing a callback for SwingJS
1203 // dialogOption is just a simple way to provide
1204 // context for the modal-like response.
1205 // The only requirement is that desktop implement
1206 // PropertyChangeListener, which is used already in Java
1207 // for changes in input value and such within the dialogs.
1209 String dialogOption = "label.input_alignment_from_url";
1210 desktop.dialogData = new Object[] { dialogOption, viewport, history };
1211 desktop.onDialogReturn(
1212 JvOptionPane.showInternalConfirmDialog(desktop, panel,
1213 MessageManager.getString(dialogOption),
1214 JvOptionPane.OK_CANCEL_OPTION));
1216 // no code may follow this, as SwingJS will not block
1217 // callback in JavaScript comes via a property change event,
1218 // thus going into desktop.onDialogReturn(int) just the same as
1225 * Opens the CutAndPaste window for the user to paste an alignment in to
1228 * - if not null, the pasted alignment is added to the current
1229 * alignment; if null, to a new alignment window
1232 public void inputTextboxMenuItem_actionPerformed(
1233 AlignmentViewPanel viewPanel)
1235 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1236 cap.setForInput(viewPanel);
1237 Desktop.addInternalFrame(cap,
1238 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1248 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1249 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1251 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1252 screen.height + "");
1253 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1254 getWidth(), getHeight()));
1256 if (jconsole != null)
1258 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1259 jconsole.stopConsole();
1263 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1266 if (dialogExecutor != null)
1268 dialogExecutor.shutdownNow();
1270 closeAll_actionPerformed(null);
1272 if (groovyConsole != null)
1274 // suppress a possible repeat prompt to save script
1275 groovyConsole.setDirty(false);
1276 groovyConsole.exit();
1281 private void storeLastKnownDimensions(String string, Rectangle jc)
1283 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1284 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1285 + " height:" + jc.height);
1287 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1288 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1289 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1290 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1300 public void aboutMenuItem_actionPerformed(ActionEvent e)
1302 // StringBuffer message = getAboutMessage(false);
1303 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1305 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1306 new Thread(new Runnable()
1311 new SplashScreen(true);
1316 public StringBuffer getAboutMessage(boolean shortv)
1318 StringBuffer message = new StringBuffer();
1319 message.append("<html>");
1322 message.append("<h1><strong>Version: "
1323 + jalview.bin.Cache.getProperty("VERSION")
1324 + "</strong></h1>");
1325 message.append("<strong>Last Updated: <em>"
1326 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1327 + "</em></strong>");
1333 message.append("<strong>Version "
1334 + jalview.bin.Cache.getProperty("VERSION")
1335 + "; last updated: "
1336 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1339 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1340 .equals("Checking"))
1342 message.append("<br>...Checking latest version...</br>");
1344 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1345 .equals(jalview.bin.Cache.getProperty("VERSION")))
1347 boolean red = false;
1348 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1349 .indexOf("automated build") == -1)
1352 // Displayed when code version and jnlp version do not match and code
1353 // version is not a development build
1354 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1357 message.append("<br>!! Version "
1358 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1360 + " is available for download from "
1361 + jalview.bin.Cache.getDefault("www.jalview.org",
1362 "http://www.jalview.org")
1366 message.append("</div>");
1369 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1371 "The Jalview Authors (See AUTHORS file for current list)")
1372 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1373 + "<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"
1374 + "<br><br>If you use Jalview, please cite:"
1375 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1376 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1377 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1389 public void documentationMenuItem_actionPerformed(ActionEvent e)
1393 Help.showHelpWindow();
1394 } catch (Exception ex)
1400 public void closeAll_actionPerformed(ActionEvent e)
1402 // TODO show a progress bar while closing?
1403 JInternalFrame[] frames = desktop.getAllFrames();
1404 for (int i = 0; i < frames.length; i++)
1408 frames[i].setClosed(true);
1409 } catch (java.beans.PropertyVetoException ex)
1413 Jalview.setCurrentAlignFrame(null);
1414 System.out.println("ALL CLOSED");
1415 if (v_client != null)
1417 // TODO clear binding to vamsas document objects on close_all
1421 * reset state of singleton objects as appropriate (clear down session state
1422 * when all windows are closed)
1424 StructureSelectionManager ssm = StructureSelectionManager
1425 .getStructureSelectionManager(this);
1433 public void raiseRelated_actionPerformed(ActionEvent e)
1435 reorderAssociatedWindows(false, false);
1439 public void minimizeAssociated_actionPerformed(ActionEvent e)
1441 reorderAssociatedWindows(true, false);
1444 void closeAssociatedWindows()
1446 reorderAssociatedWindows(false, true);
1452 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1456 protected void garbageCollect_actionPerformed(ActionEvent e)
1458 // We simply collect the garbage
1459 jalview.bin.Cache.log.debug("Collecting garbage...");
1461 jalview.bin.Cache.log.debug("Finished garbage collection.");
1468 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1472 protected void showMemusage_actionPerformed(ActionEvent e)
1474 desktop.showMemoryUsage(showMemusage.isSelected());
1481 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1485 protected void showConsole_actionPerformed(ActionEvent e)
1487 showConsole(showConsole.isSelected());
1490 Console jconsole = null;
1493 * control whether the java console is visible or not
1497 void showConsole(boolean selected)
1499 // TODO: decide if we should update properties file
1500 if (jconsole != null) // BH 2018
1502 showConsole.setSelected(selected);
1503 Cache.setProperty("SHOW_JAVA_CONSOLE",
1504 Boolean.valueOf(selected).toString());
1505 jconsole.setVisible(selected);
1509 void reorderAssociatedWindows(boolean minimize, boolean close)
1511 JInternalFrame[] frames = desktop.getAllFrames();
1512 if (frames == null || frames.length < 1)
1517 AlignmentViewport source = null, target = null;
1518 if (frames[0] instanceof AlignFrame)
1520 source = ((AlignFrame) frames[0]).getCurrentView();
1522 else if (frames[0] instanceof TreePanel)
1524 source = ((TreePanel) frames[0]).getViewPort();
1526 else if (frames[0] instanceof PCAPanel)
1528 source = ((PCAPanel) frames[0]).av;
1530 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1532 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1537 for (int i = 0; i < frames.length; i++)
1540 if (frames[i] == null)
1544 if (frames[i] instanceof AlignFrame)
1546 target = ((AlignFrame) frames[i]).getCurrentView();
1548 else if (frames[i] instanceof TreePanel)
1550 target = ((TreePanel) frames[i]).getViewPort();
1552 else if (frames[i] instanceof PCAPanel)
1554 target = ((PCAPanel) frames[i]).av;
1556 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1558 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1561 if (source == target)
1567 frames[i].setClosed(true);
1571 frames[i].setIcon(minimize);
1574 frames[i].toFront();
1578 } catch (java.beans.PropertyVetoException ex)
1593 protected void preferences_actionPerformed(ActionEvent e)
1605 public void saveState_actionPerformed(ActionEvent e)
1607 // TODO: JAL-3048 not needed for Jalview-JS
1609 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1612 chooser.setFileView(new JalviewFileView());
1613 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1615 int value = chooser.showSaveDialog(this);
1617 if (value == JalviewFileChooser.APPROVE_OPTION)
1619 final Desktop me = this;
1620 final java.io.File choice = chooser.getSelectedFile();
1621 setProjectFile(choice);
1623 new Thread(new Runnable()
1628 // TODO: refactor to Jalview desktop session controller action.
1629 setProgressBar(MessageManager.formatMessage(
1630 "label.saving_jalview_project", new Object[]
1631 { choice.getName() }), choice.hashCode());
1632 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1633 choice.getParent());
1634 // TODO catch and handle errors for savestate
1635 // TODO prevent user from messing with the Desktop whilst we're saving
1638 new Jalview2XML().saveState(choice);
1639 } catch (OutOfMemoryError oom)
1642 "Whilst saving current state to " + choice.getName(),
1644 } catch (Exception ex)
1647 "Problems whilst trying to save to " + choice.getName(),
1649 JvOptionPane.showMessageDialog(me,
1650 MessageManager.formatMessage(
1651 "label.error_whilst_saving_current_state_to",
1653 { choice.getName() }),
1654 MessageManager.getString("label.couldnt_save_project"),
1655 JvOptionPane.WARNING_MESSAGE);
1657 setProgressBar(null, choice.hashCode());
1663 private void setProjectFile(File choice)
1665 this.projectFile = choice;
1668 public File getProjectFile()
1670 return this.projectFile;
1680 public void loadState_actionPerformed(ActionEvent e)
1682 // TODO: JAL-3048 not needed for Jalview-JS
1684 JalviewFileChooser chooser = new JalviewFileChooser(
1685 Cache.getProperty("LAST_DIRECTORY"), new String[]
1688 { "Jalview Project", "Jalview Project (old)" },
1690 chooser.setFileView(new JalviewFileView());
1691 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1693 int value = chooser.showOpenDialog(this);
1695 if (value == JalviewFileChooser.APPROVE_OPTION)
1697 final File selectedFile = chooser.getSelectedFile();
1698 setProjectFile(selectedFile);
1699 final String choice = selectedFile.getAbsolutePath();
1700 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1701 new Thread(new Runnable()
1706 setProgressBar(MessageManager.formatMessage(
1707 "label.loading_jalview_project", new Object[]
1708 { choice }), choice.hashCode());
1711 new Jalview2XML().loadJalviewAlign(choice);
1712 } catch (OutOfMemoryError oom)
1714 new OOMWarning("Whilst loading project from " + choice, oom);
1715 } catch (Exception ex)
1718 "Problems whilst loading project from " + choice, ex);
1719 JvOptionPane.showMessageDialog(Desktop.desktop,
1720 MessageManager.formatMessage(
1721 "label.error_whilst_loading_project_from",
1724 MessageManager.getString("label.couldnt_load_project"),
1725 JvOptionPane.WARNING_MESSAGE);
1727 setProgressBar(null, choice.hashCode());
1734 public void inputSequence_actionPerformed(ActionEvent e)
1736 new SequenceFetcher(this);
1739 JPanel progressPanel;
1741 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1743 public void startLoading(final Object fileName)
1745 if (fileLoadingCount == 0)
1747 fileLoadingPanels.add(addProgressPanel(MessageManager
1748 .formatMessage("label.loading_file", new Object[]
1754 private JPanel addProgressPanel(String string)
1756 if (progressPanel == null)
1758 progressPanel = new JPanel(new GridLayout(1, 1));
1759 totalProgressCount = 0;
1760 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1762 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1763 JProgressBar progressBar = new JProgressBar();
1764 progressBar.setIndeterminate(true);
1766 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1768 thisprogress.add(progressBar, BorderLayout.CENTER);
1769 progressPanel.add(thisprogress);
1770 ((GridLayout) progressPanel.getLayout()).setRows(
1771 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1772 ++totalProgressCount;
1773 instance.validate();
1774 return thisprogress;
1777 int totalProgressCount = 0;
1779 private void removeProgressPanel(JPanel progbar)
1781 if (progressPanel != null)
1783 synchronized (progressPanel)
1785 progressPanel.remove(progbar);
1786 GridLayout gl = (GridLayout) progressPanel.getLayout();
1787 gl.setRows(gl.getRows() - 1);
1788 if (--totalProgressCount < 1)
1790 this.getContentPane().remove(progressPanel);
1791 progressPanel = null;
1798 public void stopLoading()
1801 if (fileLoadingCount < 1)
1803 while (fileLoadingPanels.size() > 0)
1805 removeProgressPanel(fileLoadingPanels.remove(0));
1807 fileLoadingPanels.clear();
1808 fileLoadingCount = 0;
1813 public static int getViewCount(String alignmentId)
1815 AlignmentViewport[] aps = getViewports(alignmentId);
1816 return (aps == null) ? 0 : aps.length;
1821 * @param alignmentId
1822 * - if null, all sets are returned
1823 * @return all AlignmentPanels concerning the alignmentId sequence set
1825 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1827 if (Desktop.desktop == null)
1829 // no frames created and in headless mode
1830 // TODO: verify that frames are recoverable when in headless mode
1833 List<AlignmentPanel> aps = new ArrayList<>();
1834 AlignFrame[] frames = getAlignFrames();
1839 for (AlignFrame af : frames)
1841 for (AlignmentPanel ap : af.alignPanels)
1843 if (alignmentId == null
1844 || alignmentId.equals(ap.av.getSequenceSetId()))
1850 if (aps.size() == 0)
1854 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1859 * get all the viewports on an alignment.
1861 * @param sequenceSetId
1862 * unique alignment id (may be null - all viewports returned in that
1864 * @return all viewports on the alignment bound to sequenceSetId
1866 public static AlignmentViewport[] getViewports(String sequenceSetId)
1868 List<AlignmentViewport> viewp = new ArrayList<>();
1869 if (desktop != null)
1871 AlignFrame[] frames = Desktop.getAlignFrames();
1873 for (AlignFrame afr : frames)
1875 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1876 .equals(sequenceSetId))
1878 if (afr.alignPanels != null)
1880 for (AlignmentPanel ap : afr.alignPanels)
1882 if (sequenceSetId == null
1883 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1891 viewp.add(afr.getViewport());
1895 if (viewp.size() > 0)
1897 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1904 * Explode the views in the given frame into separate AlignFrame
1908 public static void explodeViews(AlignFrame af)
1910 int size = af.alignPanels.size();
1916 for (int i = 0; i < size; i++)
1918 AlignmentPanel ap = af.alignPanels.get(i);
1919 AlignFrame newaf = new AlignFrame(ap);
1922 * Restore the view's last exploded frame geometry if known. Multiple
1923 * views from one exploded frame share and restore the same (frame)
1924 * position and size.
1926 Rectangle geometry = ap.av.getExplodedGeometry();
1927 if (geometry != null)
1929 newaf.setBounds(geometry);
1932 ap.av.setGatherViewsHere(false);
1934 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1935 AlignFrame.DEFAULT_HEIGHT);
1938 af.alignPanels.clear();
1939 af.closeMenuItem_actionPerformed(true);
1944 * Gather expanded views (separate AlignFrame's) with the same sequence set
1945 * identifier back in to this frame as additional views, and close the
1946 * expanded views. Note the expanded frames may themselves have multiple
1947 * views. We take the lot.
1951 public void gatherViews(AlignFrame source)
1953 source.viewport.setGatherViewsHere(true);
1954 source.viewport.setExplodedGeometry(source.getBounds());
1955 JInternalFrame[] frames = desktop.getAllFrames();
1956 String viewId = source.viewport.getSequenceSetId();
1958 for (int t = 0; t < frames.length; t++)
1960 if (frames[t] instanceof AlignFrame && frames[t] != source)
1962 AlignFrame af = (AlignFrame) frames[t];
1963 boolean gatherThis = false;
1964 for (int a = 0; a < af.alignPanels.size(); a++)
1966 AlignmentPanel ap = af.alignPanels.get(a);
1967 if (viewId.equals(ap.av.getSequenceSetId()))
1970 ap.av.setGatherViewsHere(false);
1971 ap.av.setExplodedGeometry(af.getBounds());
1972 source.addAlignmentPanel(ap, false);
1978 af.alignPanels.clear();
1979 af.closeMenuItem_actionPerformed(true);
1986 jalview.gui.VamsasApplication v_client = null;
1989 public void vamsasImport_actionPerformed(ActionEvent e)
1991 // TODO: JAL-3048 not needed for Jalview-JS
1993 if (v_client == null)
1995 // Load and try to start a session.
1996 JalviewFileChooser chooser = new JalviewFileChooser(
1997 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
1999 chooser.setFileView(new JalviewFileView());
2000 chooser.setDialogTitle(
2001 MessageManager.getString("label.open_saved_vamsas_session"));
2002 chooser.setToolTipText(MessageManager.getString(
2003 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2005 int value = chooser.showOpenDialog(this);
2007 if (value == JalviewFileChooser.APPROVE_OPTION)
2009 String fle = chooser.getSelectedFile().toString();
2010 if (!vamsasImport(chooser.getSelectedFile()))
2012 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2013 MessageManager.formatMessage(
2014 "label.couldnt_import_as_vamsas_session",
2018 .getString("label.vamsas_document_import_failed"),
2019 JvOptionPane.ERROR_MESSAGE);
2025 jalview.bin.Cache.log.error(
2026 "Implementation error - load session from a running session is not supported.");
2031 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2034 * @return true if import was a success and a session was started.
2036 public boolean vamsasImport(URL url)
2038 // TODO: create progress bar
2039 if (v_client != null)
2042 jalview.bin.Cache.log.error(
2043 "Implementation error - load session from a running session is not supported.");
2049 // copy the URL content to a temporary local file
2050 // TODO: be a bit cleverer here with nio (?!)
2051 File file = File.createTempFile("vdocfromurl", ".vdj");
2052 FileOutputStream fos = new FileOutputStream(file);
2053 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2054 byte[] buffer = new byte[2048];
2056 while ((ln = bis.read(buffer)) > -1)
2058 fos.write(buffer, 0, ln);
2062 v_client = new jalview.gui.VamsasApplication(this, file,
2063 url.toExternalForm());
2064 } catch (Exception ex)
2066 jalview.bin.Cache.log.error(
2067 "Failed to create new vamsas session from contents of URL "
2072 setupVamsasConnectedGui();
2073 v_client.initial_update(); // TODO: thread ?
2074 return v_client.inSession();
2078 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2081 * @return true if import was a success and a session was started.
2083 public boolean vamsasImport(File file)
2085 if (v_client != null)
2088 jalview.bin.Cache.log.error(
2089 "Implementation error - load session from a running session is not supported.");
2093 setProgressBar(MessageManager.formatMessage(
2094 "status.importing_vamsas_session_from", new Object[]
2095 { file.getName() }), file.hashCode());
2098 v_client = new jalview.gui.VamsasApplication(this, file, null);
2099 } catch (Exception ex)
2101 setProgressBar(MessageManager.formatMessage(
2102 "status.importing_vamsas_session_from", new Object[]
2103 { file.getName() }), file.hashCode());
2104 jalview.bin.Cache.log.error(
2105 "New vamsas session from existing session file failed:", ex);
2108 setupVamsasConnectedGui();
2109 v_client.initial_update(); // TODO: thread ?
2110 setProgressBar(MessageManager.formatMessage(
2111 "status.importing_vamsas_session_from", new Object[]
2112 { file.getName() }), file.hashCode());
2113 return v_client.inSession();
2116 public boolean joinVamsasSession(String mysesid)
2118 if (v_client != null)
2120 throw new Error(MessageManager
2121 .getString("error.try_join_vamsas_session_another"));
2123 if (mysesid == null)
2126 MessageManager.getString("error.invalid_vamsas_session_id"));
2128 v_client = new VamsasApplication(this, mysesid);
2129 setupVamsasConnectedGui();
2130 v_client.initial_update();
2131 return (v_client.inSession());
2135 public void vamsasStart_actionPerformed(ActionEvent e)
2137 if (v_client == null)
2140 // we just start a default session for moment.
2142 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2143 * getProperty("LAST_DIRECTORY"));
2145 * chooser.setFileView(new JalviewFileView());
2146 * chooser.setDialogTitle("Load Vamsas file");
2147 * chooser.setToolTipText("Import");
2149 * int value = chooser.showOpenDialog(this);
2151 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2152 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2154 v_client = new VamsasApplication(this);
2155 setupVamsasConnectedGui();
2156 v_client.initial_update(); // TODO: thread ?
2160 // store current data in session.
2161 v_client.push_update(); // TODO: thread
2165 protected void setupVamsasConnectedGui()
2167 vamsasStart.setText(MessageManager.getString("label.session_update"));
2168 vamsasSave.setVisible(true);
2169 vamsasStop.setVisible(true);
2170 vamsasImport.setVisible(false); // Document import to existing session is
2171 // not possible for vamsas-client-1.0.
2174 protected void setupVamsasDisconnectedGui()
2176 vamsasSave.setVisible(false);
2177 vamsasStop.setVisible(false);
2178 vamsasImport.setVisible(true);
2180 .setText(MessageManager.getString("label.new_vamsas_session"));
2184 public void vamsasStop_actionPerformed(ActionEvent e)
2186 if (v_client != null)
2188 v_client.end_session();
2190 setupVamsasDisconnectedGui();
2194 protected void buildVamsasStMenu()
2196 if (v_client == null)
2198 String[] sess = null;
2201 sess = VamsasApplication.getSessionList();
2202 } catch (Exception e)
2204 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2210 jalview.bin.Cache.log.debug(
2211 "Got current sessions list: " + sess.length + " entries.");
2212 VamsasStMenu.removeAll();
2213 for (int i = 0; i < sess.length; i++)
2215 JMenuItem sessit = new JMenuItem();
2216 sessit.setText(sess[i]);
2217 sessit.setToolTipText(MessageManager
2218 .formatMessage("label.connect_to_session", new Object[]
2220 final Desktop dsktp = this;
2221 final String mysesid = sess[i];
2222 sessit.addActionListener(new ActionListener()
2226 public void actionPerformed(ActionEvent e)
2228 if (dsktp.v_client == null)
2230 Thread rthr = new Thread(new Runnable()
2236 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2237 dsktp.setupVamsasConnectedGui();
2238 dsktp.v_client.initial_update();
2246 VamsasStMenu.add(sessit);
2248 // don't show an empty menu.
2249 VamsasStMenu.setVisible(sess.length > 0);
2254 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2255 VamsasStMenu.removeAll();
2256 VamsasStMenu.setVisible(false);
2261 // Not interested in the content. Just hide ourselves.
2262 VamsasStMenu.setVisible(false);
2267 public void vamsasSave_actionPerformed(ActionEvent e)
2269 // TODO: JAL-3048 not needed for Jalview-JS
2271 if (v_client != null)
2273 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2274 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2277 chooser.setFileView(new JalviewFileView());
2278 chooser.setDialogTitle(MessageManager
2279 .getString("label.save_vamsas_document_archive"));
2281 int value = chooser.showSaveDialog(this);
2283 if (value == JalviewFileChooser.APPROVE_OPTION)
2285 java.io.File choice = chooser.getSelectedFile();
2286 JPanel progpanel = addProgressPanel(MessageManager
2287 .formatMessage("label.saving_vamsas_doc", new Object[]
2288 { choice.getName() }));
2289 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2290 String warnmsg = null;
2291 String warnttl = null;
2294 v_client.vclient.storeDocument(choice);
2297 warnttl = "Serious Problem saving Vamsas Document";
2298 warnmsg = ex.toString();
2299 jalview.bin.Cache.log
2300 .error("Error Whilst saving document to " + choice, ex);
2302 } catch (Exception ex)
2304 warnttl = "Problem saving Vamsas Document.";
2305 warnmsg = ex.toString();
2306 jalview.bin.Cache.log.warn(
2307 "Exception Whilst saving document to " + choice, ex);
2310 removeProgressPanel(progpanel);
2311 if (warnmsg != null)
2313 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2315 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2321 JPanel vamUpdate = null;
2324 * hide vamsas user gui bits when a vamsas document event is being handled.
2327 * true to hide gui, false to reveal gui
2329 public void setVamsasUpdate(boolean b)
2331 Cache.log.debug("Setting gui for Vamsas update "
2332 + (b ? "in progress" : "finished"));
2334 if (vamUpdate != null)
2336 this.removeProgressPanel(vamUpdate);
2340 vamUpdate = this.addProgressPanel(
2341 MessageManager.getString("label.updating_vamsas_session"));
2343 vamsasStart.setVisible(!b);
2344 vamsasStop.setVisible(!b);
2345 vamsasSave.setVisible(!b);
2348 public JInternalFrame[] getAllFrames()
2350 return desktop.getAllFrames();
2354 * Checks the given url to see if it gives a response indicating that the user
2355 * should be informed of a new questionnaire.
2359 public void checkForQuestionnaire(String url)
2361 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2362 // javax.swing.SwingUtilities.invokeLater(jvq);
2363 new Thread(jvq).start();
2366 public void checkURLLinks()
2368 // Thread off the URL link checker
2369 addDialogThread(new Runnable()
2374 if (/** @j2sNative false && */ // BH 2018
2375 Cache.getDefault("CHECKURLLINKS", true))
2377 // check what the actual links are - if it's just the default don't
2378 // bother with the warning
2379 List<String> links = Preferences.sequenceUrlLinks
2382 // only need to check links if there is one with a
2383 // SEQUENCE_ID which is not the default EMBL_EBI link
2384 ListIterator<String> li = links.listIterator();
2385 boolean check = false;
2386 List<JLabel> urls = new ArrayList<>();
2387 while (li.hasNext())
2389 String link = li.next();
2390 if (link.contains(SEQUENCE_ID)
2391 && !UrlConstants.isDefaultString(link))
2394 int barPos = link.indexOf("|");
2395 String urlMsg = barPos == -1 ? link
2396 : link.substring(0, barPos) + ": "
2397 + link.substring(barPos + 1);
2398 urls.add(new JLabel(urlMsg));
2406 // ask user to check in case URL links use old style tokens
2407 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2408 JPanel msgPanel = new JPanel();
2409 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2410 msgPanel.add(Box.createVerticalGlue());
2411 JLabel msg = new JLabel(MessageManager
2412 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2413 JLabel msg2 = new JLabel(MessageManager
2414 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2416 for (JLabel url : urls)
2422 final JCheckBox jcb = new JCheckBox(
2423 MessageManager.getString("label.do_not_display_again"));
2424 jcb.addActionListener(new ActionListener()
2427 public void actionPerformed(ActionEvent e)
2429 // update Cache settings for "don't show this again"
2430 boolean showWarningAgain = !jcb.isSelected();
2431 Cache.setProperty("CHECKURLLINKS",
2432 Boolean.valueOf(showWarningAgain).toString());
2437 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2439 .getString("label.SEQUENCE_ID_no_longer_used"),
2440 JvOptionPane.WARNING_MESSAGE);
2447 * Proxy class for JDesktopPane which optionally displays the current memory
2448 * usage and highlights the desktop area with a red bar if free memory runs
2453 public class MyDesktopPane extends JDesktopPane
2454 implements Runnable, PropertyChangeListener
2457 public Object[] dialogData;
2461 public void propertyChange(PropertyChangeEvent event)
2463 Object val = event.getNewValue();
2464 String name = event.getPropertyName();
2465 System.out.println(name);
2466 switch (event.getSource().getClass().getName())
2468 case "javax.swing.JOptionPane":
2472 onDialogReturn(val);
2475 if (val instanceof Integer)
2477 onDialogReturn(((Integer) val).intValue());
2481 onDialogReturn(val);
2486 case "javax.swing.ColorChooserDialog":
2489 case "SelectedColor":
2490 onDialogReturn(val);
2494 case "javax.swing.JFileChooser":
2497 case "SelectedFile":
2498 // in JavaScript, this File object will have a _bytes property,
2499 // because the file data has already been loaded
2500 onDialogReturn(new Object[] { (File) val });
2505 System.out.println(event.getSource().getClass().getName() + " "
2506 + event.getPropertyName() + ": " + event.getNewValue());
2509 // JSCOmponent.DialogCaller interface
2510 void onDialogReturn(Object value)
2512 switch ((String) dialogData[0])
2514 case "SelectedFile":
2516 dialogData[0] = value;
2517 ((Runnable) dialogData[1]).run();
2519 case "label.select_feature_colour":
2520 ((FeatureRenderer) dialogData[1]).processColorDialog((Color) value);
2525 // JSCOmponent.DialogCaller interface
2526 void onDialogReturn(int value)
2528 if (value != Math.floor(value))
2530 // in JavaScript, this will be NaN, oddly enough
2534 switch ((String) dialogData[0])
2537 dialogData[0] = Integer.valueOf(value);
2538 ((Runnable) dialogData[1]).run();
2540 case "label.input_alignment_from_url":
2541 // reconstruct the parameter data
2543 AlignViewport viewport = (AlignViewport) dialogData[1];
2544 JComboBox history = (JComboBox) dialogData[2];
2545 // the rest of this is unchangaed
2546 if (reply != JvOptionPane.OK_OPTION)
2551 String url = history.getSelectedItem().toString();
2553 if (url.toLowerCase().endsWith(".jar"))
2555 if (viewport != null)
2557 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2558 FileFormat.Jalview);
2562 new FileLoader().LoadFile(url, DataSourceType.URL,
2563 FileFormat.Jalview);
2568 FileFormatI format = null;
2571 format = new IdentifyFile().identify(url, DataSourceType.URL);
2572 } catch (FileFormatException e)
2574 // TODO revise error handling, distinguish between
2575 // URL not found and response not valid
2580 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2581 MessageManager.formatMessage("label.couldnt_locate",
2584 MessageManager.getString("label.url_not_found"),
2585 JvOptionPane.WARNING_MESSAGE);
2590 if (viewport != null)
2592 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2597 new FileLoader().LoadFile(url, DataSourceType.URL, format);
2606 private static final float ONE_MB = 1048576f;
2608 boolean showMemoryUsage = false;
2612 java.text.NumberFormat df;
2614 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2617 public MyDesktopPane(boolean showMemoryUsage)
2619 showMemoryUsage(showMemoryUsage);
2622 public void showMemoryUsage(boolean showMemory)
2624 this.showMemoryUsage = showMemory;
2627 Thread worker = new Thread(this);
2633 public boolean isShowMemoryUsage()
2635 return showMemoryUsage;
2641 df = java.text.NumberFormat.getNumberInstance();
2642 df.setMaximumFractionDigits(2);
2643 runtime = Runtime.getRuntime();
2645 while (showMemoryUsage)
2649 maxMemory = runtime.maxMemory() / ONE_MB;
2650 allocatedMemory = runtime.totalMemory() / ONE_MB;
2651 freeMemory = runtime.freeMemory() / ONE_MB;
2652 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2654 percentUsage = (totalFreeMemory / maxMemory) * 100;
2656 // if (percentUsage < 20)
2658 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2660 // instance.set.setBorder(border1);
2663 // sleep after showing usage
2665 } catch (Exception ex)
2667 ex.printStackTrace();
2673 public void paintComponent(Graphics g)
2675 if (showMemoryUsage && g != null && df != null)
2677 if (percentUsage < 20)
2679 g.setColor(Color.red);
2681 FontMetrics fm = g.getFontMetrics();
2684 g.drawString(MessageManager.formatMessage("label.memory_stats",
2686 { df.format(totalFreeMemory), df.format(maxMemory),
2687 df.format(percentUsage) }),
2688 10, getHeight() - fm.getHeight());
2696 * Accessor method to quickly get all the AlignmentFrames loaded.
2698 * @return an array of AlignFrame, or null if none found
2700 public static AlignFrame[] getAlignFrames()
2702 if (Jalview.isHeadlessMode())
2704 // Desktop.desktop is null in headless mode
2705 return new AlignFrame[] { Jalview.currentAlignFrame };
2708 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2714 List<AlignFrame> avp = new ArrayList<>();
2716 for (int i = frames.length - 1; i > -1; i--)
2718 if (frames[i] instanceof AlignFrame)
2720 avp.add((AlignFrame) frames[i]);
2722 else if (frames[i] instanceof SplitFrame)
2725 * Also check for a split frame containing an AlignFrame
2727 GSplitFrame sf = (GSplitFrame) frames[i];
2728 if (sf.getTopFrame() instanceof AlignFrame)
2730 avp.add((AlignFrame) sf.getTopFrame());
2732 if (sf.getBottomFrame() instanceof AlignFrame)
2734 avp.add((AlignFrame) sf.getBottomFrame());
2738 if (avp.size() == 0)
2742 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2747 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2751 public GStructureViewer[] getJmols()
2753 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2759 List<GStructureViewer> avp = new ArrayList<>();
2761 for (int i = frames.length - 1; i > -1; i--)
2763 if (frames[i] instanceof AppJmol)
2765 GStructureViewer af = (GStructureViewer) frames[i];
2769 if (avp.size() == 0)
2773 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2778 * Add Groovy Support to Jalview
2781 public void groovyShell_actionPerformed()
2785 openGroovyConsole();
2786 } catch (Exception ex)
2788 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2789 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2791 MessageManager.getString("label.couldnt_create_groovy_shell"),
2792 MessageManager.getString("label.groovy_support_failed"),
2793 JvOptionPane.ERROR_MESSAGE);
2798 * Open the Groovy console
2800 void openGroovyConsole()
2802 if (groovyConsole == null)
2804 groovyConsole = new groovy.ui.Console();
2805 groovyConsole.setVariable("Jalview", this);
2806 groovyConsole.run();
2809 * We allow only one console at a time, so that AlignFrame menu option
2810 * 'Calculate | Run Groovy script' is unambiguous.
2811 * Disable 'Groovy Console', and enable 'Run script', when the console is
2812 * opened, and the reverse when it is closed
2814 Window window = (Window) groovyConsole.getFrame();
2815 window.addWindowListener(new WindowAdapter()
2818 public void windowClosed(WindowEvent e)
2821 * rebind CMD-Q from Groovy Console to Jalview Quit
2824 enableExecuteGroovy(false);
2830 * show Groovy console window (after close and reopen)
2832 ((Window) groovyConsole.getFrame()).setVisible(true);
2835 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2836 * and disable opening a second console
2838 enableExecuteGroovy(true);
2842 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2843 * binding when opened
2845 protected void addQuitHandler()
2847 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2848 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2849 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2851 getRootPane().getActionMap().put("Quit", new AbstractAction()
2854 public void actionPerformed(ActionEvent e)
2862 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2865 * true if Groovy console is open
2867 public void enableExecuteGroovy(boolean enabled)
2870 * disable opening a second Groovy console
2871 * (or re-enable when the console is closed)
2873 groovyShell.setEnabled(!enabled);
2875 AlignFrame[] alignFrames = getAlignFrames();
2876 if (alignFrames != null)
2878 for (AlignFrame af : alignFrames)
2880 af.setGroovyEnabled(enabled);
2886 * Progress bars managed by the IProgressIndicator method.
2888 private Hashtable<Long, JPanel> progressBars;
2890 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2895 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2898 public void setProgressBar(String message, long id)
2900 if (progressBars == null)
2902 progressBars = new Hashtable<>();
2903 progressBarHandlers = new Hashtable<>();
2906 if (progressBars.get(new Long(id)) != null)
2908 JPanel panel = progressBars.remove(new Long(id));
2909 if (progressBarHandlers.contains(new Long(id)))
2911 progressBarHandlers.remove(new Long(id));
2913 removeProgressPanel(panel);
2917 progressBars.put(new Long(id), addProgressPanel(message));
2924 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2925 * jalview.gui.IProgressIndicatorHandler)
2928 public void registerHandler(final long id,
2929 final IProgressIndicatorHandler handler)
2931 if (progressBarHandlers == null
2932 || !progressBars.containsKey(new Long(id)))
2934 throw new Error(MessageManager.getString(
2935 "error.call_setprogressbar_before_registering_handler"));
2937 progressBarHandlers.put(new Long(id), handler);
2938 final JPanel progressPanel = progressBars.get(new Long(id));
2939 if (handler.canCancel())
2941 JButton cancel = new JButton(
2942 MessageManager.getString("action.cancel"));
2943 final IProgressIndicator us = this;
2944 cancel.addActionListener(new ActionListener()
2948 public void actionPerformed(ActionEvent e)
2950 handler.cancelActivity(id);
2951 us.setProgressBar(MessageManager
2952 .formatMessage("label.cancelled_params", new Object[]
2953 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2957 progressPanel.add(cancel, BorderLayout.EAST);
2963 * @return true if any progress bars are still active
2966 public boolean operationInProgress()
2968 if (progressBars != null && progressBars.size() > 0)
2976 * This will return the first AlignFrame holding the given viewport instance.
2977 * It will break if there are more than one AlignFrames viewing a particular
2981 * @return alignFrame for viewport
2983 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2985 if (desktop != null)
2987 AlignmentPanel[] aps = getAlignmentPanels(
2988 viewport.getSequenceSetId());
2989 for (int panel = 0; aps != null && panel < aps.length; panel++)
2991 if (aps[panel] != null && aps[panel].av == viewport)
2993 return aps[panel].alignFrame;
3000 public VamsasApplication getVamsasApplication()
3007 * flag set if jalview GUI is being operated programmatically
3009 private boolean inBatchMode = false;
3012 * check if jalview GUI is being operated programmatically
3014 * @return inBatchMode
3016 public boolean isInBatchMode()
3022 * set flag if jalview GUI is being operated programmatically
3024 * @param inBatchMode
3026 public void setInBatchMode(boolean inBatchMode)
3028 this.inBatchMode = inBatchMode;
3031 public void startServiceDiscovery()
3033 startServiceDiscovery(false);
3036 public void startServiceDiscovery(boolean blocking)
3038 boolean alive = true;
3039 Thread t0 = null, t1 = null, t2 = null;
3040 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3043 // todo: changesupport handlers need to be transferred
3044 if (discoverer == null)
3046 discoverer = new jalview.ws.jws1.Discoverer();
3047 // register PCS handler for desktop.
3048 discoverer.addPropertyChangeListener(changeSupport);
3050 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3051 // until we phase out completely
3052 (t0 = new Thread(discoverer)).start();
3055 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3057 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3058 .startDiscoverer(changeSupport);
3062 // TODO: do rest service discovery
3071 } catch (Exception e)
3074 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3075 || (t3 != null && t3.isAlive())
3076 || (t0 != null && t0.isAlive());
3082 * called to check if the service discovery process completed successfully.
3086 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3088 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3090 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3091 .getErrorMessages();
3094 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3096 if (serviceChangedDialog == null)
3098 // only run if we aren't already displaying one of these.
3099 addDialogThread(serviceChangedDialog = new Runnable()
3106 * JalviewDialog jd =new JalviewDialog() {
3108 * @Override protected void cancelPressed() { // TODO
3109 * Auto-generated method stub
3111 * }@Override protected void okPressed() { // TODO
3112 * Auto-generated method stub
3114 * }@Override protected void raiseClosed() { // TODO
3115 * Auto-generated method stub
3117 * } }; jd.initDialogFrame(new
3118 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3119 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3120 * + " or mis-configured HTTP proxy settings.<br/>" +
3121 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3123 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3124 * ), true, true, "Web Service Configuration Problem", 450,
3127 * jd.waitForInput();
3129 JvOptionPane.showConfirmDialog(Desktop.desktop,
3130 new JLabel("<html><table width=\"450\"><tr><td>"
3131 + ermsg + "</td></tr></table>"
3132 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3133 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3134 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3135 + " Tools->Preferences dialog box to change them.</p></html>"),
3136 "Web Service Configuration Problem",
3137 JvOptionPane.DEFAULT_OPTION,
3138 JvOptionPane.ERROR_MESSAGE);
3139 serviceChangedDialog = null;
3148 "Errors reported by JABA discovery service. Check web services preferences.\n"
3155 private Runnable serviceChangedDialog = null;
3158 * start a thread to open a URL in the configured browser. Pops up a warning
3159 * dialog to the user if there is an exception when calling out to the browser
3164 public static void showUrl(final String url)
3166 showUrl(url, Desktop.instance);
3170 * Like showUrl but allows progress handler to be specified
3174 * (null) or object implementing IProgressIndicator
3176 public static void showUrl(final String url,
3177 final IProgressIndicator progress)
3179 new Thread(new Runnable()
3186 if (progress != null)
3188 progress.setProgressBar(MessageManager
3189 .formatMessage("status.opening_params", new Object[]
3190 { url }), this.hashCode());
3192 jalview.util.BrowserLauncher.openURL(url);
3193 } catch (Exception ex)
3195 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3197 .getString("label.web_browser_not_found_unix"),
3198 MessageManager.getString("label.web_browser_not_found"),
3199 JvOptionPane.WARNING_MESSAGE);
3201 ex.printStackTrace();
3203 if (progress != null)
3205 progress.setProgressBar(null, this.hashCode());
3211 public static WsParamSetManager wsparamManager = null;
3213 public static ParamManager getUserParameterStore()
3215 if (wsparamManager == null)
3217 wsparamManager = new WsParamSetManager();
3219 return wsparamManager;
3223 * static hyperlink handler proxy method for use by Jalview's internal windows
3227 public static void hyperlinkUpdate(HyperlinkEvent e)
3229 if (e.getEventType() == EventType.ACTIVATED)
3234 url = e.getURL().toString();
3235 Desktop.showUrl(url);
3236 } catch (Exception x)
3240 if (Cache.log != null)
3242 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3247 "Couldn't handle string " + url + " as a URL.");
3250 // ignore any exceptions due to dud links.
3257 * single thread that handles display of dialogs to user.
3259 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3262 * flag indicating if dialogExecutor should try to acquire a permit
3264 private volatile boolean dialogPause = true;
3269 private java.util.concurrent.Semaphore block = new Semaphore(0);
3271 private static groovy.ui.Console groovyConsole;
3274 * add another dialog thread to the queue
3278 public void addDialogThread(final Runnable prompter)
3280 dialogExecutor.submit(new Runnable()
3290 } catch (InterruptedException x)
3295 if (instance == null)
3301 SwingUtilities.invokeAndWait(prompter);
3302 } catch (Exception q)
3304 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3310 public void startDialogQueue()
3312 // set the flag so we don't pause waiting for another permit and semaphore
3313 // the current task to begin
3314 dialogPause = false;
3319 protected void snapShotWindow_actionPerformed(ActionEvent e)
3323 ImageMaker im = new jalview.util.ImageMaker(
3324 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3325 getHeight(), of = new File("Jalview_snapshot"
3326 + System.currentTimeMillis() + ".eps"),
3327 "View of desktop", null, 0, false);
3330 paintAll(im.getGraphics());
3332 } catch (Exception q)
3334 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3338 Cache.log.info("Successfully written snapshot to file "
3339 + of.getAbsolutePath());
3343 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3344 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3345 * and location last time the view was expanded (if any). However it does not
3346 * remember the split pane divider location - this is set to match the
3347 * 'exploding' frame.
3351 public void explodeViews(SplitFrame sf)
3353 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3354 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3355 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3357 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3359 int viewCount = topPanels.size();
3366 * Processing in reverse order works, forwards order leaves the first panels
3367 * not visible. I don't know why!
3369 for (int i = viewCount - 1; i >= 0; i--)
3372 * Make new top and bottom frames. These take over the respective
3373 * AlignmentPanel objects, including their AlignmentViewports, so the
3374 * cdna/protein relationships between the viewports is carried over to the
3377 * explodedGeometry holds the (x, y) position of the previously exploded
3378 * SplitFrame, and the (width, height) of the AlignFrame component
3380 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3381 AlignFrame newTopFrame = new AlignFrame(topPanel);
3382 newTopFrame.setSize(oldTopFrame.getSize());
3383 newTopFrame.setVisible(true);
3384 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3385 .getExplodedGeometry();
3386 if (geometry != null)
3388 newTopFrame.setSize(geometry.getSize());
3391 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3392 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3393 newBottomFrame.setSize(oldBottomFrame.getSize());
3394 newBottomFrame.setVisible(true);
3395 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3396 .getExplodedGeometry();
3397 if (geometry != null)
3399 newBottomFrame.setSize(geometry.getSize());
3402 topPanel.av.setGatherViewsHere(false);
3403 bottomPanel.av.setGatherViewsHere(false);
3404 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3406 if (geometry != null)
3408 splitFrame.setLocation(geometry.getLocation());
3410 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3414 * Clear references to the panels (now relocated in the new SplitFrames)
3415 * before closing the old SplitFrame.
3418 bottomPanels.clear();
3423 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3424 * back into the given SplitFrame as additional views. Note that the gathered
3425 * frames may themselves have multiple views.
3429 public void gatherViews(GSplitFrame source)
3432 * special handling of explodedGeometry for a view within a SplitFrame: - it
3433 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3434 * height) of the AlignFrame component
3436 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3437 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3438 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3439 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3440 myBottomFrame.viewport
3441 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3442 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3443 myTopFrame.viewport.setGatherViewsHere(true);
3444 myBottomFrame.viewport.setGatherViewsHere(true);
3445 String topViewId = myTopFrame.viewport.getSequenceSetId();
3446 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3448 JInternalFrame[] frames = desktop.getAllFrames();
3449 for (JInternalFrame frame : frames)
3451 if (frame instanceof SplitFrame && frame != source)
3453 SplitFrame sf = (SplitFrame) frame;
3454 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3455 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3456 boolean gatherThis = false;
3457 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3459 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3460 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3461 if (topViewId.equals(topPanel.av.getSequenceSetId())
3462 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3465 topPanel.av.setGatherViewsHere(false);
3466 bottomPanel.av.setGatherViewsHere(false);
3467 topPanel.av.setExplodedGeometry(
3468 new Rectangle(sf.getLocation(), topFrame.getSize()));
3469 bottomPanel.av.setExplodedGeometry(
3470 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3471 myTopFrame.addAlignmentPanel(topPanel, false);
3472 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3478 topFrame.getAlignPanels().clear();
3479 bottomFrame.getAlignPanels().clear();
3486 * The dust settles...give focus to the tab we did this from.
3488 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3491 public static groovy.ui.Console getGroovyConsole()
3493 return groovyConsole;
3497 * handles the payload of a drag and drop event.
3499 * TODO refactor to desktop utilities class
3502 * - Data source strings extracted from the drop event
3504 * - protocol for each data source extracted from the drop event
3508 * - the payload from the drop event
3511 public static void transferFromDropTarget(List<Object> files,
3512 List<DataSourceType> protocols, DropTargetDropEvent evt,
3513 Transferable t) throws Exception
3516 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3518 // DataFlavor[] flavors = t.getTransferDataFlavors();
3519 // for (int i = 0; i < flavors.length; i++) {
3520 // if (flavors[i].isFlavorJavaFileListType()) {
3521 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3522 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3523 // for (int j = 0; j < list.size(); j++) {
3524 // File file = (File) list.get(j);
3525 // byte[] data = getDroppedFileBytes(file);
3526 // fileName.setText(file.getName() + " - " + data.length + " " + evt.getLocation());
3527 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3528 // target.setText(new String(data));
3530 // dtde.dropComplete(true);
3535 DataFlavor uriListFlavor = new DataFlavor(
3536 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3539 urlFlavour = new DataFlavor(
3540 "application/x-java-url; class=java.net.URL");
3541 } catch (ClassNotFoundException cfe)
3543 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3546 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3551 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3552 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3553 // means url may be null.
3556 protocols.add(DataSourceType.URL);
3557 files.add(url.toString());
3558 Cache.log.debug("Drop handled as URL dataflavor "
3559 + files.get(files.size() - 1));
3564 if (Platform.isAMac())
3567 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3571 } catch (Throwable ex)
3573 Cache.log.debug("URL drop handler failed.", ex);
3576 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3578 // Works on Windows and MacOSX
3579 Cache.log.debug("Drop handled as javaFileListFlavor");
3580 for (Object file : (List) t
3581 .getTransferData(DataFlavor.javaFileListFlavor))
3584 protocols.add(DataSourceType.FILE);
3589 // Unix like behaviour
3590 boolean added = false;
3592 if (t.isDataFlavorSupported(uriListFlavor))
3594 Cache.log.debug("Drop handled as uriListFlavor");
3595 // This is used by Unix drag system
3596 data = (String) t.getTransferData(uriListFlavor);
3600 // fallback to text: workaround - on OSX where there's a JVM bug
3601 Cache.log.debug("standard URIListFlavor failed. Trying text");
3602 // try text fallback
3603 DataFlavor textDf = new DataFlavor(
3604 "text/plain;class=java.lang.String");
3605 if (t.isDataFlavorSupported(textDf))
3607 data = (String) t.getTransferData(textDf);
3610 Cache.log.debug("Plain text drop content returned "
3611 + (data == null ? "Null - failed" : data));
3616 while (protocols.size() < files.size())
3618 Cache.log.debug("Adding missing FILE protocol for "
3619 + files.get(protocols.size()));
3620 protocols.add(DataSourceType.FILE);
3622 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3623 data, "\r\n"); st.hasMoreTokens();)
3626 String s = st.nextToken();
3627 if (s.startsWith("#"))
3629 // the line is a comment (as per the RFC 2483)
3632 java.net.URI uri = new java.net.URI(s);
3633 if (uri.getScheme().toLowerCase().startsWith("http"))
3635 protocols.add(DataSourceType.URL);
3636 files.add(uri.toString());
3640 // otherwise preserve old behaviour: catch all for file objects
3641 java.io.File file = new java.io.File(uri);
3642 protocols.add(DataSourceType.FILE);
3643 files.add(file.toString());
3648 if (Cache.log.isDebugEnabled())
3650 if (data == null || !added)
3653 if (t.getTransferDataFlavors() != null
3654 && t.getTransferDataFlavors().length > 0)
3657 "Couldn't resolve drop data. Here are the supported flavors:");
3658 for (DataFlavor fl : t.getTransferDataFlavors())
3661 "Supported transfer dataflavor: " + fl.toString());
3662 Object df = t.getTransferData(fl);
3665 Cache.log.debug("Retrieves: " + df);
3669 Cache.log.debug("Retrieved nothing");
3675 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3681 if (Platform.isWindows())
3684 Cache.log.debug("Scanning dropped content for Windows Link Files");
3686 // resolve any .lnk files in the file drop
3687 for (int f = 0; f < files.size(); f++)
3689 String source = files.get(f).toString().toLowerCase();
3690 if (protocols.get(f).equals(DataSourceType.FILE)
3691 && (source.endsWith(".lnk") || source.endsWith(".url")
3692 || source.endsWith(".site")))
3695 Object obj = files.get(f);
3696 File lf = (obj instanceof File ? (File) obj : new File((String) obj));
3697 // process link file to get a URL
3698 Cache.log.debug("Found potential link file: " + lf);
3699 WindowsShortcut wscfile = new WindowsShortcut(lf);
3700 String fullname = wscfile.getRealFilename();
3701 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3702 files.set(f, fullname);
3703 Cache.log.debug("Parsed real filename " + fullname
3704 + " to extract protocol: " + protocols.get(f));
3706 catch (Exception ex)
3708 Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
3716 * Sets the Preferences property for experimental features to True or False
3717 * depending on the state of the controlling menu item
3720 protected void showExperimental_actionPerformed(boolean selected)
3722 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3726 * Answers a (possibly empty) list of any structure viewer frames (currently
3727 * for either Jmol or Chimera) which are currently open. This may optionally
3728 * be restricted to viewers of a specified class, or viewers linked to a
3729 * specified alignment panel.
3732 * if not null, only return viewers linked to this panel
3733 * @param structureViewerClass
3734 * if not null, only return viewers of this class
3737 public List<StructureViewerBase> getStructureViewers(
3738 AlignmentPanel apanel,
3739 Class<? extends StructureViewerBase> structureViewerClass)
3741 List<StructureViewerBase> result = new ArrayList<>();
3742 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3744 for (JInternalFrame frame : frames)
3746 if (frame instanceof StructureViewerBase)
3748 if (structureViewerClass == null
3749 || structureViewerClass.isInstance(frame))
3752 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3754 result.add((StructureViewerBase) frame);