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.viewmodel.AlignmentViewport;
48 import jalview.ws.params.ParamManager;
49 import jalview.ws.utils.UrlDownloadClient;
51 import java.awt.BorderLayout;
52 import java.awt.Color;
53 import java.awt.Dimension;
54 import java.awt.FontMetrics;
55 import java.awt.Graphics;
56 import java.awt.GridLayout;
57 import java.awt.Point;
58 import java.awt.Rectangle;
59 import java.awt.Toolkit;
60 import java.awt.Window;
61 import java.awt.datatransfer.Clipboard;
62 import java.awt.datatransfer.ClipboardOwner;
63 import java.awt.datatransfer.DataFlavor;
64 import java.awt.datatransfer.Transferable;
65 import java.awt.dnd.DnDConstants;
66 import java.awt.dnd.DropTargetDragEvent;
67 import java.awt.dnd.DropTargetDropEvent;
68 import java.awt.dnd.DropTargetEvent;
69 import java.awt.dnd.DropTargetListener;
70 import java.awt.event.ActionEvent;
71 import java.awt.event.ActionListener;
72 import java.awt.event.InputEvent;
73 import java.awt.event.KeyEvent;
74 import java.awt.event.MouseAdapter;
75 import java.awt.event.MouseEvent;
76 import java.awt.event.WindowAdapter;
77 import java.awt.event.WindowEvent;
78 import java.beans.PropertyChangeEvent;
79 import java.beans.PropertyChangeListener;
80 import java.io.BufferedInputStream;
82 import java.io.FileOutputStream;
83 import java.io.IOException;
85 import java.util.ArrayList;
86 import java.util.Hashtable;
87 import java.util.List;
88 import java.util.ListIterator;
89 import java.util.StringTokenizer;
90 import java.util.Vector;
91 import java.util.concurrent.ExecutorService;
92 import java.util.concurrent.Executors;
93 import java.util.concurrent.Semaphore;
95 import javax.swing.AbstractAction;
96 import javax.swing.Action;
97 import javax.swing.ActionMap;
98 import javax.swing.Box;
99 import javax.swing.BoxLayout;
100 import javax.swing.DefaultDesktopManager;
101 import javax.swing.DesktopManager;
102 import javax.swing.InputMap;
103 import javax.swing.JButton;
104 import javax.swing.JCheckBox;
105 import javax.swing.JComboBox;
106 import javax.swing.JComponent;
107 import javax.swing.JDesktopPane;
108 import javax.swing.JFileChooser;
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 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.setCallback(new Runnable()
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);
1165 int value = chooser.showOpenDialog(this);
1166 if (value == JFileChooser.APPROVE_OPTION)
1168 chooser.getCallback().run();
1180 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1182 // This construct allows us to have a wider textfield
1184 JLabel label = new JLabel(
1185 MessageManager.getString("label.input_file_url"));
1187 JComboBox history = new JComboBox();
1188 JPanel panel = new JPanel(new GridLayout(2, 1));
1191 history.setPreferredSize(new Dimension(400, 20));
1192 history.setEditable(true);
1193 history.addItem("http://www.");
1195 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1199 if (historyItems != null)
1201 st = new StringTokenizer(historyItems, "\t");
1203 while (st.hasMoreTokens())
1205 history.addItem(st.nextElement());
1209 // BH 2018 -- providing a callback for SwingJS
1210 // dialogOption is just a simple way to provide
1211 // context for the modal-like response.
1212 // The only requirement is that desktop implement
1213 // PropertyChangeListener, which is used already in Java
1214 // for changes in input value and such within the dialogs.
1216 String dialogOption = "label.input_alignment_from_url";
1217 desktop.dialogData = new Object[] { dialogOption, viewport, history };
1218 desktop.onDialogReturn(
1219 JvOptionPane.showInternalConfirmDialog(desktop, panel,
1220 MessageManager.getString(dialogOption),
1221 JvOptionPane.OK_CANCEL_OPTION));
1223 // no code may follow this, as SwingJS will not block
1224 // callback in JavaScript comes via a property change event,
1225 // thus going into desktop.onDialogReturn(int) just the same as
1232 * Opens the CutAndPaste window for the user to paste an alignment in to
1235 * - if not null, the pasted alignment is added to the current
1236 * alignment; if null, to a new alignment window
1239 public void inputTextboxMenuItem_actionPerformed(
1240 AlignmentViewPanel viewPanel)
1242 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1243 cap.setForInput(viewPanel);
1244 Desktop.addInternalFrame(cap,
1245 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1255 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1256 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1258 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1259 screen.height + "");
1260 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1261 getWidth(), getHeight()));
1263 if (jconsole != null)
1265 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1266 jconsole.stopConsole();
1270 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1273 if (dialogExecutor != null)
1275 dialogExecutor.shutdownNow();
1277 closeAll_actionPerformed(null);
1279 if (groovyConsole != null)
1281 // suppress a possible repeat prompt to save script
1282 groovyConsole.setDirty(false);
1283 groovyConsole.exit();
1288 private void storeLastKnownDimensions(String string, Rectangle jc)
1290 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1291 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1292 + " height:" + jc.height);
1294 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1295 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1296 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1297 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1307 public void aboutMenuItem_actionPerformed(ActionEvent e)
1309 // StringBuffer message = getAboutMessage(false);
1310 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1312 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1313 new Thread(new Runnable()
1318 new SplashScreen(true);
1323 public StringBuffer getAboutMessage(boolean shortv)
1325 StringBuffer message = new StringBuffer();
1326 message.append("<html>");
1329 message.append("<h1><strong>Version: "
1330 + jalview.bin.Cache.getProperty("VERSION")
1331 + "</strong></h1>");
1332 message.append("<strong>Last Updated: <em>"
1333 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1334 + "</em></strong>");
1340 message.append("<strong>Version "
1341 + jalview.bin.Cache.getProperty("VERSION")
1342 + "; last updated: "
1343 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1346 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1347 .equals("Checking"))
1349 message.append("<br>...Checking latest version...</br>");
1351 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1352 .equals(jalview.bin.Cache.getProperty("VERSION")))
1354 boolean red = false;
1355 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1356 .indexOf("automated build") == -1)
1359 // Displayed when code version and jnlp version do not match and code
1360 // version is not a development build
1361 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1364 message.append("<br>!! Version "
1365 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1367 + " is available for download from "
1368 + jalview.bin.Cache.getDefault("www.jalview.org",
1369 "http://www.jalview.org")
1373 message.append("</div>");
1376 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1378 "The Jalview Authors (See AUTHORS file for current list)")
1379 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1380 + "<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"
1381 + "<br><br>If you use Jalview, please cite:"
1382 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1383 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1384 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1396 public void documentationMenuItem_actionPerformed(ActionEvent e)
1400 Help.showHelpWindow();
1401 } catch (Exception ex)
1407 public void closeAll_actionPerformed(ActionEvent e)
1409 // TODO show a progress bar while closing?
1410 JInternalFrame[] frames = desktop.getAllFrames();
1411 for (int i = 0; i < frames.length; i++)
1415 frames[i].setClosed(true);
1416 } catch (java.beans.PropertyVetoException ex)
1420 Jalview.setCurrentAlignFrame(null);
1421 System.out.println("ALL CLOSED");
1422 if (v_client != null)
1424 // TODO clear binding to vamsas document objects on close_all
1428 * reset state of singleton objects as appropriate (clear down session state
1429 * when all windows are closed)
1431 StructureSelectionManager ssm = StructureSelectionManager
1432 .getStructureSelectionManager(this);
1440 public void raiseRelated_actionPerformed(ActionEvent e)
1442 reorderAssociatedWindows(false, false);
1446 public void minimizeAssociated_actionPerformed(ActionEvent e)
1448 reorderAssociatedWindows(true, false);
1451 void closeAssociatedWindows()
1453 reorderAssociatedWindows(false, true);
1459 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1463 protected void garbageCollect_actionPerformed(ActionEvent e)
1465 // We simply collect the garbage
1466 jalview.bin.Cache.log.debug("Collecting garbage...");
1468 jalview.bin.Cache.log.debug("Finished garbage collection.");
1475 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1479 protected void showMemusage_actionPerformed(ActionEvent e)
1481 desktop.showMemoryUsage(showMemusage.isSelected());
1488 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1492 protected void showConsole_actionPerformed(ActionEvent e)
1494 showConsole(showConsole.isSelected());
1497 Console jconsole = null;
1500 * control whether the java console is visible or not
1504 void showConsole(boolean selected)
1506 // TODO: decide if we should update properties file
1507 if (jconsole != null) // BH 2018
1509 showConsole.setSelected(selected);
1510 Cache.setProperty("SHOW_JAVA_CONSOLE",
1511 Boolean.valueOf(selected).toString());
1512 jconsole.setVisible(selected);
1516 void reorderAssociatedWindows(boolean minimize, boolean close)
1518 JInternalFrame[] frames = desktop.getAllFrames();
1519 if (frames == null || frames.length < 1)
1524 AlignmentViewport source = null, target = null;
1525 if (frames[0] instanceof AlignFrame)
1527 source = ((AlignFrame) frames[0]).getCurrentView();
1529 else if (frames[0] instanceof TreePanel)
1531 source = ((TreePanel) frames[0]).getViewPort();
1533 else if (frames[0] instanceof PCAPanel)
1535 source = ((PCAPanel) frames[0]).av;
1537 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1539 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1544 for (int i = 0; i < frames.length; i++)
1547 if (frames[i] == null)
1551 if (frames[i] instanceof AlignFrame)
1553 target = ((AlignFrame) frames[i]).getCurrentView();
1555 else if (frames[i] instanceof TreePanel)
1557 target = ((TreePanel) frames[i]).getViewPort();
1559 else if (frames[i] instanceof PCAPanel)
1561 target = ((PCAPanel) frames[i]).av;
1563 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1565 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1568 if (source == target)
1574 frames[i].setClosed(true);
1578 frames[i].setIcon(minimize);
1581 frames[i].toFront();
1585 } catch (java.beans.PropertyVetoException ex)
1600 protected void preferences_actionPerformed(ActionEvent e)
1612 public void saveState_actionPerformed(ActionEvent e)
1614 // TODO: JAL-3048 not needed for Jalview-JS
1616 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1619 chooser.setFileView(new JalviewFileView());
1620 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1622 int value = chooser.showSaveDialog(this);
1624 if (value == JalviewFileChooser.APPROVE_OPTION)
1626 final Desktop me = this;
1627 final java.io.File choice = chooser.getSelectedFile();
1628 setProjectFile(choice);
1630 new Thread(new Runnable()
1635 // TODO: refactor to Jalview desktop session controller action.
1636 setProgressBar(MessageManager.formatMessage(
1637 "label.saving_jalview_project", new Object[]
1638 { choice.getName() }), choice.hashCode());
1639 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1640 choice.getParent());
1641 // TODO catch and handle errors for savestate
1642 // TODO prevent user from messing with the Desktop whilst we're saving
1645 new Jalview2XML().saveState(choice);
1646 } catch (OutOfMemoryError oom)
1649 "Whilst saving current state to " + choice.getName(),
1651 } catch (Exception ex)
1654 "Problems whilst trying to save to " + choice.getName(),
1656 JvOptionPane.showMessageDialog(me,
1657 MessageManager.formatMessage(
1658 "label.error_whilst_saving_current_state_to",
1660 { choice.getName() }),
1661 MessageManager.getString("label.couldnt_save_project"),
1662 JvOptionPane.WARNING_MESSAGE);
1664 setProgressBar(null, choice.hashCode());
1670 private void setProjectFile(File choice)
1672 this.projectFile = choice;
1675 public File getProjectFile()
1677 return this.projectFile;
1687 public void loadState_actionPerformed(ActionEvent e)
1689 // TODO: JAL-3048 not needed for Jalview-JS
1691 JalviewFileChooser chooser = new JalviewFileChooser(
1692 Cache.getProperty("LAST_DIRECTORY"), new String[]
1695 { "Jalview Project", "Jalview Project (old)" },
1697 chooser.setFileView(new JalviewFileView());
1698 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1700 int value = chooser.showOpenDialog(this);
1702 if (value == JalviewFileChooser.APPROVE_OPTION)
1704 final File selectedFile = chooser.getSelectedFile();
1705 setProjectFile(selectedFile);
1706 final String choice = selectedFile.getAbsolutePath();
1707 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1708 new Thread(new Runnable()
1713 setProgressBar(MessageManager.formatMessage(
1714 "label.loading_jalview_project", new Object[]
1715 { choice }), choice.hashCode());
1718 new Jalview2XML().loadJalviewAlign(choice);
1719 } catch (OutOfMemoryError oom)
1721 new OOMWarning("Whilst loading project from " + choice, oom);
1722 } catch (Exception ex)
1725 "Problems whilst loading project from " + choice, ex);
1726 JvOptionPane.showMessageDialog(Desktop.desktop,
1727 MessageManager.formatMessage(
1728 "label.error_whilst_loading_project_from",
1731 MessageManager.getString("label.couldnt_load_project"),
1732 JvOptionPane.WARNING_MESSAGE);
1734 setProgressBar(null, choice.hashCode());
1741 public void inputSequence_actionPerformed(ActionEvent e)
1743 new SequenceFetcher(this);
1746 JPanel progressPanel;
1748 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1750 public void startLoading(final Object fileName)
1752 if (fileLoadingCount == 0)
1754 fileLoadingPanels.add(addProgressPanel(MessageManager
1755 .formatMessage("label.loading_file", new Object[]
1761 private JPanel addProgressPanel(String string)
1763 if (progressPanel == null)
1765 progressPanel = new JPanel(new GridLayout(1, 1));
1766 totalProgressCount = 0;
1767 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1769 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1770 JProgressBar progressBar = new JProgressBar();
1771 progressBar.setIndeterminate(true);
1773 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1775 thisprogress.add(progressBar, BorderLayout.CENTER);
1776 progressPanel.add(thisprogress);
1777 ((GridLayout) progressPanel.getLayout()).setRows(
1778 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1779 ++totalProgressCount;
1780 instance.validate();
1781 return thisprogress;
1784 int totalProgressCount = 0;
1786 private void removeProgressPanel(JPanel progbar)
1788 if (progressPanel != null)
1790 synchronized (progressPanel)
1792 progressPanel.remove(progbar);
1793 GridLayout gl = (GridLayout) progressPanel.getLayout();
1794 gl.setRows(gl.getRows() - 1);
1795 if (--totalProgressCount < 1)
1797 this.getContentPane().remove(progressPanel);
1798 progressPanel = null;
1805 public void stopLoading()
1808 if (fileLoadingCount < 1)
1810 while (fileLoadingPanels.size() > 0)
1812 removeProgressPanel(fileLoadingPanels.remove(0));
1814 fileLoadingPanels.clear();
1815 fileLoadingCount = 0;
1820 public static int getViewCount(String alignmentId)
1822 AlignmentViewport[] aps = getViewports(alignmentId);
1823 return (aps == null) ? 0 : aps.length;
1828 * @param alignmentId
1829 * - if null, all sets are returned
1830 * @return all AlignmentPanels concerning the alignmentId sequence set
1832 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1834 if (Desktop.desktop == null)
1836 // no frames created and in headless mode
1837 // TODO: verify that frames are recoverable when in headless mode
1840 List<AlignmentPanel> aps = new ArrayList<>();
1841 AlignFrame[] frames = getAlignFrames();
1846 for (AlignFrame af : frames)
1848 for (AlignmentPanel ap : af.alignPanels)
1850 if (alignmentId == null
1851 || alignmentId.equals(ap.av.getSequenceSetId()))
1857 if (aps.size() == 0)
1861 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1866 * get all the viewports on an alignment.
1868 * @param sequenceSetId
1869 * unique alignment id (may be null - all viewports returned in that
1871 * @return all viewports on the alignment bound to sequenceSetId
1873 public static AlignmentViewport[] getViewports(String sequenceSetId)
1875 List<AlignmentViewport> viewp = new ArrayList<>();
1876 if (desktop != null)
1878 AlignFrame[] frames = Desktop.getAlignFrames();
1880 for (AlignFrame afr : frames)
1882 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1883 .equals(sequenceSetId))
1885 if (afr.alignPanels != null)
1887 for (AlignmentPanel ap : afr.alignPanels)
1889 if (sequenceSetId == null
1890 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1898 viewp.add(afr.getViewport());
1902 if (viewp.size() > 0)
1904 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1911 * Explode the views in the given frame into separate AlignFrame
1915 public static void explodeViews(AlignFrame af)
1917 int size = af.alignPanels.size();
1923 for (int i = 0; i < size; i++)
1925 AlignmentPanel ap = af.alignPanels.get(i);
1926 AlignFrame newaf = new AlignFrame(ap);
1929 * Restore the view's last exploded frame geometry if known. Multiple
1930 * views from one exploded frame share and restore the same (frame)
1931 * position and size.
1933 Rectangle geometry = ap.av.getExplodedGeometry();
1934 if (geometry != null)
1936 newaf.setBounds(geometry);
1939 ap.av.setGatherViewsHere(false);
1941 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1942 AlignFrame.DEFAULT_HEIGHT);
1945 af.alignPanels.clear();
1946 af.closeMenuItem_actionPerformed(true);
1951 * Gather expanded views (separate AlignFrame's) with the same sequence set
1952 * identifier back in to this frame as additional views, and close the
1953 * expanded views. Note the expanded frames may themselves have multiple
1954 * views. We take the lot.
1958 public void gatherViews(AlignFrame source)
1960 source.viewport.setGatherViewsHere(true);
1961 source.viewport.setExplodedGeometry(source.getBounds());
1962 JInternalFrame[] frames = desktop.getAllFrames();
1963 String viewId = source.viewport.getSequenceSetId();
1965 for (int t = 0; t < frames.length; t++)
1967 if (frames[t] instanceof AlignFrame && frames[t] != source)
1969 AlignFrame af = (AlignFrame) frames[t];
1970 boolean gatherThis = false;
1971 for (int a = 0; a < af.alignPanels.size(); a++)
1973 AlignmentPanel ap = af.alignPanels.get(a);
1974 if (viewId.equals(ap.av.getSequenceSetId()))
1977 ap.av.setGatherViewsHere(false);
1978 ap.av.setExplodedGeometry(af.getBounds());
1979 source.addAlignmentPanel(ap, false);
1985 af.alignPanels.clear();
1986 af.closeMenuItem_actionPerformed(true);
1993 jalview.gui.VamsasApplication v_client = null;
1996 public void vamsasImport_actionPerformed(ActionEvent e)
1998 // TODO: JAL-3048 not needed for Jalview-JS
2000 if (v_client == null)
2002 // Load and try to start a session.
2003 JalviewFileChooser chooser = new JalviewFileChooser(
2004 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2006 chooser.setFileView(new JalviewFileView());
2007 chooser.setDialogTitle(
2008 MessageManager.getString("label.open_saved_vamsas_session"));
2009 chooser.setToolTipText(MessageManager.getString(
2010 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2012 int value = chooser.showOpenDialog(this);
2014 if (value == JalviewFileChooser.APPROVE_OPTION)
2016 String fle = chooser.getSelectedFile().toString();
2017 if (!vamsasImport(chooser.getSelectedFile()))
2019 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2020 MessageManager.formatMessage(
2021 "label.couldnt_import_as_vamsas_session",
2025 .getString("label.vamsas_document_import_failed"),
2026 JvOptionPane.ERROR_MESSAGE);
2032 jalview.bin.Cache.log.error(
2033 "Implementation error - load session from a running session is not supported.");
2038 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2041 * @return true if import was a success and a session was started.
2043 public boolean vamsasImport(URL url)
2045 // TODO: create progress bar
2046 if (v_client != null)
2049 jalview.bin.Cache.log.error(
2050 "Implementation error - load session from a running session is not supported.");
2056 // copy the URL content to a temporary local file
2057 // TODO: be a bit cleverer here with nio (?!)
2058 File file = File.createTempFile("vdocfromurl", ".vdj");
2059 FileOutputStream fos = new FileOutputStream(file);
2060 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2061 byte[] buffer = new byte[2048];
2063 while ((ln = bis.read(buffer)) > -1)
2065 fos.write(buffer, 0, ln);
2069 v_client = new jalview.gui.VamsasApplication(this, file,
2070 url.toExternalForm());
2071 } catch (Exception ex)
2073 jalview.bin.Cache.log.error(
2074 "Failed to create new vamsas session from contents of URL "
2079 setupVamsasConnectedGui();
2080 v_client.initial_update(); // TODO: thread ?
2081 return v_client.inSession();
2085 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2088 * @return true if import was a success and a session was started.
2090 public boolean vamsasImport(File file)
2092 if (v_client != null)
2095 jalview.bin.Cache.log.error(
2096 "Implementation error - load session from a running session is not supported.");
2100 setProgressBar(MessageManager.formatMessage(
2101 "status.importing_vamsas_session_from", new Object[]
2102 { file.getName() }), file.hashCode());
2105 v_client = new jalview.gui.VamsasApplication(this, file, null);
2106 } catch (Exception ex)
2108 setProgressBar(MessageManager.formatMessage(
2109 "status.importing_vamsas_session_from", new Object[]
2110 { file.getName() }), file.hashCode());
2111 jalview.bin.Cache.log.error(
2112 "New vamsas session from existing session file failed:", ex);
2115 setupVamsasConnectedGui();
2116 v_client.initial_update(); // TODO: thread ?
2117 setProgressBar(MessageManager.formatMessage(
2118 "status.importing_vamsas_session_from", new Object[]
2119 { file.getName() }), file.hashCode());
2120 return v_client.inSession();
2123 public boolean joinVamsasSession(String mysesid)
2125 if (v_client != null)
2127 throw new Error(MessageManager
2128 .getString("error.try_join_vamsas_session_another"));
2130 if (mysesid == null)
2133 MessageManager.getString("error.invalid_vamsas_session_id"));
2135 v_client = new VamsasApplication(this, mysesid);
2136 setupVamsasConnectedGui();
2137 v_client.initial_update();
2138 return (v_client.inSession());
2142 public void vamsasStart_actionPerformed(ActionEvent e)
2144 if (v_client == null)
2147 // we just start a default session for moment.
2149 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2150 * getProperty("LAST_DIRECTORY"));
2152 * chooser.setFileView(new JalviewFileView());
2153 * chooser.setDialogTitle("Load Vamsas file");
2154 * chooser.setToolTipText("Import");
2156 * int value = chooser.showOpenDialog(this);
2158 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2159 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2161 v_client = new VamsasApplication(this);
2162 setupVamsasConnectedGui();
2163 v_client.initial_update(); // TODO: thread ?
2167 // store current data in session.
2168 v_client.push_update(); // TODO: thread
2172 protected void setupVamsasConnectedGui()
2174 vamsasStart.setText(MessageManager.getString("label.session_update"));
2175 vamsasSave.setVisible(true);
2176 vamsasStop.setVisible(true);
2177 vamsasImport.setVisible(false); // Document import to existing session is
2178 // not possible for vamsas-client-1.0.
2181 protected void setupVamsasDisconnectedGui()
2183 vamsasSave.setVisible(false);
2184 vamsasStop.setVisible(false);
2185 vamsasImport.setVisible(true);
2187 .setText(MessageManager.getString("label.new_vamsas_session"));
2191 public void vamsasStop_actionPerformed(ActionEvent e)
2193 if (v_client != null)
2195 v_client.end_session();
2197 setupVamsasDisconnectedGui();
2201 protected void buildVamsasStMenu()
2203 if (v_client == null)
2205 String[] sess = null;
2208 sess = VamsasApplication.getSessionList();
2209 } catch (Exception e)
2211 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2217 jalview.bin.Cache.log.debug(
2218 "Got current sessions list: " + sess.length + " entries.");
2219 VamsasStMenu.removeAll();
2220 for (int i = 0; i < sess.length; i++)
2222 JMenuItem sessit = new JMenuItem();
2223 sessit.setText(sess[i]);
2224 sessit.setToolTipText(MessageManager
2225 .formatMessage("label.connect_to_session", new Object[]
2227 final Desktop dsktp = this;
2228 final String mysesid = sess[i];
2229 sessit.addActionListener(new ActionListener()
2233 public void actionPerformed(ActionEvent e)
2235 if (dsktp.v_client == null)
2237 Thread rthr = new Thread(new Runnable()
2243 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2244 dsktp.setupVamsasConnectedGui();
2245 dsktp.v_client.initial_update();
2253 VamsasStMenu.add(sessit);
2255 // don't show an empty menu.
2256 VamsasStMenu.setVisible(sess.length > 0);
2261 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2262 VamsasStMenu.removeAll();
2263 VamsasStMenu.setVisible(false);
2268 // Not interested in the content. Just hide ourselves.
2269 VamsasStMenu.setVisible(false);
2274 public void vamsasSave_actionPerformed(ActionEvent e)
2276 // TODO: JAL-3048 not needed for Jalview-JS
2278 if (v_client != null)
2280 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2281 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2284 chooser.setFileView(new JalviewFileView());
2285 chooser.setDialogTitle(MessageManager
2286 .getString("label.save_vamsas_document_archive"));
2288 int value = chooser.showSaveDialog(this);
2290 if (value == JalviewFileChooser.APPROVE_OPTION)
2292 java.io.File choice = chooser.getSelectedFile();
2293 JPanel progpanel = addProgressPanel(MessageManager
2294 .formatMessage("label.saving_vamsas_doc", new Object[]
2295 { choice.getName() }));
2296 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2297 String warnmsg = null;
2298 String warnttl = null;
2301 v_client.vclient.storeDocument(choice);
2304 warnttl = "Serious Problem saving Vamsas Document";
2305 warnmsg = ex.toString();
2306 jalview.bin.Cache.log
2307 .error("Error Whilst saving document to " + choice, ex);
2309 } catch (Exception ex)
2311 warnttl = "Problem saving Vamsas Document.";
2312 warnmsg = ex.toString();
2313 jalview.bin.Cache.log.warn(
2314 "Exception Whilst saving document to " + choice, ex);
2317 removeProgressPanel(progpanel);
2318 if (warnmsg != null)
2320 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2322 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2328 JPanel vamUpdate = null;
2331 * hide vamsas user gui bits when a vamsas document event is being handled.
2334 * true to hide gui, false to reveal gui
2336 public void setVamsasUpdate(boolean b)
2338 Cache.log.debug("Setting gui for Vamsas update "
2339 + (b ? "in progress" : "finished"));
2341 if (vamUpdate != null)
2343 this.removeProgressPanel(vamUpdate);
2347 vamUpdate = this.addProgressPanel(
2348 MessageManager.getString("label.updating_vamsas_session"));
2350 vamsasStart.setVisible(!b);
2351 vamsasStop.setVisible(!b);
2352 vamsasSave.setVisible(!b);
2355 public JInternalFrame[] getAllFrames()
2357 return desktop.getAllFrames();
2361 * Checks the given url to see if it gives a response indicating that the user
2362 * should be informed of a new questionnaire.
2366 public void checkForQuestionnaire(String url)
2368 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2369 // javax.swing.SwingUtilities.invokeLater(jvq);
2370 new Thread(jvq).start();
2373 public void checkURLLinks()
2375 // Thread off the URL link checker
2376 addDialogThread(new Runnable()
2381 if (/** @j2sNative false && */ // BH 2018
2382 Cache.getDefault("CHECKURLLINKS", true))
2384 // check what the actual links are - if it's just the default don't
2385 // bother with the warning
2386 List<String> links = Preferences.sequenceUrlLinks
2389 // only need to check links if there is one with a
2390 // SEQUENCE_ID which is not the default EMBL_EBI link
2391 ListIterator<String> li = links.listIterator();
2392 boolean check = false;
2393 List<JLabel> urls = new ArrayList<>();
2394 while (li.hasNext())
2396 String link = li.next();
2397 if (link.contains(SEQUENCE_ID)
2398 && !UrlConstants.isDefaultString(link))
2401 int barPos = link.indexOf("|");
2402 String urlMsg = barPos == -1 ? link
2403 : link.substring(0, barPos) + ": "
2404 + link.substring(barPos + 1);
2405 urls.add(new JLabel(urlMsg));
2413 // ask user to check in case URL links use old style tokens
2414 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2415 JPanel msgPanel = new JPanel();
2416 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2417 msgPanel.add(Box.createVerticalGlue());
2418 JLabel msg = new JLabel(MessageManager
2419 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2420 JLabel msg2 = new JLabel(MessageManager
2421 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2423 for (JLabel url : urls)
2429 final JCheckBox jcb = new JCheckBox(
2430 MessageManager.getString("label.do_not_display_again"));
2431 jcb.addActionListener(new ActionListener()
2434 public void actionPerformed(ActionEvent e)
2436 // update Cache settings for "don't show this again"
2437 boolean showWarningAgain = !jcb.isSelected();
2438 Cache.setProperty("CHECKURLLINKS",
2439 Boolean.valueOf(showWarningAgain).toString());
2444 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2446 .getString("label.SEQUENCE_ID_no_longer_used"),
2447 JvOptionPane.WARNING_MESSAGE);
2454 * Proxy class for JDesktopPane which optionally displays the current memory
2455 * usage and highlights the desktop area with a red bar if free memory runs
2460 public class MyDesktopPane extends JDesktopPane
2461 implements Runnable, PropertyChangeListener
2464 public Object[] dialogData;
2468 public void propertyChange(PropertyChangeEvent event)
2470 Object val = event.getNewValue();
2471 String name = event.getPropertyName();
2472 System.out.println(name);
2473 switch (event.getSource().getClass().getName())
2475 case "javax.swing.JOptionPane":
2479 onDialogReturn(val);
2482 if (val instanceof Integer)
2484 onDialogReturn(((Integer) val).intValue());
2488 onDialogReturn(val);
2493 case "javax.swing.ColorChooserDialog":
2496 case "SelectedColor":
2497 onDialogReturn(val);
2501 case "javax.swing.JFileChooser":
2504 case "SelectedFile":
2505 // in JavaScript, this File object will have a _bytes property,
2506 // because the file data has already been loaded
2507 onDialogReturn(new Object[] { (File) val });
2512 System.out.println(event.getSource().getClass().getName() + " "
2513 + event.getPropertyName() + ": " + event.getNewValue());
2516 // JSCOmponent.DialogCaller interface
2517 void onDialogReturn(Object value)
2519 switch ((String) dialogData[0])
2521 case "SelectedFile":
2523 dialogData[0] = value;
2524 ((Runnable) dialogData[1]).run();
2526 case "label.select_feature_colour":
2527 ((FeatureRenderer) dialogData[1]).processColorDialog((Color) value);
2532 // JSCOmponent.DialogCaller interface
2533 void onDialogReturn(int value)
2535 if (value != Math.floor(value))
2537 // in JavaScript, this will be NaN, oddly enough
2541 switch ((String) dialogData[0])
2544 dialogData[0] = Integer.valueOf(value);
2545 ((Runnable) dialogData[1]).run();
2547 case "label.input_alignment_from_url":
2548 // reconstruct the parameter data
2550 AlignViewport viewport = (AlignViewport) dialogData[1];
2551 JComboBox history = (JComboBox) dialogData[2];
2552 // the rest of this is unchangaed
2553 if (reply != JvOptionPane.OK_OPTION)
2558 String url = history.getSelectedItem().toString();
2560 if (url.toLowerCase().endsWith(".jar"))
2562 if (viewport != null)
2564 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2565 FileFormat.Jalview);
2569 new FileLoader().LoadFile(url, DataSourceType.URL,
2570 FileFormat.Jalview);
2575 FileFormatI format = null;
2578 format = new IdentifyFile().identify(url, DataSourceType.URL);
2579 } catch (FileFormatException e)
2581 // TODO revise error handling, distinguish between
2582 // URL not found and response not valid
2587 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2588 MessageManager.formatMessage("label.couldnt_locate",
2591 MessageManager.getString("label.url_not_found"),
2592 JvOptionPane.WARNING_MESSAGE);
2597 if (viewport != null)
2599 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2604 new FileLoader().LoadFile(url, DataSourceType.URL, format);
2613 private static final float ONE_MB = 1048576f;
2615 boolean showMemoryUsage = false;
2619 java.text.NumberFormat df;
2621 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2624 public MyDesktopPane(boolean showMemoryUsage)
2626 showMemoryUsage(showMemoryUsage);
2629 public void showMemoryUsage(boolean showMemory)
2631 this.showMemoryUsage = showMemory;
2634 Thread worker = new Thread(this);
2640 public boolean isShowMemoryUsage()
2642 return showMemoryUsage;
2648 df = java.text.NumberFormat.getNumberInstance();
2649 df.setMaximumFractionDigits(2);
2650 runtime = Runtime.getRuntime();
2652 while (showMemoryUsage)
2656 maxMemory = runtime.maxMemory() / ONE_MB;
2657 allocatedMemory = runtime.totalMemory() / ONE_MB;
2658 freeMemory = runtime.freeMemory() / ONE_MB;
2659 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2661 percentUsage = (totalFreeMemory / maxMemory) * 100;
2663 // if (percentUsage < 20)
2665 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2667 // instance.set.setBorder(border1);
2670 // sleep after showing usage
2672 } catch (Exception ex)
2674 ex.printStackTrace();
2680 public void paintComponent(Graphics g)
2682 if (showMemoryUsage && g != null && df != null)
2684 if (percentUsage < 20)
2686 g.setColor(Color.red);
2688 FontMetrics fm = g.getFontMetrics();
2691 g.drawString(MessageManager.formatMessage("label.memory_stats",
2693 { df.format(totalFreeMemory), df.format(maxMemory),
2694 df.format(percentUsage) }),
2695 10, getHeight() - fm.getHeight());
2703 * Accessor method to quickly get all the AlignmentFrames loaded.
2705 * @return an array of AlignFrame, or null if none found
2707 public static AlignFrame[] getAlignFrames()
2709 if (Jalview.isHeadlessMode())
2711 // Desktop.desktop is null in headless mode
2712 return new AlignFrame[] { Jalview.currentAlignFrame };
2715 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2721 List<AlignFrame> avp = new ArrayList<>();
2723 for (int i = frames.length - 1; i > -1; i--)
2725 if (frames[i] instanceof AlignFrame)
2727 avp.add((AlignFrame) frames[i]);
2729 else if (frames[i] instanceof SplitFrame)
2732 * Also check for a split frame containing an AlignFrame
2734 GSplitFrame sf = (GSplitFrame) frames[i];
2735 if (sf.getTopFrame() instanceof AlignFrame)
2737 avp.add((AlignFrame) sf.getTopFrame());
2739 if (sf.getBottomFrame() instanceof AlignFrame)
2741 avp.add((AlignFrame) sf.getBottomFrame());
2745 if (avp.size() == 0)
2749 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2754 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2758 public GStructureViewer[] getJmols()
2760 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2766 List<GStructureViewer> avp = new ArrayList<>();
2768 for (int i = frames.length - 1; i > -1; i--)
2770 if (frames[i] instanceof AppJmol)
2772 GStructureViewer af = (GStructureViewer) frames[i];
2776 if (avp.size() == 0)
2780 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2785 * Add Groovy Support to Jalview
2788 public void groovyShell_actionPerformed()
2792 openGroovyConsole();
2793 } catch (Exception ex)
2795 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2796 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2798 MessageManager.getString("label.couldnt_create_groovy_shell"),
2799 MessageManager.getString("label.groovy_support_failed"),
2800 JvOptionPane.ERROR_MESSAGE);
2805 * Open the Groovy console
2807 void openGroovyConsole()
2809 if (groovyConsole == null)
2811 groovyConsole = new groovy.ui.Console();
2812 groovyConsole.setVariable("Jalview", this);
2813 groovyConsole.run();
2816 * We allow only one console at a time, so that AlignFrame menu option
2817 * 'Calculate | Run Groovy script' is unambiguous.
2818 * Disable 'Groovy Console', and enable 'Run script', when the console is
2819 * opened, and the reverse when it is closed
2821 Window window = (Window) groovyConsole.getFrame();
2822 window.addWindowListener(new WindowAdapter()
2825 public void windowClosed(WindowEvent e)
2828 * rebind CMD-Q from Groovy Console to Jalview Quit
2831 enableExecuteGroovy(false);
2837 * show Groovy console window (after close and reopen)
2839 ((Window) groovyConsole.getFrame()).setVisible(true);
2842 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2843 * and disable opening a second console
2845 enableExecuteGroovy(true);
2849 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2850 * binding when opened
2852 protected void addQuitHandler()
2854 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2855 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2856 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2858 getRootPane().getActionMap().put("Quit", new AbstractAction()
2861 public void actionPerformed(ActionEvent e)
2869 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2872 * true if Groovy console is open
2874 public void enableExecuteGroovy(boolean enabled)
2877 * disable opening a second Groovy console
2878 * (or re-enable when the console is closed)
2880 groovyShell.setEnabled(!enabled);
2882 AlignFrame[] alignFrames = getAlignFrames();
2883 if (alignFrames != null)
2885 for (AlignFrame af : alignFrames)
2887 af.setGroovyEnabled(enabled);
2893 * Progress bars managed by the IProgressIndicator method.
2895 private Hashtable<Long, JPanel> progressBars;
2897 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2902 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2905 public void setProgressBar(String message, long id)
2907 if (progressBars == null)
2909 progressBars = new Hashtable<>();
2910 progressBarHandlers = new Hashtable<>();
2913 if (progressBars.get(new Long(id)) != null)
2915 JPanel panel = progressBars.remove(new Long(id));
2916 if (progressBarHandlers.contains(new Long(id)))
2918 progressBarHandlers.remove(new Long(id));
2920 removeProgressPanel(panel);
2924 progressBars.put(new Long(id), addProgressPanel(message));
2931 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2932 * jalview.gui.IProgressIndicatorHandler)
2935 public void registerHandler(final long id,
2936 final IProgressIndicatorHandler handler)
2938 if (progressBarHandlers == null
2939 || !progressBars.containsKey(new Long(id)))
2941 throw new Error(MessageManager.getString(
2942 "error.call_setprogressbar_before_registering_handler"));
2944 progressBarHandlers.put(new Long(id), handler);
2945 final JPanel progressPanel = progressBars.get(new Long(id));
2946 if (handler.canCancel())
2948 JButton cancel = new JButton(
2949 MessageManager.getString("action.cancel"));
2950 final IProgressIndicator us = this;
2951 cancel.addActionListener(new ActionListener()
2955 public void actionPerformed(ActionEvent e)
2957 handler.cancelActivity(id);
2958 us.setProgressBar(MessageManager
2959 .formatMessage("label.cancelled_params", new Object[]
2960 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2964 progressPanel.add(cancel, BorderLayout.EAST);
2970 * @return true if any progress bars are still active
2973 public boolean operationInProgress()
2975 if (progressBars != null && progressBars.size() > 0)
2983 * This will return the first AlignFrame holding the given viewport instance.
2984 * It will break if there are more than one AlignFrames viewing a particular
2988 * @return alignFrame for viewport
2990 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2992 if (desktop != null)
2994 AlignmentPanel[] aps = getAlignmentPanels(
2995 viewport.getSequenceSetId());
2996 for (int panel = 0; aps != null && panel < aps.length; panel++)
2998 if (aps[panel] != null && aps[panel].av == viewport)
3000 return aps[panel].alignFrame;
3007 public VamsasApplication getVamsasApplication()
3014 * flag set if jalview GUI is being operated programmatically
3016 private boolean inBatchMode = false;
3019 * check if jalview GUI is being operated programmatically
3021 * @return inBatchMode
3023 public boolean isInBatchMode()
3029 * set flag if jalview GUI is being operated programmatically
3031 * @param inBatchMode
3033 public void setInBatchMode(boolean inBatchMode)
3035 this.inBatchMode = inBatchMode;
3038 public void startServiceDiscovery()
3040 startServiceDiscovery(false);
3043 public void startServiceDiscovery(boolean blocking)
3045 boolean alive = true;
3046 Thread t0 = null, t1 = null, t2 = null;
3047 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3050 // todo: changesupport handlers need to be transferred
3051 if (discoverer == null)
3053 discoverer = new jalview.ws.jws1.Discoverer();
3054 // register PCS handler for desktop.
3055 discoverer.addPropertyChangeListener(changeSupport);
3057 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3058 // until we phase out completely
3059 (t0 = new Thread(discoverer)).start();
3062 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3064 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3065 .startDiscoverer(changeSupport);
3069 // TODO: do rest service discovery
3078 } catch (Exception e)
3081 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3082 || (t3 != null && t3.isAlive())
3083 || (t0 != null && t0.isAlive());
3089 * called to check if the service discovery process completed successfully.
3093 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3095 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3097 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3098 .getErrorMessages();
3101 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3103 if (serviceChangedDialog == null)
3105 // only run if we aren't already displaying one of these.
3106 addDialogThread(serviceChangedDialog = new Runnable()
3113 * JalviewDialog jd =new JalviewDialog() {
3115 * @Override protected void cancelPressed() { // TODO
3116 * Auto-generated method stub
3118 * }@Override protected void okPressed() { // TODO
3119 * Auto-generated method stub
3121 * }@Override protected void raiseClosed() { // TODO
3122 * Auto-generated method stub
3124 * } }; jd.initDialogFrame(new
3125 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3126 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3127 * + " or mis-configured HTTP proxy settings.<br/>" +
3128 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3130 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3131 * ), true, true, "Web Service Configuration Problem", 450,
3134 * jd.waitForInput();
3136 JvOptionPane.showConfirmDialog(Desktop.desktop,
3137 new JLabel("<html><table width=\"450\"><tr><td>"
3138 + ermsg + "</td></tr></table>"
3139 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3140 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3141 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3142 + " Tools->Preferences dialog box to change them.</p></html>"),
3143 "Web Service Configuration Problem",
3144 JvOptionPane.DEFAULT_OPTION,
3145 JvOptionPane.ERROR_MESSAGE);
3146 serviceChangedDialog = null;
3155 "Errors reported by JABA discovery service. Check web services preferences.\n"
3162 private Runnable serviceChangedDialog = null;
3165 * start a thread to open a URL in the configured browser. Pops up a warning
3166 * dialog to the user if there is an exception when calling out to the browser
3171 public static void showUrl(final String url)
3173 showUrl(url, Desktop.instance);
3177 * Like showUrl but allows progress handler to be specified
3181 * (null) or object implementing IProgressIndicator
3183 public static void showUrl(final String url,
3184 final IProgressIndicator progress)
3186 new Thread(new Runnable()
3193 if (progress != null)
3195 progress.setProgressBar(MessageManager
3196 .formatMessage("status.opening_params", new Object[]
3197 { url }), this.hashCode());
3199 jalview.util.BrowserLauncher.openURL(url);
3200 } catch (Exception ex)
3202 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3204 .getString("label.web_browser_not_found_unix"),
3205 MessageManager.getString("label.web_browser_not_found"),
3206 JvOptionPane.WARNING_MESSAGE);
3208 ex.printStackTrace();
3210 if (progress != null)
3212 progress.setProgressBar(null, this.hashCode());
3218 public static WsParamSetManager wsparamManager = null;
3220 public static ParamManager getUserParameterStore()
3222 if (wsparamManager == null)
3224 wsparamManager = new WsParamSetManager();
3226 return wsparamManager;
3230 * static hyperlink handler proxy method for use by Jalview's internal windows
3234 public static void hyperlinkUpdate(HyperlinkEvent e)
3236 if (e.getEventType() == EventType.ACTIVATED)
3241 url = e.getURL().toString();
3242 Desktop.showUrl(url);
3243 } catch (Exception x)
3247 if (Cache.log != null)
3249 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3254 "Couldn't handle string " + url + " as a URL.");
3257 // ignore any exceptions due to dud links.
3264 * single thread that handles display of dialogs to user.
3266 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3269 * flag indicating if dialogExecutor should try to acquire a permit
3271 private volatile boolean dialogPause = true;
3276 private java.util.concurrent.Semaphore block = new Semaphore(0);
3278 private static groovy.ui.Console groovyConsole;
3281 * add another dialog thread to the queue
3285 public void addDialogThread(final Runnable prompter)
3287 dialogExecutor.submit(new Runnable()
3297 } catch (InterruptedException x)
3302 if (instance == null)
3308 SwingUtilities.invokeAndWait(prompter);
3309 } catch (Exception q)
3311 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3317 public void startDialogQueue()
3319 // set the flag so we don't pause waiting for another permit and semaphore
3320 // the current task to begin
3321 dialogPause = false;
3326 protected void snapShotWindow_actionPerformed(ActionEvent e)
3330 ImageMaker im = new jalview.util.ImageMaker(
3331 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3332 getHeight(), of = new File("Jalview_snapshot"
3333 + System.currentTimeMillis() + ".eps"),
3334 "View of desktop", null, 0, false);
3337 paintAll(im.getGraphics());
3339 } catch (Exception q)
3341 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3345 Cache.log.info("Successfully written snapshot to file "
3346 + of.getAbsolutePath());
3350 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3351 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3352 * and location last time the view was expanded (if any). However it does not
3353 * remember the split pane divider location - this is set to match the
3354 * 'exploding' frame.
3358 public void explodeViews(SplitFrame sf)
3360 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3361 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3362 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3364 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3366 int viewCount = topPanels.size();
3373 * Processing in reverse order works, forwards order leaves the first panels
3374 * not visible. I don't know why!
3376 for (int i = viewCount - 1; i >= 0; i--)
3379 * Make new top and bottom frames. These take over the respective
3380 * AlignmentPanel objects, including their AlignmentViewports, so the
3381 * cdna/protein relationships between the viewports is carried over to the
3384 * explodedGeometry holds the (x, y) position of the previously exploded
3385 * SplitFrame, and the (width, height) of the AlignFrame component
3387 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3388 AlignFrame newTopFrame = new AlignFrame(topPanel);
3389 newTopFrame.setSize(oldTopFrame.getSize());
3390 newTopFrame.setVisible(true);
3391 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3392 .getExplodedGeometry();
3393 if (geometry != null)
3395 newTopFrame.setSize(geometry.getSize());
3398 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3399 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3400 newBottomFrame.setSize(oldBottomFrame.getSize());
3401 newBottomFrame.setVisible(true);
3402 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3403 .getExplodedGeometry();
3404 if (geometry != null)
3406 newBottomFrame.setSize(geometry.getSize());
3409 topPanel.av.setGatherViewsHere(false);
3410 bottomPanel.av.setGatherViewsHere(false);
3411 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3413 if (geometry != null)
3415 splitFrame.setLocation(geometry.getLocation());
3417 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3421 * Clear references to the panels (now relocated in the new SplitFrames)
3422 * before closing the old SplitFrame.
3425 bottomPanels.clear();
3430 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3431 * back into the given SplitFrame as additional views. Note that the gathered
3432 * frames may themselves have multiple views.
3436 public void gatherViews(GSplitFrame source)
3439 * special handling of explodedGeometry for a view within a SplitFrame: - it
3440 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3441 * height) of the AlignFrame component
3443 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3444 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3445 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3446 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3447 myBottomFrame.viewport
3448 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3449 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3450 myTopFrame.viewport.setGatherViewsHere(true);
3451 myBottomFrame.viewport.setGatherViewsHere(true);
3452 String topViewId = myTopFrame.viewport.getSequenceSetId();
3453 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3455 JInternalFrame[] frames = desktop.getAllFrames();
3456 for (JInternalFrame frame : frames)
3458 if (frame instanceof SplitFrame && frame != source)
3460 SplitFrame sf = (SplitFrame) frame;
3461 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3462 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3463 boolean gatherThis = false;
3464 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3466 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3467 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3468 if (topViewId.equals(topPanel.av.getSequenceSetId())
3469 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3472 topPanel.av.setGatherViewsHere(false);
3473 bottomPanel.av.setGatherViewsHere(false);
3474 topPanel.av.setExplodedGeometry(
3475 new Rectangle(sf.getLocation(), topFrame.getSize()));
3476 bottomPanel.av.setExplodedGeometry(
3477 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3478 myTopFrame.addAlignmentPanel(topPanel, false);
3479 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3485 topFrame.getAlignPanels().clear();
3486 bottomFrame.getAlignPanels().clear();
3493 * The dust settles...give focus to the tab we did this from.
3495 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3498 public static groovy.ui.Console getGroovyConsole()
3500 return groovyConsole;
3504 * handles the payload of a drag and drop event.
3506 * TODO refactor to desktop utilities class
3509 * - Data source strings extracted from the drop event
3511 * - protocol for each data source extracted from the drop event
3515 * - the payload from the drop event
3518 public static void transferFromDropTarget(List<Object> files,
3519 List<DataSourceType> protocols, DropTargetDropEvent evt,
3520 Transferable t) throws Exception
3523 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3525 // DataFlavor[] flavors = t.getTransferDataFlavors();
3526 // for (int i = 0; i < flavors.length; i++) {
3527 // if (flavors[i].isFlavorJavaFileListType()) {
3528 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3529 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3530 // for (int j = 0; j < list.size(); j++) {
3531 // File file = (File) list.get(j);
3532 // byte[] data = getDroppedFileBytes(file);
3533 // fileName.setText(file.getName() + " - " + data.length + " " + evt.getLocation());
3534 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3535 // target.setText(new String(data));
3537 // dtde.dropComplete(true);
3542 DataFlavor uriListFlavor = new DataFlavor(
3543 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3546 urlFlavour = new DataFlavor(
3547 "application/x-java-url; class=java.net.URL");
3548 } catch (ClassNotFoundException cfe)
3550 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3553 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3558 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3559 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3560 // means url may be null.
3563 protocols.add(DataSourceType.URL);
3564 files.add(url.toString());
3565 Cache.log.debug("Drop handled as URL dataflavor "
3566 + files.get(files.size() - 1));
3571 if (Platform.isAMac())
3574 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3578 } catch (Throwable ex)
3580 Cache.log.debug("URL drop handler failed.", ex);
3583 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3585 // Works on Windows and MacOSX
3586 Cache.log.debug("Drop handled as javaFileListFlavor");
3587 for (Object file : (List) t
3588 .getTransferData(DataFlavor.javaFileListFlavor))
3591 protocols.add(DataSourceType.FILE);
3596 // Unix like behaviour
3597 boolean added = false;
3599 if (t.isDataFlavorSupported(uriListFlavor))
3601 Cache.log.debug("Drop handled as uriListFlavor");
3602 // This is used by Unix drag system
3603 data = (String) t.getTransferData(uriListFlavor);
3607 // fallback to text: workaround - on OSX where there's a JVM bug
3608 Cache.log.debug("standard URIListFlavor failed. Trying text");
3609 // try text fallback
3610 DataFlavor textDf = new DataFlavor(
3611 "text/plain;class=java.lang.String");
3612 if (t.isDataFlavorSupported(textDf))
3614 data = (String) t.getTransferData(textDf);
3617 Cache.log.debug("Plain text drop content returned "
3618 + (data == null ? "Null - failed" : data));
3623 while (protocols.size() < files.size())
3625 Cache.log.debug("Adding missing FILE protocol for "
3626 + files.get(protocols.size()));
3627 protocols.add(DataSourceType.FILE);
3629 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3630 data, "\r\n"); st.hasMoreTokens();)
3633 String s = st.nextToken();
3634 if (s.startsWith("#"))
3636 // the line is a comment (as per the RFC 2483)
3639 java.net.URI uri = new java.net.URI(s);
3640 if (uri.getScheme().toLowerCase().startsWith("http"))
3642 protocols.add(DataSourceType.URL);
3643 files.add(uri.toString());
3647 // otherwise preserve old behaviour: catch all for file objects
3648 java.io.File file = new java.io.File(uri);
3649 protocols.add(DataSourceType.FILE);
3650 files.add(file.toString());
3655 if (Cache.log.isDebugEnabled())
3657 if (data == null || !added)
3660 if (t.getTransferDataFlavors() != null
3661 && t.getTransferDataFlavors().length > 0)
3664 "Couldn't resolve drop data. Here are the supported flavors:");
3665 for (DataFlavor fl : t.getTransferDataFlavors())
3668 "Supported transfer dataflavor: " + fl.toString());
3669 Object df = t.getTransferData(fl);
3672 Cache.log.debug("Retrieves: " + df);
3676 Cache.log.debug("Retrieved nothing");
3682 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3688 if (Platform.isWindows())
3691 Cache.log.debug("Scanning dropped content for Windows Link Files");
3693 // resolve any .lnk files in the file drop
3694 for (int f = 0; f < files.size(); f++)
3696 String source = files.get(f).toString().toLowerCase();
3697 if (protocols.get(f).equals(DataSourceType.FILE)
3698 && (source.endsWith(".lnk") || source.endsWith(".url")
3699 || source.endsWith(".site")))
3702 Object obj = files.get(f);
3703 File lf = (obj instanceof File ? (File) obj : new File((String) obj));
3704 // process link file to get a URL
3705 Cache.log.debug("Found potential link file: " + lf);
3706 WindowsShortcut wscfile = new WindowsShortcut(lf);
3707 String fullname = wscfile.getRealFilename();
3708 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3709 files.set(f, fullname);
3710 Cache.log.debug("Parsed real filename " + fullname
3711 + " to extract protocol: " + protocols.get(f));
3713 catch (Exception ex)
3715 Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
3723 * Sets the Preferences property for experimental features to True or False
3724 * depending on the state of the controlling menu item
3727 protected void showExperimental_actionPerformed(boolean selected)
3729 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3733 * Answers a (possibly empty) list of any structure viewer frames (currently
3734 * for either Jmol or Chimera) which are currently open. This may optionally
3735 * be restricted to viewers of a specified class, or viewers linked to a
3736 * specified alignment panel.
3739 * if not null, only return viewers linked to this panel
3740 * @param structureViewerClass
3741 * if not null, only return viewers of this class
3744 public List<StructureViewerBase> getStructureViewers(
3745 AlignmentPanel apanel,
3746 Class<? extends StructureViewerBase> structureViewerClass)
3748 List<StructureViewerBase> result = new ArrayList<>();
3749 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3751 for (JInternalFrame frame : frames)
3753 if (frame instanceof StructureViewerBase)
3755 if (structureViewerClass == null
3756 || structureViewerClass.isInstance(frame))
3759 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3761 result.add((StructureViewerBase) frame);