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.ImageMaker.TYPE;
45 import jalview.util.MessageManager;
46 import jalview.util.Platform;
47 import jalview.util.UrlConstants;
48 import jalview.util.dialogrunner.RunResponse;
49 import jalview.viewmodel.AlignmentViewport;
50 import jalview.ws.params.ParamManager;
51 import jalview.ws.utils.UrlDownloadClient;
53 import java.awt.BorderLayout;
54 import java.awt.Color;
55 import java.awt.Dimension;
56 import java.awt.FontMetrics;
57 import java.awt.Graphics;
58 import java.awt.GridLayout;
59 import java.awt.Point;
60 import java.awt.Rectangle;
61 import java.awt.Toolkit;
62 import java.awt.Window;
63 import java.awt.datatransfer.Clipboard;
64 import java.awt.datatransfer.ClipboardOwner;
65 import java.awt.datatransfer.DataFlavor;
66 import java.awt.datatransfer.Transferable;
67 import java.awt.dnd.DnDConstants;
68 import java.awt.dnd.DropTargetDragEvent;
69 import java.awt.dnd.DropTargetDropEvent;
70 import java.awt.dnd.DropTargetEvent;
71 import java.awt.dnd.DropTargetListener;
72 import java.awt.event.ActionEvent;
73 import java.awt.event.ActionListener;
74 import java.awt.event.InputEvent;
75 import java.awt.event.KeyEvent;
76 import java.awt.event.MouseAdapter;
77 import java.awt.event.MouseEvent;
78 import java.awt.event.WindowAdapter;
79 import java.awt.event.WindowEvent;
80 import java.beans.PropertyChangeEvent;
81 import java.beans.PropertyChangeListener;
82 import java.io.BufferedInputStream;
84 import java.io.FileOutputStream;
85 import java.io.IOException;
87 import java.util.ArrayList;
88 import java.util.Hashtable;
89 import java.util.List;
90 import java.util.ListIterator;
91 import java.util.StringTokenizer;
92 import java.util.Vector;
93 import java.util.concurrent.ExecutorService;
94 import java.util.concurrent.Executors;
95 import java.util.concurrent.Semaphore;
97 import javax.swing.AbstractAction;
98 import javax.swing.Action;
99 import javax.swing.ActionMap;
100 import javax.swing.Box;
101 import javax.swing.BoxLayout;
102 import javax.swing.DefaultDesktopManager;
103 import javax.swing.DesktopManager;
104 import javax.swing.InputMap;
105 import javax.swing.JButton;
106 import javax.swing.JCheckBox;
107 import javax.swing.JComboBox;
108 import javax.swing.JComponent;
109 import javax.swing.JDesktopPane;
110 import javax.swing.JFrame;
111 import javax.swing.JInternalFrame;
112 import javax.swing.JLabel;
113 import javax.swing.JMenuItem;
114 import javax.swing.JPanel;
115 import javax.swing.JPopupMenu;
116 import javax.swing.JProgressBar;
117 import javax.swing.KeyStroke;
118 import javax.swing.SwingUtilities;
119 import javax.swing.event.HyperlinkEvent;
120 import javax.swing.event.HyperlinkEvent.EventType;
121 import javax.swing.event.InternalFrameAdapter;
122 import javax.swing.event.InternalFrameEvent;
123 import javax.swing.event.MenuEvent;
124 import javax.swing.event.MenuListener;
126 import org.stackoverflowusers.file.WindowsShortcut;
133 * @version $Revision: 1.155 $
135 public class Desktop extends jalview.jbgui.GDesktop
136 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
137 jalview.api.StructureSelectionManagerProvider
139 private static int DEFAULT_MIN_WIDTH = 300;
141 private static int DEFAULT_MIN_HEIGHT = 250;
143 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
145 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
147 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
149 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
152 * news reader - null if it was never started.
154 private BlogReader jvnews = null;
156 private File projectFile;
160 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
162 public void addJalviewPropertyChangeListener(
163 PropertyChangeListener listener)
165 changeSupport.addJalviewPropertyChangeListener(listener);
169 * @param propertyName
171 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
172 * java.beans.PropertyChangeListener)
174 public void addJalviewPropertyChangeListener(String propertyName,
175 PropertyChangeListener listener)
177 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
181 * @param propertyName
183 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
184 * java.beans.PropertyChangeListener)
186 public void removeJalviewPropertyChangeListener(String propertyName,
187 PropertyChangeListener listener)
189 changeSupport.removeJalviewPropertyChangeListener(propertyName,
193 /** Singleton Desktop instance */
194 public static Desktop instance;
196 public static MyDesktopPane desktop;
198 public static MyDesktopPane getDesktop()
200 // BH 2018 could use currentThread() here as a reference to a
201 // Hashtable<Thread, MyDesktopPane> in JavaScript
205 static int openFrameCount = 0;
207 static final int xOffset = 30;
209 static final int yOffset = 30;
211 public static jalview.ws.jws1.Discoverer discoverer;
213 public static Object[] jalviewClipboard;
215 public static boolean internalCopy = false;
217 static int fileLoadingCount = 0;
219 class MyDesktopManager implements DesktopManager
222 private DesktopManager delegate;
224 public MyDesktopManager(DesktopManager delegate)
226 this.delegate = delegate;
230 public void activateFrame(JInternalFrame f)
234 delegate.activateFrame(f);
235 } catch (NullPointerException npe)
237 Point p = getMousePosition();
238 instance.showPasteMenu(p.x, p.y);
243 public void beginDraggingFrame(JComponent f)
245 delegate.beginDraggingFrame(f);
249 public void beginResizingFrame(JComponent f, int direction)
251 delegate.beginResizingFrame(f, direction);
255 public void closeFrame(JInternalFrame f)
257 delegate.closeFrame(f);
261 public void deactivateFrame(JInternalFrame f)
263 delegate.deactivateFrame(f);
267 public void deiconifyFrame(JInternalFrame f)
269 delegate.deiconifyFrame(f);
273 public void dragFrame(JComponent f, int newX, int newY)
279 delegate.dragFrame(f, newX, newY);
283 public void endDraggingFrame(JComponent f)
285 delegate.endDraggingFrame(f);
290 public void endResizingFrame(JComponent f)
292 delegate.endResizingFrame(f);
297 public void iconifyFrame(JInternalFrame f)
299 delegate.iconifyFrame(f);
303 public void maximizeFrame(JInternalFrame f)
305 delegate.maximizeFrame(f);
309 public void minimizeFrame(JInternalFrame f)
311 delegate.minimizeFrame(f);
315 public void openFrame(JInternalFrame f)
317 delegate.openFrame(f);
321 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
328 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
332 public void setBoundsForFrame(JComponent f, int newX, int newY,
333 int newWidth, int newHeight)
335 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
338 // All other methods, simply delegate
343 * Creates a new Desktop object.
348 * A note to implementors. It is ESSENTIAL that any activities that might block
349 * are spawned off as threads rather than waited for during this constructor.
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(new MyDesktopManager(
375 (Platform.isWindows() ? new DefaultDesktopManager()
377 ? new AquaInternalFrameManager(
378 desktop.getDesktopManager())
379 : desktop.getDesktopManager())));
381 Rectangle dims = getLastKnownDimensions("");
388 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
389 int xPos = Math.max(5, (screenSize.width - 900) / 2);
390 int yPos = Math.max(5, (screenSize.height - 650) / 2);
391 setBounds(xPos, yPos, 900, 650);
400 jconsole = new Console(this, showjconsole);
401 // add essential build information
402 jconsole.setHeader("Jalview Version: "
403 + jalview.bin.Cache.getProperty("VERSION") + "\n"
404 + "Jalview Installation: "
405 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
406 + "\n" + "Build Date: "
407 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
408 + "Java version: " + System.getProperty("java.version") + "\n"
409 + System.getProperty("os.arch") + " "
410 + System.getProperty("os.name") + " "
411 + System.getProperty("os.version"));
413 showConsole(showjconsole);
415 showNews.setVisible(false);
417 experimentalFeatures.setSelected(showExperimental());
419 getIdentifiersOrgData();
423 // Spawn a thread that shows the splashscreen
425 SwingUtilities.invokeLater(new Runnable()
434 // Thread off a new instance of the file chooser - this reduces the time it
435 // takes to open it later on.
436 new Thread(new Runnable()
441 Cache.log.debug("Filechooser init thread started.");
442 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
443 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
445 Cache.log.debug("Filechooser init thread finished.");
448 // Add the service change listener
449 changeSupport.addJalviewPropertyChangeListener("services",
450 new PropertyChangeListener()
454 public void propertyChange(PropertyChangeEvent evt)
456 Cache.log.debug("Firing service changed event for "
457 + evt.getNewValue());
458 JalviewServicesChanged(evt);
463 } // end BH 2018 ignore
465 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
467 this.addWindowListener(new WindowAdapter()
470 public void windowClosing(WindowEvent evt)
477 this.addMouseListener(ma = new MouseAdapter()
480 public void mousePressed(MouseEvent evt)
482 if (evt.isPopupTrigger()) // Mac
484 showPasteMenu(evt.getX(), evt.getY());
489 public void mouseReleased(MouseEvent evt)
491 if (evt.isPopupTrigger()) // Windows
493 showPasteMenu(evt.getX(), evt.getY());
497 desktop.addMouseListener(ma);
502 * Answers true if user preferences to enable experimental features is True
507 public boolean showExperimental()
509 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
510 Boolean.FALSE.toString());
511 return Boolean.valueOf(experimental).booleanValue();
514 public void doConfigureStructurePrefs()
516 // configure services
517 StructureSelectionManager ssm = StructureSelectionManager
518 .getStructureSelectionManager(this);
519 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
521 ssm.setAddTempFacAnnot(jalview.bin.Cache
522 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
523 ssm.setProcessSecondaryStructure(jalview.bin.Cache
524 .getDefault(Preferences.STRUCT_FROM_PDB, true));
525 ssm.setSecStructServices(
526 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
530 ssm.setAddTempFacAnnot(false);
531 ssm.setProcessSecondaryStructure(false);
532 ssm.setSecStructServices(false);
536 public void checkForNews()
545 final Desktop me = this;
546 // Thread off the news reader, in case there are connection problems.
547 addDialogThread(new Runnable()
552 Cache.log.debug("Starting news thread.");
554 jvnews = new BlogReader(me);
555 showNews.setVisible(true);
556 Cache.log.debug("Completed news thread.");
562 public void getIdentifiersOrgData()
564 // Thread off the identifiers fetcher
565 addDialogThread(new Runnable()
570 Cache.log.debug("Downloading data from identifiers.org");
571 UrlDownloadClient client = new UrlDownloadClient();
574 client.download(IdOrgSettings.getUrl(),
575 IdOrgSettings.getDownloadLocation());
576 } catch (IOException e)
578 Cache.log.debug("Exception downloading identifiers.org data"
586 protected void showNews_actionPerformed(ActionEvent e)
588 showNews(showNews.isSelected());
591 void showNews(boolean visible)
600 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
601 showNews.setSelected(visible);
602 if (visible && !jvnews.isVisible())
604 new Thread(new Runnable()
609 long now = System.currentTimeMillis();
610 Desktop.instance.setProgressBar(
611 MessageManager.getString("status.refreshing_news"),
613 jvnews.refreshNews();
614 Desktop.instance.setProgressBar(null, now);
623 * recover the last known dimensions for a jalview window
626 * - empty string is desktop, all other windows have unique prefix
627 * @return null or last known dimensions scaled to current geometry (if last
628 * window geom was known)
630 Rectangle getLastKnownDimensions(String windowName)
632 // TODO: lock aspect ratio for scaling desktop Bug #0058199
633 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
634 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
635 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
636 String width = jalview.bin.Cache
637 .getProperty(windowName + "SCREEN_WIDTH");
638 String height = jalview.bin.Cache
639 .getProperty(windowName + "SCREEN_HEIGHT");
640 if ((x != null) && (y != null) && (width != null) && (height != null))
642 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
643 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
644 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
646 // attempt #1 - try to cope with change in screen geometry - this
647 // version doesn't preserve original jv aspect ratio.
648 // take ratio of current screen size vs original screen size.
649 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
650 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
651 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
652 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
653 // rescale the bounds depending upon the current screen geometry.
654 ix = (int) (ix * sw);
655 iw = (int) (iw * sw);
656 iy = (int) (iy * sh);
657 ih = (int) (ih * sh);
658 while (ix >= screenSize.width)
660 jalview.bin.Cache.log.debug(
661 "Window geometry location recall error: shifting horizontal to within screenbounds.");
662 ix -= screenSize.width;
664 while (iy >= screenSize.height)
666 jalview.bin.Cache.log.debug(
667 "Window geometry location recall error: shifting vertical to within screenbounds.");
668 iy -= screenSize.height;
670 jalview.bin.Cache.log.debug(
671 "Got last known dimensions for " + windowName + ": x:" + ix
672 + " y:" + iy + " width:" + iw + " height:" + ih);
674 // return dimensions for new instance
675 return new Rectangle(ix, iy, iw, ih);
680 private void doVamsasClientCheck()
682 if (/** @j2sNative false && */ // BH 2018
683 jalview.bin.Cache.vamsasJarsPresent())
685 setupVamsasDisconnectedGui();
686 VamsasMenu.setVisible(true);
687 final Desktop us = this;
688 VamsasMenu.addMenuListener(new MenuListener()
690 // this listener remembers when the menu was first selected, and
691 // doesn't rebuild the session list until it has been cleared and
693 boolean refresh = true;
696 public void menuCanceled(MenuEvent e)
702 public void menuDeselected(MenuEvent e)
708 public void menuSelected(MenuEvent e)
712 us.buildVamsasStMenu();
717 vamsasStart.setVisible(true);
721 void showPasteMenu(int x, int y)
723 JPopupMenu popup = new JPopupMenu();
724 JMenuItem item = new JMenuItem(
725 MessageManager.getString("label.paste_new_window"));
726 item.addActionListener(new ActionListener()
729 public void actionPerformed(ActionEvent evt)
736 popup.show(this, x, y);
743 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
744 Transferable contents = c.getContents(this);
746 if (contents != null)
748 String file = (String) contents
749 .getTransferData(DataFlavor.stringFlavor);
751 FileFormatI format = new IdentifyFile().identify(file,
752 DataSourceType.PASTE);
754 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
757 } catch (Exception ex)
760 "Unable to paste alignment from system clipboard:\n" + ex);
765 * Adds and opens the given frame to the desktop
776 public static synchronized void addInternalFrame(
777 final JInternalFrame frame, String title, int w, int h)
779 addInternalFrame(frame, title, true, w, h, true, false);
783 * Add an internal frame to the Jalview desktop
790 * When true, display frame immediately, otherwise, caller must call
791 * setVisible themselves.
797 public static synchronized void addInternalFrame(
798 final JInternalFrame frame, String title, boolean makeVisible,
801 addInternalFrame(frame, title, makeVisible, w, h, true, false);
805 * Add an internal frame to the Jalview desktop and make it visible
818 public static synchronized void addInternalFrame(
819 final JInternalFrame frame, String title, int w, int h,
822 addInternalFrame(frame, title, true, w, h, resizable, false);
826 * Add an internal frame to the Jalview desktop
833 * When true, display frame immediately, otherwise, caller must call
834 * setVisible themselves.
841 * @param ignoreMinSize
842 * Do not set the default minimum size for frame
844 public static synchronized void addInternalFrame(
845 final JInternalFrame frame, String title, boolean makeVisible,
846 int w, int h, boolean resizable, boolean ignoreMinSize)
849 // TODO: allow callers to determine X and Y position of frame (eg. via
851 // TODO: consider fixing method to update entries in the window submenu with
852 // the current window title
854 frame.setTitle(title);
855 if (frame.getWidth() < 1 || frame.getHeight() < 1)
859 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
860 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
861 // IF JALVIEW IS RUNNING HEADLESS
862 // ///////////////////////////////////////////////
863 if (instance == null || (System.getProperty("java.awt.headless") != null
864 && System.getProperty("java.awt.headless").equals("true")))
873 frame.setMinimumSize(
874 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
876 // Set default dimension for Alignment Frame window.
877 // The Alignment Frame window could be added from a number of places,
879 // I did this here in order not to miss out on any Alignment frame.
880 if (frame instanceof AlignFrame)
882 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
883 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
887 frame.setVisible(makeVisible);
888 frame.setClosable(true);
889 frame.setResizable(resizable);
890 frame.setMaximizable(resizable);
891 frame.setIconifiable(resizable);
892 frame.setOpaque(/** @j2sNative true || */
895 if (frame.getX() < 1 && frame.getY() < 1)
897 frame.setLocation(xOffset * openFrameCount,
898 yOffset * ((openFrameCount - 1) % 10) + yOffset);
902 * add an entry for the new frame in the Window menu
903 * (and remove it when the frame is closed)
905 final JMenuItem menuItem = new JMenuItem(title);
906 frame.addInternalFrameListener(new InternalFrameAdapter()
909 public void internalFrameActivated(InternalFrameEvent evt)
911 JInternalFrame itf = desktop.getSelectedFrame();
914 if (itf instanceof AlignFrame)
916 Jalview.setCurrentAlignFrame((AlignFrame) itf);
923 public void internalFrameClosed(InternalFrameEvent evt)
925 PaintRefresher.RemoveComponent(frame);
928 * defensive check to prevent frames being
929 * added half off the window
931 if (openFrameCount > 0)
937 * ensure no reference to alignFrame retained by menu item listener
939 if (menuItem.getActionListeners().length > 0)
941 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
943 windowMenu.remove(menuItem);
947 menuItem.addActionListener(new ActionListener()
950 public void actionPerformed(ActionEvent e)
954 frame.setSelected(true);
955 frame.setIcon(false);
956 } catch (java.beans.PropertyVetoException ex)
963 setKeyBindings(frame);
967 windowMenu.add(menuItem);
972 frame.setSelected(true);
973 frame.requestFocus();
974 } catch (java.beans.PropertyVetoException ve)
976 } catch (java.lang.ClassCastException cex)
979 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
985 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
990 private static void setKeyBindings(JInternalFrame frame)
992 @SuppressWarnings("serial")
993 final Action closeAction = new AbstractAction()
996 public void actionPerformed(ActionEvent e)
1003 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1005 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1006 InputEvent.CTRL_DOWN_MASK);
1007 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1008 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1010 InputMap inputMap = frame
1011 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1012 String ctrlW = ctrlWKey.toString();
1013 inputMap.put(ctrlWKey, ctrlW);
1014 inputMap.put(cmdWKey, ctrlW);
1016 ActionMap actionMap = frame.getActionMap();
1017 actionMap.put(ctrlW, closeAction);
1021 public void lostOwnership(Clipboard clipboard, Transferable contents)
1025 Desktop.jalviewClipboard = null;
1028 internalCopy = false;
1032 public void dragEnter(DropTargetDragEvent evt)
1037 public void dragExit(DropTargetEvent evt)
1042 public void dragOver(DropTargetDragEvent evt)
1047 public void dropActionChanged(DropTargetDragEvent evt)
1058 public void drop(DropTargetDropEvent evt)
1060 boolean success = true;
1061 // JAL-1552 - acceptDrop required before getTransferable call for
1062 // Java's Transferable for native dnd
1063 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1064 Transferable t = evt.getTransferable();
1065 List<Object> files = new ArrayList<>();
1066 List<DataSourceType> protocols = new ArrayList<>();
1070 Desktop.transferFromDropTarget(files, protocols, evt, t);
1071 } catch (Exception e)
1073 e.printStackTrace();
1081 for (int i = 0; i < files.size(); i++)
1083 // BH 2018 File or String
1084 Object file = files.get(i);
1085 String fileName = file.toString();
1086 DataSourceType protocol = (protocols == null)
1087 ? DataSourceType.FILE
1089 FileFormatI format = null;
1091 if (fileName.endsWith(".jar"))
1093 format = FileFormat.Jalview;
1098 format = new IdentifyFile().identify(file, protocol);
1101 new FileLoader().LoadFile(null, file, protocol, format);
1104 } catch (Exception ex)
1109 evt.dropComplete(success); // need this to ensure input focus is properly
1110 // transfered to any new windows created
1120 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1122 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1123 JalviewFileChooser chooser = JalviewFileChooser
1124 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1126 chooser.setFileView(new JalviewFileView());
1127 chooser.setDialogTitle(
1128 MessageManager.getString("label.open_local_file"));
1129 chooser.setToolTipText(MessageManager.getString("action.open"));
1131 chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION)
1137 File selectedFile = chooser.getSelectedFile();
1138 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1140 FileFormatI format = chooser.getSelectedFormat();
1143 * Call IdentifyFile to verify the file contains what its extension implies.
1144 * Skip this step for dynamically added file formats, because
1145 * IdentifyFile does not know how to recognise them.
1147 if (FileFormats.getInstance().isIdentifiable(format))
1151 format = new IdentifyFile().identify(selectedFile,
1152 DataSourceType.FILE);
1153 } catch (FileFormatException e)
1155 // format = null; //??
1159 new FileLoader().LoadFile(viewport, selectedFile,
1160 DataSourceType.FILE, format);
1162 }).openDialog(this);
1172 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1174 // This construct allows us to have a wider textfield
1176 JLabel label = new JLabel(
1177 MessageManager.getString("label.input_file_url"));
1179 JComboBox history = new JComboBox();
1180 JPanel panel = new JPanel(new GridLayout(2, 1));
1183 history.setPreferredSize(new Dimension(400, 20));
1184 history.setEditable(true);
1185 history.addItem("http://www.");
1187 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1191 if (historyItems != null)
1193 st = new StringTokenizer(historyItems, "\t");
1195 while (st.hasMoreTokens())
1197 history.addItem(st.nextElement());
1201 // BH 2018 -- providing a callback for SwingJS
1202 // dialogOption is just a simple way to provide
1203 // context for the modal-like response.
1204 // The only requirement is that desktop implement
1205 // PropertyChangeListener, which is used already in Java
1206 // for changes in input value and such within the dialogs.
1208 String dialogOption = "label.input_alignment_from_url";
1209 desktop.dialogData = new Object[] { dialogOption, viewport, history };
1210 desktop.onDialogReturn(JvOptionPane.showInternalConfirmDialog(desktop,
1211 panel, MessageManager.getString(dialogOption),
1212 JvOptionPane.OK_CANCEL_OPTION));
1214 // no code may follow this, as SwingJS will not block
1215 // callback in JavaScript comes via a property change event,
1216 // thus going into desktop.onDialogReturn(int) just the same as
1222 * Opens the CutAndPaste window for the user to paste an alignment in to
1225 * - if not null, the pasted alignment is added to the current
1226 * alignment; if null, to a new alignment window
1229 public void inputTextboxMenuItem_actionPerformed(
1230 AlignmentViewPanel viewPanel)
1232 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1233 cap.setForInput(viewPanel);
1234 Desktop.addInternalFrame(cap,
1235 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1245 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1246 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1248 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1249 screen.height + "");
1250 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1251 getWidth(), getHeight()));
1253 if (jconsole != null)
1255 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1256 jconsole.stopConsole();
1260 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1263 if (dialogExecutor != null)
1265 dialogExecutor.shutdownNow();
1267 closeAll_actionPerformed(null);
1269 if (groovyConsole != null)
1271 // suppress a possible repeat prompt to save script
1272 groovyConsole.setDirty(false);
1273 groovyConsole.exit();
1278 private void storeLastKnownDimensions(String string, Rectangle jc)
1280 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1281 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1282 + " height:" + jc.height);
1284 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1285 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1286 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1287 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1297 public void aboutMenuItem_actionPerformed(ActionEvent e)
1299 // StringBuffer message = getAboutMessage(false);
1300 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1302 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1303 new Thread(new Runnable()
1308 new SplashScreen(true);
1313 public StringBuffer getAboutMessage(boolean shortv)
1315 StringBuffer message = new StringBuffer();
1316 message.append("<html>");
1319 message.append("<h1><strong>Version: "
1320 + jalview.bin.Cache.getProperty("VERSION")
1321 + "</strong></h1>");
1322 message.append("<strong>Last Updated: <em>"
1323 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1324 + "</em></strong>");
1330 message.append("<strong>Version "
1331 + jalview.bin.Cache.getProperty("VERSION")
1332 + "; last updated: "
1333 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1336 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1337 .equals("Checking"))
1339 message.append("<br>...Checking latest version...</br>");
1341 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1342 .equals(jalview.bin.Cache.getProperty("VERSION")))
1344 boolean red = false;
1345 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1346 .indexOf("automated build") == -1)
1349 // Displayed when code version and jnlp version do not match and code
1350 // version is not a development build
1351 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1354 message.append("<br>!! Version "
1355 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1357 + " is available for download from "
1358 + jalview.bin.Cache.getDefault("www.jalview.org",
1359 "http://www.jalview.org")
1363 message.append("</div>");
1366 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1368 "The Jalview Authors (See AUTHORS file for current list)")
1369 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1370 + "<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"
1371 + "<br><br>If you use Jalview, please cite:"
1372 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1373 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1374 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1386 public void documentationMenuItem_actionPerformed(ActionEvent e)
1390 Help.showHelpWindow();
1391 } catch (Exception ex)
1397 public void closeAll_actionPerformed(ActionEvent e)
1399 // TODO show a progress bar while closing?
1400 JInternalFrame[] frames = desktop.getAllFrames();
1401 for (int i = 0; i < frames.length; i++)
1405 frames[i].setClosed(true);
1406 } catch (java.beans.PropertyVetoException ex)
1410 Jalview.setCurrentAlignFrame(null);
1411 System.out.println("ALL CLOSED");
1412 if (v_client != null)
1414 // TODO clear binding to vamsas document objects on close_all
1418 * reset state of singleton objects as appropriate (clear down session state
1419 * when all windows are closed)
1421 StructureSelectionManager ssm = StructureSelectionManager
1422 .getStructureSelectionManager(this);
1430 public void raiseRelated_actionPerformed(ActionEvent e)
1432 reorderAssociatedWindows(false, false);
1436 public void minimizeAssociated_actionPerformed(ActionEvent e)
1438 reorderAssociatedWindows(true, false);
1441 void closeAssociatedWindows()
1443 reorderAssociatedWindows(false, true);
1449 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1453 protected void garbageCollect_actionPerformed(ActionEvent e)
1455 // We simply collect the garbage
1456 jalview.bin.Cache.log.debug("Collecting garbage...");
1458 jalview.bin.Cache.log.debug("Finished garbage collection.");
1465 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1469 protected void showMemusage_actionPerformed(ActionEvent e)
1471 desktop.showMemoryUsage(showMemusage.isSelected());
1478 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1482 protected void showConsole_actionPerformed(ActionEvent e)
1484 showConsole(showConsole.isSelected());
1487 Console jconsole = null;
1490 * control whether the java console is visible or not
1494 void showConsole(boolean selected)
1496 // TODO: decide if we should update properties file
1497 if (jconsole != null) // BH 2018
1499 showConsole.setSelected(selected);
1500 Cache.setProperty("SHOW_JAVA_CONSOLE",
1501 Boolean.valueOf(selected).toString());
1502 jconsole.setVisible(selected);
1506 void reorderAssociatedWindows(boolean minimize, boolean close)
1508 JInternalFrame[] frames = desktop.getAllFrames();
1509 if (frames == null || frames.length < 1)
1514 AlignmentViewport source = null, target = null;
1515 if (frames[0] instanceof AlignFrame)
1517 source = ((AlignFrame) frames[0]).getCurrentView();
1519 else if (frames[0] instanceof TreePanel)
1521 source = ((TreePanel) frames[0]).getViewPort();
1523 else if (frames[0] instanceof PCAPanel)
1525 source = ((PCAPanel) frames[0]).av;
1527 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1529 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1534 for (int i = 0; i < frames.length; i++)
1537 if (frames[i] == null)
1541 if (frames[i] instanceof AlignFrame)
1543 target = ((AlignFrame) frames[i]).getCurrentView();
1545 else if (frames[i] instanceof TreePanel)
1547 target = ((TreePanel) frames[i]).getViewPort();
1549 else if (frames[i] instanceof PCAPanel)
1551 target = ((PCAPanel) frames[i]).av;
1553 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1555 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1558 if (source == target)
1564 frames[i].setClosed(true);
1568 frames[i].setIcon(minimize);
1571 frames[i].toFront();
1575 } catch (java.beans.PropertyVetoException ex)
1590 protected void preferences_actionPerformed(ActionEvent e)
1602 public void saveState_actionPerformed(ActionEvent e)
1604 // TODO: JAL-3048 not needed for Jalview-JS
1606 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1609 chooser.setFileView(new JalviewFileView());
1610 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1612 int value = chooser.showSaveDialog(this);
1614 if (value == JalviewFileChooser.APPROVE_OPTION)
1616 final Desktop me = this;
1617 final java.io.File choice = chooser.getSelectedFile();
1618 setProjectFile(choice);
1620 new Thread(new Runnable()
1625 // TODO: refactor to Jalview desktop session controller action.
1626 setProgressBar(MessageManager.formatMessage(
1627 "label.saving_jalview_project", new Object[]
1628 { choice.getName() }), choice.hashCode());
1629 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1630 choice.getParent());
1631 // TODO catch and handle errors for savestate
1632 // TODO prevent user from messing with the Desktop whilst we're saving
1635 new Jalview2XML().saveState(choice);
1636 } catch (OutOfMemoryError oom)
1639 "Whilst saving current state to " + choice.getName(),
1641 } catch (Exception ex)
1644 "Problems whilst trying to save to " + choice.getName(),
1646 JvOptionPane.showMessageDialog(me,
1647 MessageManager.formatMessage(
1648 "label.error_whilst_saving_current_state_to",
1650 { choice.getName() }),
1651 MessageManager.getString("label.couldnt_save_project"),
1652 JvOptionPane.WARNING_MESSAGE);
1654 setProgressBar(null, choice.hashCode());
1660 private void setProjectFile(File choice)
1662 this.projectFile = choice;
1665 public File getProjectFile()
1667 return this.projectFile;
1677 public void loadState_actionPerformed(ActionEvent e)
1679 // TODO: JAL-3048 not needed for Jalview-JS
1681 JalviewFileChooser chooser = new JalviewFileChooser(
1682 Cache.getProperty("LAST_DIRECTORY"), new String[]
1685 { "Jalview Project", "Jalview Project (old)" },
1687 chooser.setFileView(new JalviewFileView());
1688 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1690 int value = chooser.showOpenDialog(this);
1692 if (value == JalviewFileChooser.APPROVE_OPTION)
1694 final File selectedFile = chooser.getSelectedFile();
1695 setProjectFile(selectedFile);
1696 final String choice = selectedFile.getAbsolutePath();
1697 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1698 new Thread(new Runnable()
1703 setProgressBar(MessageManager.formatMessage(
1704 "label.loading_jalview_project", new Object[]
1705 { choice }), choice.hashCode());
1708 new Jalview2XML().loadJalviewAlign(choice);
1709 } catch (OutOfMemoryError oom)
1711 new OOMWarning("Whilst loading project from " + choice, oom);
1712 } catch (Exception ex)
1715 "Problems whilst loading project from " + choice, ex);
1716 JvOptionPane.showMessageDialog(Desktop.desktop,
1717 MessageManager.formatMessage(
1718 "label.error_whilst_loading_project_from",
1721 MessageManager.getString("label.couldnt_load_project"),
1722 JvOptionPane.WARNING_MESSAGE);
1724 setProgressBar(null, choice.hashCode());
1731 public void inputSequence_actionPerformed(ActionEvent e)
1733 new SequenceFetcher(this);
1736 JPanel progressPanel;
1738 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1740 public void startLoading(final Object fileName)
1742 if (fileLoadingCount == 0)
1744 fileLoadingPanels.add(addProgressPanel(MessageManager
1745 .formatMessage("label.loading_file", new Object[]
1751 private JPanel addProgressPanel(String string)
1753 if (progressPanel == null)
1755 progressPanel = new JPanel(new GridLayout(1, 1));
1756 totalProgressCount = 0;
1757 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1759 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1760 JProgressBar progressBar = new JProgressBar();
1761 progressBar.setIndeterminate(true);
1763 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1765 thisprogress.add(progressBar, BorderLayout.CENTER);
1766 progressPanel.add(thisprogress);
1767 ((GridLayout) progressPanel.getLayout()).setRows(
1768 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1769 ++totalProgressCount;
1770 instance.validate();
1771 return thisprogress;
1774 int totalProgressCount = 0;
1776 private void removeProgressPanel(JPanel progbar)
1778 if (progressPanel != null)
1780 synchronized (progressPanel)
1782 progressPanel.remove(progbar);
1783 GridLayout gl = (GridLayout) progressPanel.getLayout();
1784 gl.setRows(gl.getRows() - 1);
1785 if (--totalProgressCount < 1)
1787 this.getContentPane().remove(progressPanel);
1788 progressPanel = null;
1795 public void stopLoading()
1798 if (fileLoadingCount < 1)
1800 while (fileLoadingPanels.size() > 0)
1802 removeProgressPanel(fileLoadingPanels.remove(0));
1804 fileLoadingPanels.clear();
1805 fileLoadingCount = 0;
1810 public static int getViewCount(String alignmentId)
1812 AlignmentViewport[] aps = getViewports(alignmentId);
1813 return (aps == null) ? 0 : aps.length;
1818 * @param alignmentId
1819 * - if null, all sets are returned
1820 * @return all AlignmentPanels concerning the alignmentId sequence set
1822 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1824 if (Desktop.desktop == null)
1826 // no frames created and in headless mode
1827 // TODO: verify that frames are recoverable when in headless mode
1830 List<AlignmentPanel> aps = new ArrayList<>();
1831 AlignFrame[] frames = getAlignFrames();
1836 for (AlignFrame af : frames)
1838 for (AlignmentPanel ap : af.alignPanels)
1840 if (alignmentId == null
1841 || alignmentId.equals(ap.av.getSequenceSetId()))
1847 if (aps.size() == 0)
1851 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1856 * get all the viewports on an alignment.
1858 * @param sequenceSetId
1859 * unique alignment id (may be null - all viewports returned in that
1861 * @return all viewports on the alignment bound to sequenceSetId
1863 public static AlignmentViewport[] getViewports(String sequenceSetId)
1865 List<AlignmentViewport> viewp = new ArrayList<>();
1866 if (desktop != null)
1868 AlignFrame[] frames = Desktop.getAlignFrames();
1870 for (AlignFrame afr : frames)
1872 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1873 .equals(sequenceSetId))
1875 if (afr.alignPanels != null)
1877 for (AlignmentPanel ap : afr.alignPanels)
1879 if (sequenceSetId == null
1880 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1888 viewp.add(afr.getViewport());
1892 if (viewp.size() > 0)
1894 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1901 * Explode the views in the given frame into separate AlignFrame
1905 public static void explodeViews(AlignFrame af)
1907 int size = af.alignPanels.size();
1913 for (int i = 0; i < size; i++)
1915 AlignmentPanel ap = af.alignPanels.get(i);
1916 AlignFrame newaf = new AlignFrame(ap);
1919 * Restore the view's last exploded frame geometry if known. Multiple
1920 * views from one exploded frame share and restore the same (frame)
1921 * position and size.
1923 Rectangle geometry = ap.av.getExplodedGeometry();
1924 if (geometry != null)
1926 newaf.setBounds(geometry);
1929 ap.av.setGatherViewsHere(false);
1931 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1932 AlignFrame.DEFAULT_HEIGHT);
1935 af.alignPanels.clear();
1936 af.closeMenuItem_actionPerformed(true);
1941 * Gather expanded views (separate AlignFrame's) with the same sequence set
1942 * identifier back in to this frame as additional views, and close the expanded
1943 * views. Note the expanded frames may themselves have multiple views. We take
1948 public void gatherViews(AlignFrame source)
1950 source.viewport.setGatherViewsHere(true);
1951 source.viewport.setExplodedGeometry(source.getBounds());
1952 JInternalFrame[] frames = desktop.getAllFrames();
1953 String viewId = source.viewport.getSequenceSetId();
1955 for (int t = 0; t < frames.length; t++)
1957 if (frames[t] instanceof AlignFrame && frames[t] != source)
1959 AlignFrame af = (AlignFrame) frames[t];
1960 boolean gatherThis = false;
1961 for (int a = 0; a < af.alignPanels.size(); a++)
1963 AlignmentPanel ap = af.alignPanels.get(a);
1964 if (viewId.equals(ap.av.getSequenceSetId()))
1967 ap.av.setGatherViewsHere(false);
1968 ap.av.setExplodedGeometry(af.getBounds());
1969 source.addAlignmentPanel(ap, false);
1975 af.alignPanels.clear();
1976 af.closeMenuItem_actionPerformed(true);
1983 jalview.gui.VamsasApplication v_client = null;
1986 public void vamsasImport_actionPerformed(ActionEvent e)
1988 // TODO: JAL-3048 not needed for Jalview-JS
1990 if (v_client == null)
1992 // Load and try to start a session.
1993 JalviewFileChooser chooser = new JalviewFileChooser(
1994 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
1996 chooser.setFileView(new JalviewFileView());
1997 chooser.setDialogTitle(
1998 MessageManager.getString("label.open_saved_vamsas_session"));
1999 chooser.setToolTipText(MessageManager.getString(
2000 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2002 int value = chooser.showOpenDialog(this);
2004 if (value == JalviewFileChooser.APPROVE_OPTION)
2006 String fle = chooser.getSelectedFile().toString();
2007 if (!vamsasImport(chooser.getSelectedFile()))
2009 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2010 MessageManager.formatMessage(
2011 "label.couldnt_import_as_vamsas_session",
2015 .getString("label.vamsas_document_import_failed"),
2016 JvOptionPane.ERROR_MESSAGE);
2022 jalview.bin.Cache.log.error(
2023 "Implementation error - load session from a running session is not supported.");
2028 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2031 * @return true if import was a success and a session was started.
2033 public boolean vamsasImport(URL url)
2035 // TODO: create progress bar
2036 if (v_client != null)
2039 jalview.bin.Cache.log.error(
2040 "Implementation error - load session from a running session is not supported.");
2046 // copy the URL content to a temporary local file
2047 // TODO: be a bit cleverer here with nio (?!)
2048 File file = File.createTempFile("vdocfromurl", ".vdj");
2049 FileOutputStream fos = new FileOutputStream(file);
2050 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2051 byte[] buffer = new byte[2048];
2053 while ((ln = bis.read(buffer)) > -1)
2055 fos.write(buffer, 0, ln);
2059 v_client = new jalview.gui.VamsasApplication(this, file,
2060 url.toExternalForm());
2061 } catch (Exception ex)
2063 jalview.bin.Cache.log.error(
2064 "Failed to create new vamsas session from contents of URL "
2069 setupVamsasConnectedGui();
2070 v_client.initial_update(); // TODO: thread ?
2071 return v_client.inSession();
2075 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2078 * @return true if import was a success and a session was started.
2080 public boolean vamsasImport(File file)
2082 if (v_client != null)
2085 jalview.bin.Cache.log.error(
2086 "Implementation error - load session from a running session is not supported.");
2090 setProgressBar(MessageManager.formatMessage(
2091 "status.importing_vamsas_session_from", new Object[]
2092 { file.getName() }), file.hashCode());
2095 v_client = new jalview.gui.VamsasApplication(this, file, null);
2096 } catch (Exception ex)
2098 setProgressBar(MessageManager.formatMessage(
2099 "status.importing_vamsas_session_from", new Object[]
2100 { file.getName() }), file.hashCode());
2101 jalview.bin.Cache.log.error(
2102 "New vamsas session from existing session file failed:", ex);
2105 setupVamsasConnectedGui();
2106 v_client.initial_update(); // TODO: thread ?
2107 setProgressBar(MessageManager.formatMessage(
2108 "status.importing_vamsas_session_from", new Object[]
2109 { file.getName() }), file.hashCode());
2110 return v_client.inSession();
2113 public boolean joinVamsasSession(String mysesid)
2115 if (v_client != null)
2117 throw new Error(MessageManager
2118 .getString("error.try_join_vamsas_session_another"));
2120 if (mysesid == null)
2123 MessageManager.getString("error.invalid_vamsas_session_id"));
2125 v_client = new VamsasApplication(this, mysesid);
2126 setupVamsasConnectedGui();
2127 v_client.initial_update();
2128 return (v_client.inSession());
2132 public void vamsasStart_actionPerformed(ActionEvent e)
2134 if (v_client == null)
2137 // we just start a default session for moment.
2139 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2140 * getProperty("LAST_DIRECTORY"));
2142 * chooser.setFileView(new JalviewFileView());
2143 * chooser.setDialogTitle("Load Vamsas file");
2144 * chooser.setToolTipText("Import");
2146 * int value = chooser.showOpenDialog(this);
2148 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2149 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2151 v_client = new VamsasApplication(this);
2152 setupVamsasConnectedGui();
2153 v_client.initial_update(); // TODO: thread ?
2157 // store current data in session.
2158 v_client.push_update(); // TODO: thread
2162 protected void setupVamsasConnectedGui()
2164 vamsasStart.setText(MessageManager.getString("label.session_update"));
2165 vamsasSave.setVisible(true);
2166 vamsasStop.setVisible(true);
2167 vamsasImport.setVisible(false); // Document import to existing session is
2168 // not possible for vamsas-client-1.0.
2171 protected void setupVamsasDisconnectedGui()
2173 vamsasSave.setVisible(false);
2174 vamsasStop.setVisible(false);
2175 vamsasImport.setVisible(true);
2177 .setText(MessageManager.getString("label.new_vamsas_session"));
2181 public void vamsasStop_actionPerformed(ActionEvent e)
2183 if (v_client != null)
2185 v_client.end_session();
2187 setupVamsasDisconnectedGui();
2191 protected void buildVamsasStMenu()
2193 if (v_client == null)
2195 String[] sess = null;
2198 sess = VamsasApplication.getSessionList();
2199 } catch (Exception e)
2201 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2207 jalview.bin.Cache.log.debug(
2208 "Got current sessions list: " + sess.length + " entries.");
2209 VamsasStMenu.removeAll();
2210 for (int i = 0; i < sess.length; i++)
2212 JMenuItem sessit = new JMenuItem();
2213 sessit.setText(sess[i]);
2214 sessit.setToolTipText(MessageManager
2215 .formatMessage("label.connect_to_session", new Object[]
2217 final Desktop dsktp = this;
2218 final String mysesid = sess[i];
2219 sessit.addActionListener(new ActionListener()
2223 public void actionPerformed(ActionEvent e)
2225 if (dsktp.v_client == null)
2227 Thread rthr = new Thread(new Runnable()
2233 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2234 dsktp.setupVamsasConnectedGui();
2235 dsktp.v_client.initial_update();
2243 VamsasStMenu.add(sessit);
2245 // don't show an empty menu.
2246 VamsasStMenu.setVisible(sess.length > 0);
2251 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2252 VamsasStMenu.removeAll();
2253 VamsasStMenu.setVisible(false);
2258 // Not interested in the content. Just hide ourselves.
2259 VamsasStMenu.setVisible(false);
2264 public void vamsasSave_actionPerformed(ActionEvent e)
2266 // TODO: JAL-3048 not needed for Jalview-JS
2268 if (v_client != null)
2270 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2271 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2274 chooser.setFileView(new JalviewFileView());
2275 chooser.setDialogTitle(MessageManager
2276 .getString("label.save_vamsas_document_archive"));
2278 int value = chooser.showSaveDialog(this);
2280 if (value == JalviewFileChooser.APPROVE_OPTION)
2282 java.io.File choice = chooser.getSelectedFile();
2283 JPanel progpanel = addProgressPanel(MessageManager
2284 .formatMessage("label.saving_vamsas_doc", new Object[]
2285 { choice.getName() }));
2286 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2287 String warnmsg = null;
2288 String warnttl = null;
2291 v_client.vclient.storeDocument(choice);
2294 warnttl = "Serious Problem saving Vamsas Document";
2295 warnmsg = ex.toString();
2296 jalview.bin.Cache.log
2297 .error("Error Whilst saving document to " + choice, ex);
2299 } catch (Exception ex)
2301 warnttl = "Problem saving Vamsas Document.";
2302 warnmsg = ex.toString();
2303 jalview.bin.Cache.log.warn(
2304 "Exception Whilst saving document to " + choice, ex);
2307 removeProgressPanel(progpanel);
2308 if (warnmsg != null)
2310 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2312 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2318 JPanel vamUpdate = null;
2321 * hide vamsas user gui bits when a vamsas document event is being handled.
2324 * true to hide gui, false to reveal gui
2326 public void setVamsasUpdate(boolean b)
2328 Cache.log.debug("Setting gui for Vamsas update "
2329 + (b ? "in progress" : "finished"));
2331 if (vamUpdate != null)
2333 this.removeProgressPanel(vamUpdate);
2337 vamUpdate = this.addProgressPanel(
2338 MessageManager.getString("label.updating_vamsas_session"));
2340 vamsasStart.setVisible(!b);
2341 vamsasStop.setVisible(!b);
2342 vamsasSave.setVisible(!b);
2345 public JInternalFrame[] getAllFrames()
2347 return desktop.getAllFrames();
2351 * Checks the given url to see if it gives a response indicating that the user
2352 * should be informed of a new questionnaire.
2356 public void checkForQuestionnaire(String url)
2358 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2359 // javax.swing.SwingUtilities.invokeLater(jvq);
2360 new Thread(jvq).start();
2363 public void checkURLLinks()
2365 // Thread off the URL link checker
2366 addDialogThread(new Runnable()
2371 if (/** @j2sNative false && */ // BH 2018
2372 Cache.getDefault("CHECKURLLINKS", true))
2374 // check what the actual links are - if it's just the default don't
2375 // bother with the warning
2376 List<String> links = Preferences.sequenceUrlLinks
2379 // only need to check links if there is one with a
2380 // SEQUENCE_ID which is not the default EMBL_EBI link
2381 ListIterator<String> li = links.listIterator();
2382 boolean check = false;
2383 List<JLabel> urls = new ArrayList<>();
2384 while (li.hasNext())
2386 String link = li.next();
2387 if (link.contains(SEQUENCE_ID)
2388 && !UrlConstants.isDefaultString(link))
2391 int barPos = link.indexOf("|");
2392 String urlMsg = barPos == -1 ? link
2393 : link.substring(0, barPos) + ": "
2394 + link.substring(barPos + 1);
2395 urls.add(new JLabel(urlMsg));
2403 // ask user to check in case URL links use old style tokens
2404 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2405 JPanel msgPanel = new JPanel();
2406 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2407 msgPanel.add(Box.createVerticalGlue());
2408 JLabel msg = new JLabel(MessageManager
2409 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2410 JLabel msg2 = new JLabel(MessageManager
2411 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2413 for (JLabel url : urls)
2419 final JCheckBox jcb = new JCheckBox(
2420 MessageManager.getString("label.do_not_display_again"));
2421 jcb.addActionListener(new ActionListener()
2424 public void actionPerformed(ActionEvent e)
2426 // update Cache settings for "don't show this again"
2427 boolean showWarningAgain = !jcb.isSelected();
2428 Cache.setProperty("CHECKURLLINKS",
2429 Boolean.valueOf(showWarningAgain).toString());
2434 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2436 .getString("label.SEQUENCE_ID_no_longer_used"),
2437 JvOptionPane.WARNING_MESSAGE);
2444 * Proxy class for JDesktopPane which optionally displays the current memory
2445 * usage and highlights the desktop area with a red bar if free memory runs low.
2449 public class MyDesktopPane extends JDesktopPane
2450 implements Runnable, PropertyChangeListener
2453 public Object[] dialogData;
2457 public void propertyChange(PropertyChangeEvent event)
2459 // TODO this is obsolete with JAL-3048 - delete?
2460 Object val = event.getNewValue();
2461 String name = event.getPropertyName();
2462 System.out.println(name);
2463 switch (event.getSource().getClass().getName())
2465 case "javax.swing.JOptionPane":
2469 onDialogReturn(val);
2472 if (val instanceof Integer)
2474 onDialogReturn(((Integer) val).intValue());
2478 onDialogReturn(val);
2483 case "javax.swing.JFileChooser":
2486 case "SelectedFile":
2487 // in JavaScript, this File object will have a _bytes property,
2488 // because the file data has already been loaded
2489 onDialogReturn(new Object[] { (File) val });
2494 System.out.println(event.getSource().getClass().getName() + " "
2495 + event.getPropertyName() + ": " + event.getNewValue());
2498 // JSCOmponent.DialogCaller interface
2499 void onDialogReturn(Object value)
2501 switch ((String) dialogData[0])
2503 case "SelectedFile":
2505 dialogData[0] = value;
2506 ((Runnable) dialogData[1]).run();
2512 // JSCOmponent.DialogCaller interface
2513 void onDialogReturn(int value)
2515 if (value != Math.floor(value))
2517 // in JavaScript, this will be NaN, oddly enough
2521 switch ((String) dialogData[0])
2524 dialogData[0] = Integer.valueOf(value);
2525 ((Runnable) dialogData[1]).run();
2527 case "label.input_alignment_from_url":
2528 // reconstruct the parameter data
2530 AlignViewport viewport = (AlignViewport) dialogData[1];
2531 JComboBox history = (JComboBox) dialogData[2];
2532 // the rest of this is unchangaed
2533 if (reply != JvOptionPane.OK_OPTION)
2538 String url = history.getSelectedItem().toString();
2540 if (url.toLowerCase().endsWith(".jar"))
2542 if (viewport != null)
2544 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2545 FileFormat.Jalview);
2549 new FileLoader().LoadFile(url, DataSourceType.URL,
2550 FileFormat.Jalview);
2555 FileFormatI format = null;
2558 format = new IdentifyFile().identify(url, DataSourceType.URL);
2559 } catch (FileFormatException e)
2561 // TODO revise error handling, distinguish between
2562 // URL not found and response not valid
2567 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2568 MessageManager.formatMessage("label.couldnt_locate",
2571 MessageManager.getString("label.url_not_found"),
2572 JvOptionPane.WARNING_MESSAGE);
2577 if (viewport != null)
2579 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2584 new FileLoader().LoadFile(url, DataSourceType.URL, format);
2593 private static final float ONE_MB = 1048576f;
2595 boolean showMemoryUsage = false;
2599 java.text.NumberFormat df;
2601 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2604 public MyDesktopPane(boolean showMemoryUsage)
2606 showMemoryUsage(showMemoryUsage);
2609 public void showMemoryUsage(boolean showMemory)
2611 this.showMemoryUsage = showMemory;
2614 Thread worker = new Thread(this);
2620 public boolean isShowMemoryUsage()
2622 return showMemoryUsage;
2628 df = java.text.NumberFormat.getNumberInstance();
2629 df.setMaximumFractionDigits(2);
2630 runtime = Runtime.getRuntime();
2632 while (showMemoryUsage)
2636 maxMemory = runtime.maxMemory() / ONE_MB;
2637 allocatedMemory = runtime.totalMemory() / ONE_MB;
2638 freeMemory = runtime.freeMemory() / ONE_MB;
2639 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2641 percentUsage = (totalFreeMemory / maxMemory) * 100;
2643 // if (percentUsage < 20)
2645 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2647 // instance.set.setBorder(border1);
2650 // sleep after showing usage
2652 } catch (Exception ex)
2654 ex.printStackTrace();
2660 public void paintComponent(Graphics g)
2662 if (showMemoryUsage && g != null && df != null)
2664 if (percentUsage < 20)
2666 g.setColor(Color.red);
2668 FontMetrics fm = g.getFontMetrics();
2671 g.drawString(MessageManager.formatMessage("label.memory_stats",
2673 { df.format(totalFreeMemory), df.format(maxMemory),
2674 df.format(percentUsage) }),
2675 10, getHeight() - fm.getHeight());
2682 * Accessor method to quickly get all the AlignmentFrames loaded.
2684 * @return an array of AlignFrame, or null if none found
2686 public static AlignFrame[] getAlignFrames()
2688 if (Jalview.isHeadlessMode())
2690 // Desktop.desktop is null in headless mode
2691 return new AlignFrame[] { Jalview.currentAlignFrame };
2694 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2700 List<AlignFrame> avp = new ArrayList<>();
2702 for (int i = frames.length - 1; i > -1; i--)
2704 if (frames[i] instanceof AlignFrame)
2706 avp.add((AlignFrame) frames[i]);
2708 else if (frames[i] instanceof SplitFrame)
2711 * Also check for a split frame containing an AlignFrame
2713 GSplitFrame sf = (GSplitFrame) frames[i];
2714 if (sf.getTopFrame() instanceof AlignFrame)
2716 avp.add((AlignFrame) sf.getTopFrame());
2718 if (sf.getBottomFrame() instanceof AlignFrame)
2720 avp.add((AlignFrame) sf.getBottomFrame());
2724 if (avp.size() == 0)
2728 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2733 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2737 public GStructureViewer[] getJmols()
2739 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2745 List<GStructureViewer> avp = new ArrayList<>();
2747 for (int i = frames.length - 1; i > -1; i--)
2749 if (frames[i] instanceof AppJmol)
2751 GStructureViewer af = (GStructureViewer) frames[i];
2755 if (avp.size() == 0)
2759 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2764 * Add Groovy Support to Jalview
2767 public void groovyShell_actionPerformed()
2771 openGroovyConsole();
2772 } catch (Exception ex)
2774 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2775 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2777 MessageManager.getString("label.couldnt_create_groovy_shell"),
2778 MessageManager.getString("label.groovy_support_failed"),
2779 JvOptionPane.ERROR_MESSAGE);
2784 * Open the Groovy console
2786 void openGroovyConsole()
2788 if (groovyConsole == null)
2790 groovyConsole = new groovy.ui.Console();
2791 groovyConsole.setVariable("Jalview", this);
2792 groovyConsole.run();
2795 * We allow only one console at a time, so that AlignFrame menu option
2796 * 'Calculate | Run Groovy script' is unambiguous.
2797 * Disable 'Groovy Console', and enable 'Run script', when the console is
2798 * opened, and the reverse when it is closed
2800 Window window = (Window) groovyConsole.getFrame();
2801 window.addWindowListener(new WindowAdapter()
2804 public void windowClosed(WindowEvent e)
2807 * rebind CMD-Q from Groovy Console to Jalview Quit
2810 enableExecuteGroovy(false);
2816 * show Groovy console window (after close and reopen)
2818 ((Window) groovyConsole.getFrame()).setVisible(true);
2821 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2822 * and disable opening a second console
2824 enableExecuteGroovy(true);
2828 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
2831 protected void addQuitHandler()
2833 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2834 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2835 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2837 getRootPane().getActionMap().put("Quit", new AbstractAction()
2840 public void actionPerformed(ActionEvent e)
2848 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2851 * true if Groovy console is open
2853 public void enableExecuteGroovy(boolean enabled)
2856 * disable opening a second Groovy console
2857 * (or re-enable when the console is closed)
2859 groovyShell.setEnabled(!enabled);
2861 AlignFrame[] alignFrames = getAlignFrames();
2862 if (alignFrames != null)
2864 for (AlignFrame af : alignFrames)
2866 af.setGroovyEnabled(enabled);
2872 * Progress bars managed by the IProgressIndicator method.
2874 private Hashtable<Long, JPanel> progressBars;
2876 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2881 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2884 public void setProgressBar(String message, long id)
2886 if (progressBars == null)
2888 progressBars = new Hashtable<>();
2889 progressBarHandlers = new Hashtable<>();
2892 if (progressBars.get(new Long(id)) != null)
2894 JPanel panel = progressBars.remove(new Long(id));
2895 if (progressBarHandlers.contains(new Long(id)))
2897 progressBarHandlers.remove(new Long(id));
2899 removeProgressPanel(panel);
2903 progressBars.put(new Long(id), addProgressPanel(message));
2910 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2911 * jalview.gui.IProgressIndicatorHandler)
2914 public void registerHandler(final long id,
2915 final IProgressIndicatorHandler handler)
2917 if (progressBarHandlers == null
2918 || !progressBars.containsKey(new Long(id)))
2920 throw new Error(MessageManager.getString(
2921 "error.call_setprogressbar_before_registering_handler"));
2923 progressBarHandlers.put(new Long(id), handler);
2924 final JPanel progressPanel = progressBars.get(new Long(id));
2925 if (handler.canCancel())
2927 JButton cancel = new JButton(
2928 MessageManager.getString("action.cancel"));
2929 final IProgressIndicator us = this;
2930 cancel.addActionListener(new ActionListener()
2934 public void actionPerformed(ActionEvent e)
2936 handler.cancelActivity(id);
2937 us.setProgressBar(MessageManager
2938 .formatMessage("label.cancelled_params", new Object[]
2939 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2943 progressPanel.add(cancel, BorderLayout.EAST);
2949 * @return true if any progress bars are still active
2952 public boolean operationInProgress()
2954 if (progressBars != null && progressBars.size() > 0)
2962 * This will return the first AlignFrame holding the given viewport instance. It
2963 * will break if there are more than one AlignFrames viewing a particular av.
2966 * @return alignFrame for viewport
2968 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2970 if (desktop != null)
2972 AlignmentPanel[] aps = getAlignmentPanels(
2973 viewport.getSequenceSetId());
2974 for (int panel = 0; aps != null && panel < aps.length; panel++)
2976 if (aps[panel] != null && aps[panel].av == viewport)
2978 return aps[panel].alignFrame;
2985 public VamsasApplication getVamsasApplication()
2992 * flag set if jalview GUI is being operated programmatically
2994 private boolean inBatchMode = false;
2997 * check if jalview GUI is being operated programmatically
2999 * @return inBatchMode
3001 public boolean isInBatchMode()
3007 * set flag if jalview GUI is being operated programmatically
3009 * @param inBatchMode
3011 public void setInBatchMode(boolean inBatchMode)
3013 this.inBatchMode = inBatchMode;
3016 public void startServiceDiscovery()
3018 startServiceDiscovery(false);
3021 public void startServiceDiscovery(boolean blocking)
3023 boolean alive = true;
3024 Thread t0 = null, t1 = null, t2 = null;
3025 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3028 // todo: changesupport handlers need to be transferred
3029 if (discoverer == null)
3031 discoverer = new jalview.ws.jws1.Discoverer();
3032 // register PCS handler for desktop.
3033 discoverer.addPropertyChangeListener(changeSupport);
3035 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3036 // until we phase out completely
3037 (t0 = new Thread(discoverer)).start();
3040 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3042 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3043 .startDiscoverer(changeSupport);
3047 // TODO: do rest service discovery
3056 } catch (Exception e)
3059 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3060 || (t3 != null && t3.isAlive())
3061 || (t0 != null && t0.isAlive());
3067 * called to check if the service discovery process completed successfully.
3071 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3073 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3075 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3076 .getErrorMessages();
3079 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3081 if (serviceChangedDialog == null)
3083 // only run if we aren't already displaying one of these.
3084 addDialogThread(serviceChangedDialog = new Runnable()
3091 * JalviewDialog jd =new JalviewDialog() {
3093 * @Override protected void cancelPressed() { // TODO
3094 * Auto-generated method stub
3096 * }@Override protected void okPressed() { // TODO
3097 * Auto-generated method stub
3099 * }@Override protected void raiseClosed() { // TODO
3100 * Auto-generated method stub
3102 * } }; jd.initDialogFrame(new
3103 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3104 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3105 * + " or mis-configured HTTP proxy settings.<br/>" +
3106 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3108 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3109 * ), true, true, "Web Service Configuration Problem", 450,
3112 * jd.waitForInput();
3114 JvOptionPane.showConfirmDialog(Desktop.desktop,
3115 new JLabel("<html><table width=\"450\"><tr><td>"
3116 + ermsg + "</td></tr></table>"
3117 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3118 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3119 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3120 + " Tools->Preferences dialog box to change them.</p></html>"),
3121 "Web Service Configuration Problem",
3122 JvOptionPane.DEFAULT_OPTION,
3123 JvOptionPane.ERROR_MESSAGE);
3124 serviceChangedDialog = null;
3133 "Errors reported by JABA discovery service. Check web services preferences.\n"
3140 private Runnable serviceChangedDialog = null;
3143 * start a thread to open a URL in the configured browser. Pops up a warning
3144 * dialog to the user if there is an exception when calling out to the browser
3149 public static void showUrl(final String url)
3151 showUrl(url, Desktop.instance);
3155 * Like showUrl but allows progress handler to be specified
3159 * (null) or object implementing IProgressIndicator
3161 public static void showUrl(final String url,
3162 final IProgressIndicator progress)
3164 new Thread(new Runnable()
3171 if (progress != null)
3173 progress.setProgressBar(MessageManager
3174 .formatMessage("status.opening_params", new Object[]
3175 { url }), this.hashCode());
3177 jalview.util.BrowserLauncher.openURL(url);
3178 } catch (Exception ex)
3180 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3182 .getString("label.web_browser_not_found_unix"),
3183 MessageManager.getString("label.web_browser_not_found"),
3184 JvOptionPane.WARNING_MESSAGE);
3186 ex.printStackTrace();
3188 if (progress != null)
3190 progress.setProgressBar(null, this.hashCode());
3196 public static WsParamSetManager wsparamManager = null;
3198 public static ParamManager getUserParameterStore()
3200 if (wsparamManager == null)
3202 wsparamManager = new WsParamSetManager();
3204 return wsparamManager;
3208 * static hyperlink handler proxy method for use by Jalview's internal windows
3212 public static void hyperlinkUpdate(HyperlinkEvent e)
3214 if (e.getEventType() == EventType.ACTIVATED)
3219 url = e.getURL().toString();
3220 Desktop.showUrl(url);
3221 } catch (Exception x)
3225 if (Cache.log != null)
3227 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3232 "Couldn't handle string " + url + " as a URL.");
3235 // ignore any exceptions due to dud links.
3242 * single thread that handles display of dialogs to user.
3244 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3247 * flag indicating if dialogExecutor should try to acquire a permit
3249 private volatile boolean dialogPause = true;
3254 private java.util.concurrent.Semaphore block = new Semaphore(0);
3256 private static groovy.ui.Console groovyConsole;
3259 * add another dialog thread to the queue
3263 public void addDialogThread(final Runnable prompter)
3265 dialogExecutor.submit(new Runnable()
3275 } catch (InterruptedException x)
3280 if (instance == null)
3286 SwingUtilities.invokeAndWait(prompter);
3287 } catch (Exception q)
3289 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3295 public void startDialogQueue()
3297 // set the flag so we don't pause waiting for another permit and semaphore
3298 // the current task to begin
3299 dialogPause = false;
3304 * Outputs an image of the desktop to file in EPS format, after prompting the
3305 * user for choice of Text or Lineart character rendering (unless a preference
3306 * has been set). The file name is generated as
3309 * Jalview_snapshot_nnnnn.eps where nnnnn is the current timestamp in milliseconds
3313 protected void snapShotWindow_actionPerformed(ActionEvent e)
3315 // currently the menu option to do this is not shown
3318 int width = getWidth();
3319 int height = getHeight();
3321 "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
3322 ImageWriterI writer = new ImageWriterI()
3325 public void exportImage(Graphics g) throws Exception
3328 Cache.log.info("Successfully written snapshot to file "
3329 + of.getAbsolutePath());
3332 String title = "View of desktop";
3333 ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
3335 exporter.doExport(of, this, width, height, title);
3339 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3340 * This respects (remembers) any previous 'exploded geometry' i.e. the size and
3341 * location last time the view was expanded (if any). However it does not
3342 * remember the split pane divider location - this is set to match the
3343 * 'exploding' frame.
3347 public void explodeViews(SplitFrame sf)
3349 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3350 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3351 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3353 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3355 int viewCount = topPanels.size();
3362 * Processing in reverse order works, forwards order leaves the first panels
3363 * not visible. I don't know why!
3365 for (int i = viewCount - 1; i >= 0; i--)
3368 * Make new top and bottom frames. These take over the respective
3369 * AlignmentPanel objects, including their AlignmentViewports, so the
3370 * cdna/protein relationships between the viewports is carried over to the
3373 * explodedGeometry holds the (x, y) position of the previously exploded
3374 * SplitFrame, and the (width, height) of the AlignFrame component
3376 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3377 AlignFrame newTopFrame = new AlignFrame(topPanel);
3378 newTopFrame.setSize(oldTopFrame.getSize());
3379 newTopFrame.setVisible(true);
3380 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3381 .getExplodedGeometry();
3382 if (geometry != null)
3384 newTopFrame.setSize(geometry.getSize());
3387 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3388 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3389 newBottomFrame.setSize(oldBottomFrame.getSize());
3390 newBottomFrame.setVisible(true);
3391 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3392 .getExplodedGeometry();
3393 if (geometry != null)
3395 newBottomFrame.setSize(geometry.getSize());
3398 topPanel.av.setGatherViewsHere(false);
3399 bottomPanel.av.setGatherViewsHere(false);
3400 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3402 if (geometry != null)
3404 splitFrame.setLocation(geometry.getLocation());
3406 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3410 * Clear references to the panels (now relocated in the new SplitFrames)
3411 * before closing the old SplitFrame.
3414 bottomPanels.clear();
3419 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3420 * back into the given SplitFrame as additional views. Note that the gathered
3421 * frames may themselves have multiple views.
3425 public void gatherViews(GSplitFrame source)
3428 * special handling of explodedGeometry for a view within a SplitFrame: - it
3429 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3430 * height) of the AlignFrame component
3432 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3433 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3434 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3435 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3436 myBottomFrame.viewport
3437 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3438 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3439 myTopFrame.viewport.setGatherViewsHere(true);
3440 myBottomFrame.viewport.setGatherViewsHere(true);
3441 String topViewId = myTopFrame.viewport.getSequenceSetId();
3442 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3444 JInternalFrame[] frames = desktop.getAllFrames();
3445 for (JInternalFrame frame : frames)
3447 if (frame instanceof SplitFrame && frame != source)
3449 SplitFrame sf = (SplitFrame) frame;
3450 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3451 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3452 boolean gatherThis = false;
3453 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3455 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3456 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3457 if (topViewId.equals(topPanel.av.getSequenceSetId())
3458 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3461 topPanel.av.setGatherViewsHere(false);
3462 bottomPanel.av.setGatherViewsHere(false);
3463 topPanel.av.setExplodedGeometry(
3464 new Rectangle(sf.getLocation(), topFrame.getSize()));
3465 bottomPanel.av.setExplodedGeometry(
3466 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3467 myTopFrame.addAlignmentPanel(topPanel, false);
3468 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3474 topFrame.getAlignPanels().clear();
3475 bottomFrame.getAlignPanels().clear();
3482 * The dust settles...give focus to the tab we did this from.
3484 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3487 public static groovy.ui.Console getGroovyConsole()
3489 return groovyConsole;
3493 * handles the payload of a drag and drop event.
3495 * TODO refactor to desktop utilities class
3498 * - Data source strings extracted from the drop event
3500 * - protocol for each data source extracted from the drop event
3504 * - the payload from the drop event
3507 public static void transferFromDropTarget(List<Object> files,
3508 List<DataSourceType> protocols, DropTargetDropEvent evt,
3509 Transferable t) throws Exception
3512 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3514 // DataFlavor[] flavors = t.getTransferDataFlavors();
3515 // for (int i = 0; i < flavors.length; i++) {
3516 // if (flavors[i].isFlavorJavaFileListType()) {
3517 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3518 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3519 // for (int j = 0; j < list.size(); j++) {
3520 // File file = (File) list.get(j);
3521 // byte[] data = getDroppedFileBytes(file);
3522 // fileName.setText(file.getName() + " - " + data.length + " " +
3523 // evt.getLocation());
3524 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3525 // target.setText(new String(data));
3527 // dtde.dropComplete(true);
3532 DataFlavor uriListFlavor = new DataFlavor(
3533 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3536 urlFlavour = new DataFlavor(
3537 "application/x-java-url; class=java.net.URL");
3538 } catch (ClassNotFoundException cfe)
3540 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3543 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3548 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3549 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3550 // means url may be null.
3553 protocols.add(DataSourceType.URL);
3554 files.add(url.toString());
3555 Cache.log.debug("Drop handled as URL dataflavor "
3556 + files.get(files.size() - 1));
3561 if (Platform.isAMac())
3564 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3568 } catch (Throwable ex)
3570 Cache.log.debug("URL drop handler failed.", ex);
3573 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3575 // Works on Windows and MacOSX
3576 Cache.log.debug("Drop handled as javaFileListFlavor");
3577 for (Object file : (List) t
3578 .getTransferData(DataFlavor.javaFileListFlavor))
3581 protocols.add(DataSourceType.FILE);
3586 // Unix like behaviour
3587 boolean added = false;
3589 if (t.isDataFlavorSupported(uriListFlavor))
3591 Cache.log.debug("Drop handled as uriListFlavor");
3592 // This is used by Unix drag system
3593 data = (String) t.getTransferData(uriListFlavor);
3597 // fallback to text: workaround - on OSX where there's a JVM bug
3598 Cache.log.debug("standard URIListFlavor failed. Trying text");
3599 // try text fallback
3600 DataFlavor textDf = new DataFlavor(
3601 "text/plain;class=java.lang.String");
3602 if (t.isDataFlavorSupported(textDf))
3604 data = (String) t.getTransferData(textDf);
3607 Cache.log.debug("Plain text drop content returned "
3608 + (data == null ? "Null - failed" : data));
3613 while (protocols.size() < files.size())
3615 Cache.log.debug("Adding missing FILE protocol for "
3616 + files.get(protocols.size()));
3617 protocols.add(DataSourceType.FILE);
3619 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3620 data, "\r\n"); st.hasMoreTokens();)
3623 String s = st.nextToken();
3624 if (s.startsWith("#"))
3626 // the line is a comment (as per the RFC 2483)
3629 java.net.URI uri = new java.net.URI(s);
3630 if (uri.getScheme().toLowerCase().startsWith("http"))
3632 protocols.add(DataSourceType.URL);
3633 files.add(uri.toString());
3637 // otherwise preserve old behaviour: catch all for file objects
3638 java.io.File file = new java.io.File(uri);
3639 protocols.add(DataSourceType.FILE);
3640 files.add(file.toString());
3645 if (Cache.log.isDebugEnabled())
3647 if (data == null || !added)
3650 if (t.getTransferDataFlavors() != null
3651 && t.getTransferDataFlavors().length > 0)
3654 "Couldn't resolve drop data. Here are the supported flavors:");
3655 for (DataFlavor fl : t.getTransferDataFlavors())
3658 "Supported transfer dataflavor: " + fl.toString());
3659 Object df = t.getTransferData(fl);
3662 Cache.log.debug("Retrieves: " + df);
3666 Cache.log.debug("Retrieved nothing");
3672 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3678 if (Platform.isWindows())
3681 Cache.log.debug("Scanning dropped content for Windows Link Files");
3683 // resolve any .lnk files in the file drop
3684 for (int f = 0; f < files.size(); f++)
3686 String source = files.get(f).toString().toLowerCase();
3687 if (protocols.get(f).equals(DataSourceType.FILE)
3688 && (source.endsWith(".lnk") || source.endsWith(".url")
3689 || source.endsWith(".site")))
3693 Object obj = files.get(f);
3694 File lf = (obj instanceof File ? (File) obj
3695 : new File((String) obj));
3696 // process link file to get a URL
3697 Cache.log.debug("Found potential link file: " + lf);
3698 WindowsShortcut wscfile = new WindowsShortcut(lf);
3699 String fullname = wscfile.getRealFilename();
3700 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3701 files.set(f, fullname);
3702 Cache.log.debug("Parsed real filename " + fullname
3703 + " to extract protocol: " + protocols.get(f));
3704 } catch (Exception ex)
3707 "Couldn't parse " + files.get(f) + " as a link file.",
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 for
3727 * either Jmol or Chimera) which are currently open. This may optionally be
3728 * restricted to viewers of a specified class, or viewers linked to a specified
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);