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 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
425 // Spawn a thread that shows the splashscreen
427 SwingUtilities.invokeLater(new Runnable()
436 // Thread off a new instance of the file chooser - this reduces the time it
437 // takes to open it later on.
438 new Thread(new Runnable()
443 Cache.log.debug("Filechooser init thread started.");
444 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
445 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
447 Cache.log.debug("Filechooser init thread finished.");
450 // Add the service change listener
451 changeSupport.addJalviewPropertyChangeListener("services",
452 new PropertyChangeListener()
456 public void propertyChange(PropertyChangeEvent evt)
458 Cache.log.debug("Firing service changed event for "
459 + evt.getNewValue());
460 JalviewServicesChanged(evt);
465 } // end BH 2018 ignore
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
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<String> 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 String file = files.get(i).toString();
1084 DataSourceType protocol = (protocols == null)
1085 ? DataSourceType.FILE
1087 FileFormatI format = null;
1089 if (file.endsWith(".jar"))
1091 format = FileFormat.Jalview;
1096 format = new IdentifyFile().identify(file, protocol);
1099 new FileLoader().LoadFile(file, protocol, format);
1102 } catch (Exception ex)
1107 evt.dropComplete(success); // need this to ensure input focus is properly
1108 // transfered to any new windows created
1118 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1120 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1121 final JalviewFileChooser chooser = JalviewFileChooser
1122 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1124 chooser.setFileView(new JalviewFileView());
1125 chooser.setDialogTitle(
1126 MessageManager.getString("label.open_local_file"));
1127 chooser.setToolTipText(MessageManager.getString("action.open"));
1129 chooser.setCallback(new Runnable()
1135 File selectedFile = chooser.getSelectedFile();
1136 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1138 FileFormatI format = chooser.getSelectedFormat();
1141 * Call IdentifyFile to verify the file contains what its extension implies.
1142 * Skip this step for dynamically added file formats, because
1143 * IdentifyFile does not know how to recognise them.
1145 if (FileFormats.getInstance().isIdentifiable(format))
1149 format = new IdentifyFile().identify(selectedFile,
1150 DataSourceType.FILE);
1151 } catch (FileFormatException e)
1153 // format = null; //??
1157 new FileLoader().LoadFile(viewport, selectedFile,
1158 DataSourceType.FILE, format);
1162 int value = chooser.showOpenDialog(this);
1163 if (value == JFileChooser.APPROVE_OPTION)
1165 chooser.getCallback().run();
1177 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1179 // This construct allows us to have a wider textfield
1181 JLabel label = new JLabel(
1182 MessageManager.getString("label.input_file_url"));
1184 JComboBox history = new JComboBox();
1185 JPanel panel = new JPanel(new GridLayout(2, 1));
1188 history.setPreferredSize(new Dimension(400, 20));
1189 history.setEditable(true);
1190 history.addItem("http://www.");
1192 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1196 if (historyItems != null)
1198 st = new StringTokenizer(historyItems, "\t");
1200 while (st.hasMoreTokens())
1202 history.addItem(st.nextElement());
1206 // BH 2018 -- providing a callback for SwingJS
1207 // dialogOption is just a simple way to provide
1208 // context for the modal-like response.
1209 // The only requirement is that desktop implement
1210 // PropertyChangeListener, which is used already in Java
1211 // for changes in input value and such within the dialogs.
1213 String dialogOption = "label.input_alignment_from_url";
1214 desktop.dialogData = new Object[] { dialogOption, viewport, history };
1215 desktop.onDialogReturn(
1216 JvOptionPane.showInternalConfirmDialog(desktop, panel,
1217 MessageManager.getString(dialogOption),
1218 JvOptionPane.OK_CANCEL_OPTION));
1220 // no code may follow this, as SwingJS will not block
1221 // callback in JavaScript comes via a property change event,
1222 // thus going into desktop.onDialogReturn(int) just the same as
1229 * Opens the CutAndPaste window for the user to paste an alignment in to
1232 * - if not null, the pasted alignment is added to the current
1233 * alignment; if null, to a new alignment window
1236 public void inputTextboxMenuItem_actionPerformed(
1237 AlignmentViewPanel viewPanel)
1239 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1240 cap.setForInput(viewPanel);
1241 Desktop.addInternalFrame(cap,
1242 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1252 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1253 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1255 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1256 screen.height + "");
1257 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1258 getWidth(), getHeight()));
1260 if (jconsole != null)
1262 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1263 jconsole.stopConsole();
1267 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1270 if (dialogExecutor != null)
1272 dialogExecutor.shutdownNow();
1274 closeAll_actionPerformed(null);
1276 if (groovyConsole != null)
1278 // suppress a possible repeat prompt to save script
1279 groovyConsole.setDirty(false);
1280 groovyConsole.exit();
1285 private void storeLastKnownDimensions(String string, Rectangle jc)
1287 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1288 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1289 + " height:" + jc.height);
1291 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1292 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1293 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1294 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1304 public void aboutMenuItem_actionPerformed(ActionEvent e)
1306 // StringBuffer message = getAboutMessage(false);
1307 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1309 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1310 new Thread(new Runnable()
1315 new SplashScreen(true);
1320 public StringBuffer getAboutMessage(boolean shortv)
1322 StringBuffer message = new StringBuffer();
1323 message.append("<html>");
1326 message.append("<h1><strong>Version: "
1327 + jalview.bin.Cache.getProperty("VERSION")
1328 + "</strong></h1>");
1329 message.append("<strong>Last Updated: <em>"
1330 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1331 + "</em></strong>");
1337 message.append("<strong>Version "
1338 + jalview.bin.Cache.getProperty("VERSION")
1339 + "; last updated: "
1340 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1343 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1344 .equals("Checking"))
1346 message.append("<br>...Checking latest version...</br>");
1348 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1349 .equals(jalview.bin.Cache.getProperty("VERSION")))
1351 boolean red = false;
1352 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1353 .indexOf("automated build") == -1)
1356 // Displayed when code version and jnlp version do not match and code
1357 // version is not a development build
1358 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1361 message.append("<br>!! Version "
1362 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1364 + " is available for download from "
1365 + jalview.bin.Cache.getDefault("www.jalview.org",
1366 "http://www.jalview.org")
1370 message.append("</div>");
1373 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1375 "The Jalview Authors (See AUTHORS file for current list)")
1376 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1377 + "<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"
1378 + "<br><br>If you use Jalview, please cite:"
1379 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1380 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1381 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1393 public void documentationMenuItem_actionPerformed(ActionEvent e)
1397 Help.showHelpWindow();
1398 } catch (Exception ex)
1404 public void closeAll_actionPerformed(ActionEvent e)
1406 // TODO show a progress bar while closing?
1407 JInternalFrame[] frames = desktop.getAllFrames();
1408 for (int i = 0; i < frames.length; i++)
1412 frames[i].setClosed(true);
1413 } catch (java.beans.PropertyVetoException ex)
1417 Jalview.setCurrentAlignFrame(null);
1418 System.out.println("ALL CLOSED");
1419 if (v_client != null)
1421 // TODO clear binding to vamsas document objects on close_all
1425 * reset state of singleton objects as appropriate (clear down session state
1426 * when all windows are closed)
1428 StructureSelectionManager ssm = StructureSelectionManager
1429 .getStructureSelectionManager(this);
1437 public void raiseRelated_actionPerformed(ActionEvent e)
1439 reorderAssociatedWindows(false, false);
1443 public void minimizeAssociated_actionPerformed(ActionEvent e)
1445 reorderAssociatedWindows(true, false);
1448 void closeAssociatedWindows()
1450 reorderAssociatedWindows(false, true);
1456 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1460 protected void garbageCollect_actionPerformed(ActionEvent e)
1462 // We simply collect the garbage
1463 jalview.bin.Cache.log.debug("Collecting garbage...");
1465 jalview.bin.Cache.log.debug("Finished garbage collection.");
1472 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1476 protected void showMemusage_actionPerformed(ActionEvent e)
1478 desktop.showMemoryUsage(showMemusage.isSelected());
1485 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1489 protected void showConsole_actionPerformed(ActionEvent e)
1491 showConsole(showConsole.isSelected());
1494 Console jconsole = null;
1497 * control whether the java console is visible or not
1501 void showConsole(boolean selected)
1503 // TODO: decide if we should update properties file
1504 if (jconsole != null) // BH 2018
1506 showConsole.setSelected(selected);
1507 Cache.setProperty("SHOW_JAVA_CONSOLE",
1508 Boolean.valueOf(selected).toString());
1509 jconsole.setVisible(selected);
1513 void reorderAssociatedWindows(boolean minimize, boolean close)
1515 JInternalFrame[] frames = desktop.getAllFrames();
1516 if (frames == null || frames.length < 1)
1521 AlignmentViewport source = null, target = null;
1522 if (frames[0] instanceof AlignFrame)
1524 source = ((AlignFrame) frames[0]).getCurrentView();
1526 else if (frames[0] instanceof TreePanel)
1528 source = ((TreePanel) frames[0]).getViewPort();
1530 else if (frames[0] instanceof PCAPanel)
1532 source = ((PCAPanel) frames[0]).av;
1534 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1536 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1541 for (int i = 0; i < frames.length; i++)
1544 if (frames[i] == null)
1548 if (frames[i] instanceof AlignFrame)
1550 target = ((AlignFrame) frames[i]).getCurrentView();
1552 else if (frames[i] instanceof TreePanel)
1554 target = ((TreePanel) frames[i]).getViewPort();
1556 else if (frames[i] instanceof PCAPanel)
1558 target = ((PCAPanel) frames[i]).av;
1560 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1562 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1565 if (source == target)
1571 frames[i].setClosed(true);
1575 frames[i].setIcon(minimize);
1578 frames[i].toFront();
1582 } catch (java.beans.PropertyVetoException ex)
1597 protected void preferences_actionPerformed(ActionEvent e)
1609 public void saveState_actionPerformed(ActionEvent e)
1611 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1614 chooser.setFileView(new JalviewFileView());
1615 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1617 int value = chooser.showSaveDialog(this);
1619 if (value == JalviewFileChooser.APPROVE_OPTION)
1621 final Desktop me = this;
1622 final java.io.File choice = chooser.getSelectedFile();
1623 setProjectFile(choice);
1625 new Thread(new Runnable()
1630 // TODO: refactor to Jalview desktop session controller action.
1631 setProgressBar(MessageManager.formatMessage(
1632 "label.saving_jalview_project", new Object[]
1633 { choice.getName() }), choice.hashCode());
1634 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1635 choice.getParent());
1636 // TODO catch and handle errors for savestate
1637 // TODO prevent user from messing with the Desktop whilst we're saving
1640 new Jalview2XML().saveState(choice);
1641 } catch (OutOfMemoryError oom)
1644 "Whilst saving current state to " + choice.getName(),
1646 } catch (Exception ex)
1649 "Problems whilst trying to save to " + choice.getName(),
1651 JvOptionPane.showMessageDialog(me,
1652 MessageManager.formatMessage(
1653 "label.error_whilst_saving_current_state_to",
1655 { choice.getName() }),
1656 MessageManager.getString("label.couldnt_save_project"),
1657 JvOptionPane.WARNING_MESSAGE);
1659 setProgressBar(null, choice.hashCode());
1665 private void setProjectFile(File choice)
1667 this.projectFile = choice;
1670 public File getProjectFile()
1672 return this.projectFile;
1682 public void loadState_actionPerformed(ActionEvent e)
1684 JalviewFileChooser chooser = new JalviewFileChooser(
1685 Cache.getProperty("LAST_DIRECTORY"), new String[]
1688 { "Jalview Project", "Jalview Project (old)" },
1690 chooser.setFileView(new JalviewFileView());
1691 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1693 int value = chooser.showOpenDialog(this);
1695 if (value == JalviewFileChooser.APPROVE_OPTION)
1697 final File selectedFile = chooser.getSelectedFile();
1698 setProjectFile(selectedFile);
1699 final String choice = selectedFile.getAbsolutePath();
1700 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1701 new Thread(new Runnable()
1706 setProgressBar(MessageManager.formatMessage(
1707 "label.loading_jalview_project", new Object[]
1708 { choice }), choice.hashCode());
1711 new Jalview2XML().loadJalviewAlign(choice);
1712 } catch (OutOfMemoryError oom)
1714 new OOMWarning("Whilst loading project from " + choice, oom);
1715 } catch (Exception ex)
1718 "Problems whilst loading project from " + choice, ex);
1719 JvOptionPane.showMessageDialog(Desktop.desktop,
1720 MessageManager.formatMessage(
1721 "label.error_whilst_loading_project_from",
1724 MessageManager.getString("label.couldnt_load_project"),
1725 JvOptionPane.WARNING_MESSAGE);
1727 setProgressBar(null, choice.hashCode());
1734 public void inputSequence_actionPerformed(ActionEvent e)
1736 new SequenceFetcher(this);
1739 JPanel progressPanel;
1741 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1743 public void startLoading(final String fileName)
1745 if (fileLoadingCount == 0)
1747 fileLoadingPanels.add(addProgressPanel(MessageManager
1748 .formatMessage("label.loading_file", new Object[]
1754 private JPanel addProgressPanel(String string)
1756 if (progressPanel == null)
1758 progressPanel = new JPanel(new GridLayout(1, 1));
1759 totalProgressCount = 0;
1760 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1762 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1763 JProgressBar progressBar = new JProgressBar();
1764 progressBar.setIndeterminate(true);
1766 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1768 thisprogress.add(progressBar, BorderLayout.CENTER);
1769 progressPanel.add(thisprogress);
1770 ((GridLayout) progressPanel.getLayout()).setRows(
1771 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1772 ++totalProgressCount;
1773 instance.validate();
1774 return thisprogress;
1777 int totalProgressCount = 0;
1779 private void removeProgressPanel(JPanel progbar)
1781 if (progressPanel != null)
1783 synchronized (progressPanel)
1785 progressPanel.remove(progbar);
1786 GridLayout gl = (GridLayout) progressPanel.getLayout();
1787 gl.setRows(gl.getRows() - 1);
1788 if (--totalProgressCount < 1)
1790 this.getContentPane().remove(progressPanel);
1791 progressPanel = null;
1798 public void stopLoading()
1801 if (fileLoadingCount < 1)
1803 while (fileLoadingPanels.size() > 0)
1805 removeProgressPanel(fileLoadingPanels.remove(0));
1807 fileLoadingPanels.clear();
1808 fileLoadingCount = 0;
1813 public static int getViewCount(String alignmentId)
1815 AlignmentViewport[] aps = getViewports(alignmentId);
1816 return (aps == null) ? 0 : aps.length;
1821 * @param alignmentId
1822 * - if null, all sets are returned
1823 * @return all AlignmentPanels concerning the alignmentId sequence set
1825 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1827 if (Desktop.desktop == null)
1829 // no frames created and in headless mode
1830 // TODO: verify that frames are recoverable when in headless mode
1833 List<AlignmentPanel> aps = new ArrayList<>();
1834 AlignFrame[] frames = getAlignFrames();
1839 for (AlignFrame af : frames)
1841 for (AlignmentPanel ap : af.alignPanels)
1843 if (alignmentId == null
1844 || alignmentId.equals(ap.av.getSequenceSetId()))
1850 if (aps.size() == 0)
1854 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1859 * get all the viewports on an alignment.
1861 * @param sequenceSetId
1862 * unique alignment id (may be null - all viewports returned in that
1864 * @return all viewports on the alignment bound to sequenceSetId
1866 public static AlignmentViewport[] getViewports(String sequenceSetId)
1868 List<AlignmentViewport> viewp = new ArrayList<>();
1869 if (desktop != null)
1871 AlignFrame[] frames = Desktop.getAlignFrames();
1873 for (AlignFrame afr : frames)
1875 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1876 .equals(sequenceSetId))
1878 if (afr.alignPanels != null)
1880 for (AlignmentPanel ap : afr.alignPanels)
1882 if (sequenceSetId == null
1883 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1891 viewp.add(afr.getViewport());
1895 if (viewp.size() > 0)
1897 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1904 * Explode the views in the given frame into separate AlignFrame
1908 public static void explodeViews(AlignFrame af)
1910 int size = af.alignPanels.size();
1916 for (int i = 0; i < size; i++)
1918 AlignmentPanel ap = af.alignPanels.get(i);
1919 AlignFrame newaf = new AlignFrame(ap);
1922 * Restore the view's last exploded frame geometry if known. Multiple
1923 * views from one exploded frame share and restore the same (frame)
1924 * position and size.
1926 Rectangle geometry = ap.av.getExplodedGeometry();
1927 if (geometry != null)
1929 newaf.setBounds(geometry);
1932 ap.av.setGatherViewsHere(false);
1934 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1935 AlignFrame.DEFAULT_HEIGHT);
1938 af.alignPanels.clear();
1939 af.closeMenuItem_actionPerformed(true);
1944 * Gather expanded views (separate AlignFrame's) with the same sequence set
1945 * identifier back in to this frame as additional views, and close the
1946 * expanded views. Note the expanded frames may themselves have multiple
1947 * views. We take the lot.
1951 public void gatherViews(AlignFrame source)
1953 source.viewport.setGatherViewsHere(true);
1954 source.viewport.setExplodedGeometry(source.getBounds());
1955 JInternalFrame[] frames = desktop.getAllFrames();
1956 String viewId = source.viewport.getSequenceSetId();
1958 for (int t = 0; t < frames.length; t++)
1960 if (frames[t] instanceof AlignFrame && frames[t] != source)
1962 AlignFrame af = (AlignFrame) frames[t];
1963 boolean gatherThis = false;
1964 for (int a = 0; a < af.alignPanels.size(); a++)
1966 AlignmentPanel ap = af.alignPanels.get(a);
1967 if (viewId.equals(ap.av.getSequenceSetId()))
1970 ap.av.setGatherViewsHere(false);
1971 ap.av.setExplodedGeometry(af.getBounds());
1972 source.addAlignmentPanel(ap, false);
1978 af.alignPanels.clear();
1979 af.closeMenuItem_actionPerformed(true);
1986 jalview.gui.VamsasApplication v_client = null;
1989 public void vamsasImport_actionPerformed(ActionEvent e)
1991 if (v_client == null)
1993 // Load and try to start a session.
1994 JalviewFileChooser chooser = new JalviewFileChooser(
1995 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
1997 chooser.setFileView(new JalviewFileView());
1998 chooser.setDialogTitle(
1999 MessageManager.getString("label.open_saved_vamsas_session"));
2000 chooser.setToolTipText(MessageManager.getString(
2001 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2003 int value = chooser.showOpenDialog(this);
2005 if (value == JalviewFileChooser.APPROVE_OPTION)
2007 String fle = chooser.getSelectedFile().toString();
2008 if (!vamsasImport(chooser.getSelectedFile()))
2010 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2011 MessageManager.formatMessage(
2012 "label.couldnt_import_as_vamsas_session",
2016 .getString("label.vamsas_document_import_failed"),
2017 JvOptionPane.ERROR_MESSAGE);
2023 jalview.bin.Cache.log.error(
2024 "Implementation error - load session from a running session is not supported.");
2029 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2032 * @return true if import was a success and a session was started.
2034 public boolean vamsasImport(URL url)
2036 // TODO: create progress bar
2037 if (v_client != null)
2040 jalview.bin.Cache.log.error(
2041 "Implementation error - load session from a running session is not supported.");
2047 // copy the URL content to a temporary local file
2048 // TODO: be a bit cleverer here with nio (?!)
2049 File file = File.createTempFile("vdocfromurl", ".vdj");
2050 FileOutputStream fos = new FileOutputStream(file);
2051 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2052 byte[] buffer = new byte[2048];
2054 while ((ln = bis.read(buffer)) > -1)
2056 fos.write(buffer, 0, ln);
2060 v_client = new jalview.gui.VamsasApplication(this, file,
2061 url.toExternalForm());
2062 } catch (Exception ex)
2064 jalview.bin.Cache.log.error(
2065 "Failed to create new vamsas session from contents of URL "
2070 setupVamsasConnectedGui();
2071 v_client.initial_update(); // TODO: thread ?
2072 return v_client.inSession();
2076 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2079 * @return true if import was a success and a session was started.
2081 public boolean vamsasImport(File file)
2083 if (v_client != null)
2086 jalview.bin.Cache.log.error(
2087 "Implementation error - load session from a running session is not supported.");
2091 setProgressBar(MessageManager.formatMessage(
2092 "status.importing_vamsas_session_from", new Object[]
2093 { file.getName() }), file.hashCode());
2096 v_client = new jalview.gui.VamsasApplication(this, file, null);
2097 } catch (Exception ex)
2099 setProgressBar(MessageManager.formatMessage(
2100 "status.importing_vamsas_session_from", new Object[]
2101 { file.getName() }), file.hashCode());
2102 jalview.bin.Cache.log.error(
2103 "New vamsas session from existing session file failed:", ex);
2106 setupVamsasConnectedGui();
2107 v_client.initial_update(); // TODO: thread ?
2108 setProgressBar(MessageManager.formatMessage(
2109 "status.importing_vamsas_session_from", new Object[]
2110 { file.getName() }), file.hashCode());
2111 return v_client.inSession();
2114 public boolean joinVamsasSession(String mysesid)
2116 if (v_client != null)
2118 throw new Error(MessageManager
2119 .getString("error.try_join_vamsas_session_another"));
2121 if (mysesid == null)
2124 MessageManager.getString("error.invalid_vamsas_session_id"));
2126 v_client = new VamsasApplication(this, mysesid);
2127 setupVamsasConnectedGui();
2128 v_client.initial_update();
2129 return (v_client.inSession());
2133 public void vamsasStart_actionPerformed(ActionEvent e)
2135 if (v_client == null)
2138 // we just start a default session for moment.
2140 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2141 * getProperty("LAST_DIRECTORY"));
2143 * chooser.setFileView(new JalviewFileView());
2144 * chooser.setDialogTitle("Load Vamsas file");
2145 * chooser.setToolTipText("Import");
2147 * int value = chooser.showOpenDialog(this);
2149 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2150 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2152 v_client = new VamsasApplication(this);
2153 setupVamsasConnectedGui();
2154 v_client.initial_update(); // TODO: thread ?
2158 // store current data in session.
2159 v_client.push_update(); // TODO: thread
2163 protected void setupVamsasConnectedGui()
2165 vamsasStart.setText(MessageManager.getString("label.session_update"));
2166 vamsasSave.setVisible(true);
2167 vamsasStop.setVisible(true);
2168 vamsasImport.setVisible(false); // Document import to existing session is
2169 // not possible for vamsas-client-1.0.
2172 protected void setupVamsasDisconnectedGui()
2174 vamsasSave.setVisible(false);
2175 vamsasStop.setVisible(false);
2176 vamsasImport.setVisible(true);
2178 .setText(MessageManager.getString("label.new_vamsas_session"));
2182 public void vamsasStop_actionPerformed(ActionEvent e)
2184 if (v_client != null)
2186 v_client.end_session();
2188 setupVamsasDisconnectedGui();
2192 protected void buildVamsasStMenu()
2194 if (v_client == null)
2196 String[] sess = null;
2199 sess = VamsasApplication.getSessionList();
2200 } catch (Exception e)
2202 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2208 jalview.bin.Cache.log.debug(
2209 "Got current sessions list: " + sess.length + " entries.");
2210 VamsasStMenu.removeAll();
2211 for (int i = 0; i < sess.length; i++)
2213 JMenuItem sessit = new JMenuItem();
2214 sessit.setText(sess[i]);
2215 sessit.setToolTipText(MessageManager
2216 .formatMessage("label.connect_to_session", new Object[]
2218 final Desktop dsktp = this;
2219 final String mysesid = sess[i];
2220 sessit.addActionListener(new ActionListener()
2224 public void actionPerformed(ActionEvent e)
2226 if (dsktp.v_client == null)
2228 Thread rthr = new Thread(new Runnable()
2234 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2235 dsktp.setupVamsasConnectedGui();
2236 dsktp.v_client.initial_update();
2244 VamsasStMenu.add(sessit);
2246 // don't show an empty menu.
2247 VamsasStMenu.setVisible(sess.length > 0);
2252 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2253 VamsasStMenu.removeAll();
2254 VamsasStMenu.setVisible(false);
2259 // Not interested in the content. Just hide ourselves.
2260 VamsasStMenu.setVisible(false);
2265 public void vamsasSave_actionPerformed(ActionEvent e)
2267 if (v_client != null)
2269 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2270 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2273 chooser.setFileView(new JalviewFileView());
2274 chooser.setDialogTitle(MessageManager
2275 .getString("label.save_vamsas_document_archive"));
2277 int value = chooser.showSaveDialog(this);
2279 if (value == JalviewFileChooser.APPROVE_OPTION)
2281 java.io.File choice = chooser.getSelectedFile();
2282 JPanel progpanel = addProgressPanel(MessageManager
2283 .formatMessage("label.saving_vamsas_doc", new Object[]
2284 { choice.getName() }));
2285 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2286 String warnmsg = null;
2287 String warnttl = null;
2290 v_client.vclient.storeDocument(choice);
2293 warnttl = "Serious Problem saving Vamsas Document";
2294 warnmsg = ex.toString();
2295 jalview.bin.Cache.log
2296 .error("Error Whilst saving document to " + choice, ex);
2298 } catch (Exception ex)
2300 warnttl = "Problem saving Vamsas Document.";
2301 warnmsg = ex.toString();
2302 jalview.bin.Cache.log.warn(
2303 "Exception Whilst saving document to " + choice, ex);
2306 removeProgressPanel(progpanel);
2307 if (warnmsg != null)
2309 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2311 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2317 JPanel vamUpdate = null;
2320 * hide vamsas user gui bits when a vamsas document event is being handled.
2323 * true to hide gui, false to reveal gui
2325 public void setVamsasUpdate(boolean b)
2327 Cache.log.debug("Setting gui for Vamsas update "
2328 + (b ? "in progress" : "finished"));
2330 if (vamUpdate != null)
2332 this.removeProgressPanel(vamUpdate);
2336 vamUpdate = this.addProgressPanel(
2337 MessageManager.getString("label.updating_vamsas_session"));
2339 vamsasStart.setVisible(!b);
2340 vamsasStop.setVisible(!b);
2341 vamsasSave.setVisible(!b);
2344 public JInternalFrame[] getAllFrames()
2346 return desktop.getAllFrames();
2350 * Checks the given url to see if it gives a response indicating that the user
2351 * should be informed of a new questionnaire.
2355 public void checkForQuestionnaire(String url)
2357 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2358 // javax.swing.SwingUtilities.invokeLater(jvq);
2359 new Thread(jvq).start();
2362 public void checkURLLinks()
2364 // Thread off the URL link checker
2365 addDialogThread(new Runnable()
2370 if (/** @j2sNative false && */ // BH 2018
2371 Cache.getDefault("CHECKURLLINKS", true))
2373 // check what the actual links are - if it's just the default don't
2374 // bother with the warning
2375 List<String> links = Preferences.sequenceUrlLinks
2378 // only need to check links if there is one with a
2379 // SEQUENCE_ID which is not the default EMBL_EBI link
2380 ListIterator<String> li = links.listIterator();
2381 boolean check = false;
2382 List<JLabel> urls = new ArrayList<>();
2383 while (li.hasNext())
2385 String link = li.next();
2386 if (link.contains(SEQUENCE_ID)
2387 && !UrlConstants.isDefaultString(link))
2390 int barPos = link.indexOf("|");
2391 String urlMsg = barPos == -1 ? link
2392 : link.substring(0, barPos) + ": "
2393 + link.substring(barPos + 1);
2394 urls.add(new JLabel(urlMsg));
2402 // ask user to check in case URL links use old style tokens
2403 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2404 JPanel msgPanel = new JPanel();
2405 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2406 msgPanel.add(Box.createVerticalGlue());
2407 JLabel msg = new JLabel(MessageManager
2408 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2409 JLabel msg2 = new JLabel(MessageManager
2410 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2412 for (JLabel url : urls)
2418 final JCheckBox jcb = new JCheckBox(
2419 MessageManager.getString("label.do_not_display_again"));
2420 jcb.addActionListener(new ActionListener()
2423 public void actionPerformed(ActionEvent e)
2425 // update Cache settings for "don't show this again"
2426 boolean showWarningAgain = !jcb.isSelected();
2427 Cache.setProperty("CHECKURLLINKS",
2428 Boolean.valueOf(showWarningAgain).toString());
2433 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2435 .getString("label.SEQUENCE_ID_no_longer_used"),
2436 JvOptionPane.WARNING_MESSAGE);
2443 * Proxy class for JDesktopPane which optionally displays the current memory
2444 * usage and highlights the desktop area with a red bar if free memory runs
2449 public class MyDesktopPane extends JDesktopPane
2450 implements Runnable, PropertyChangeListener
2453 public Object[] dialogData;
2457 public void propertyChange(PropertyChangeEvent event)
2459 Object val = event.getNewValue();
2460 String name = event.getPropertyName();
2461 System.out.println(name);
2462 switch (event.getSource().getClass().getName())
2464 case "javax.swing.JOptionPane":
2468 onDialogReturn(val);
2471 if (val instanceof Integer)
2473 onDialogReturn(((Integer) val).intValue());
2477 onDialogReturn(val);
2482 case "javax.swing.ColorChooserDialog":
2485 case "SelectedColor":
2486 onDialogReturn(val);
2490 case "javax.swing.JFileChooser":
2493 case "SelectedFile":
2494 // in JavaScript, this File object will have a _bytes property,
2495 // because the file data has already been loaded
2496 onDialogReturn(new Object[] { (File) val });
2501 System.out.println(event.getSource().getClass().getName() + " "
2502 + event.getPropertyName() + ": " + event.getNewValue());
2505 // JSCOmponent.DialogCaller interface
2506 void onDialogReturn(Object value)
2508 switch ((String) dialogData[0])
2510 case "SelectedFile":
2512 dialogData[0] = value;
2513 ((Runnable) dialogData[1]).run();
2515 case "label.select_feature_colour":
2516 ((FeatureRenderer) dialogData[1]).processColorDialog((Color) value);
2521 // JSCOmponent.DialogCaller interface
2522 void onDialogReturn(int value)
2524 if (value != Math.floor(value))
2526 // in JavaScript, this will be NaN, oddly enough
2530 switch ((String) dialogData[0])
2533 dialogData[0] = Integer.valueOf(value);
2534 ((Runnable) dialogData[1]).run();
2536 case "label.input_alignment_from_url":
2537 // reconstruct the parameter data
2539 AlignViewport viewport = (AlignViewport) dialogData[1];
2540 JComboBox history = (JComboBox) dialogData[2];
2541 // the rest of this is unchangaed
2542 if (reply != JvOptionPane.OK_OPTION)
2547 String url = history.getSelectedItem().toString();
2549 if (url.toLowerCase().endsWith(".jar"))
2551 if (viewport != null)
2553 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2554 FileFormat.Jalview);
2558 new FileLoader().LoadFile(url, DataSourceType.URL,
2559 FileFormat.Jalview);
2564 FileFormatI format = null;
2567 format = new IdentifyFile().identify(url, DataSourceType.URL);
2568 } catch (FileFormatException e)
2570 // TODO revise error handling, distinguish between
2571 // URL not found and response not valid
2576 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2577 MessageManager.formatMessage("label.couldnt_locate",
2580 MessageManager.getString("label.url_not_found"),
2581 JvOptionPane.WARNING_MESSAGE);
2586 if (viewport != null)
2588 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2593 new FileLoader().LoadFile(url, DataSourceType.URL, format);
2602 private static final float ONE_MB = 1048576f;
2604 boolean showMemoryUsage = false;
2608 java.text.NumberFormat df;
2610 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2613 public MyDesktopPane(boolean showMemoryUsage)
2615 showMemoryUsage(showMemoryUsage);
2618 public void showMemoryUsage(boolean showMemory)
2620 this.showMemoryUsage = showMemory;
2623 Thread worker = new Thread(this);
2629 public boolean isShowMemoryUsage()
2631 return showMemoryUsage;
2637 df = java.text.NumberFormat.getNumberInstance();
2638 df.setMaximumFractionDigits(2);
2639 runtime = Runtime.getRuntime();
2641 while (showMemoryUsage)
2645 maxMemory = runtime.maxMemory() / ONE_MB;
2646 allocatedMemory = runtime.totalMemory() / ONE_MB;
2647 freeMemory = runtime.freeMemory() / ONE_MB;
2648 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2650 percentUsage = (totalFreeMemory / maxMemory) * 100;
2652 // if (percentUsage < 20)
2654 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2656 // instance.set.setBorder(border1);
2659 // sleep after showing usage
2661 } catch (Exception ex)
2663 ex.printStackTrace();
2669 public void paintComponent(Graphics g)
2671 if (showMemoryUsage && g != null && df != null)
2673 if (percentUsage < 20)
2675 g.setColor(Color.red);
2677 FontMetrics fm = g.getFontMetrics();
2680 g.drawString(MessageManager.formatMessage("label.memory_stats",
2682 { df.format(totalFreeMemory), df.format(maxMemory),
2683 df.format(percentUsage) }),
2684 10, getHeight() - fm.getHeight());
2692 * Accessor method to quickly get all the AlignmentFrames loaded.
2694 * @return an array of AlignFrame, or null if none found
2696 public static AlignFrame[] getAlignFrames()
2698 if (Jalview.isHeadlessMode())
2700 // Desktop.desktop is null in headless mode
2701 return new AlignFrame[] { Jalview.currentAlignFrame };
2704 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2710 List<AlignFrame> avp = new ArrayList<>();
2712 for (int i = frames.length - 1; i > -1; i--)
2714 if (frames[i] instanceof AlignFrame)
2716 avp.add((AlignFrame) frames[i]);
2718 else if (frames[i] instanceof SplitFrame)
2721 * Also check for a split frame containing an AlignFrame
2723 GSplitFrame sf = (GSplitFrame) frames[i];
2724 if (sf.getTopFrame() instanceof AlignFrame)
2726 avp.add((AlignFrame) sf.getTopFrame());
2728 if (sf.getBottomFrame() instanceof AlignFrame)
2730 avp.add((AlignFrame) sf.getBottomFrame());
2734 if (avp.size() == 0)
2738 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2743 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2747 public GStructureViewer[] getJmols()
2749 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2755 List<GStructureViewer> avp = new ArrayList<>();
2757 for (int i = frames.length - 1; i > -1; i--)
2759 if (frames[i] instanceof AppJmol)
2761 GStructureViewer af = (GStructureViewer) frames[i];
2765 if (avp.size() == 0)
2769 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2774 * Add Groovy Support to Jalview
2777 public void groovyShell_actionPerformed()
2781 openGroovyConsole();
2782 } catch (Exception ex)
2784 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2785 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2787 MessageManager.getString("label.couldnt_create_groovy_shell"),
2788 MessageManager.getString("label.groovy_support_failed"),
2789 JvOptionPane.ERROR_MESSAGE);
2794 * Open the Groovy console
2796 void openGroovyConsole()
2798 if (groovyConsole == null)
2800 groovyConsole = new groovy.ui.Console();
2801 groovyConsole.setVariable("Jalview", this);
2802 groovyConsole.run();
2805 * We allow only one console at a time, so that AlignFrame menu option
2806 * 'Calculate | Run Groovy script' is unambiguous.
2807 * Disable 'Groovy Console', and enable 'Run script', when the console is
2808 * opened, and the reverse when it is closed
2810 Window window = (Window) groovyConsole.getFrame();
2811 window.addWindowListener(new WindowAdapter()
2814 public void windowClosed(WindowEvent e)
2817 * rebind CMD-Q from Groovy Console to Jalview Quit
2820 enableExecuteGroovy(false);
2826 * show Groovy console window (after close and reopen)
2828 ((Window) groovyConsole.getFrame()).setVisible(true);
2831 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2832 * and disable opening a second console
2834 enableExecuteGroovy(true);
2838 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2839 * binding when opened
2841 protected void addQuitHandler()
2843 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2844 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2845 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2847 getRootPane().getActionMap().put("Quit", new AbstractAction()
2850 public void actionPerformed(ActionEvent e)
2858 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2861 * true if Groovy console is open
2863 public void enableExecuteGroovy(boolean enabled)
2866 * disable opening a second Groovy console
2867 * (or re-enable when the console is closed)
2869 groovyShell.setEnabled(!enabled);
2871 AlignFrame[] alignFrames = getAlignFrames();
2872 if (alignFrames != null)
2874 for (AlignFrame af : alignFrames)
2876 af.setGroovyEnabled(enabled);
2882 * Progress bars managed by the IProgressIndicator method.
2884 private Hashtable<Long, JPanel> progressBars;
2886 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2891 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2894 public void setProgressBar(String message, long id)
2896 if (progressBars == null)
2898 progressBars = new Hashtable<>();
2899 progressBarHandlers = new Hashtable<>();
2902 if (progressBars.get(new Long(id)) != null)
2904 JPanel panel = progressBars.remove(new Long(id));
2905 if (progressBarHandlers.contains(new Long(id)))
2907 progressBarHandlers.remove(new Long(id));
2909 removeProgressPanel(panel);
2913 progressBars.put(new Long(id), addProgressPanel(message));
2920 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2921 * jalview.gui.IProgressIndicatorHandler)
2924 public void registerHandler(final long id,
2925 final IProgressIndicatorHandler handler)
2927 if (progressBarHandlers == null
2928 || !progressBars.containsKey(new Long(id)))
2930 throw new Error(MessageManager.getString(
2931 "error.call_setprogressbar_before_registering_handler"));
2933 progressBarHandlers.put(new Long(id), handler);
2934 final JPanel progressPanel = progressBars.get(new Long(id));
2935 if (handler.canCancel())
2937 JButton cancel = new JButton(
2938 MessageManager.getString("action.cancel"));
2939 final IProgressIndicator us = this;
2940 cancel.addActionListener(new ActionListener()
2944 public void actionPerformed(ActionEvent e)
2946 handler.cancelActivity(id);
2947 us.setProgressBar(MessageManager
2948 .formatMessage("label.cancelled_params", new Object[]
2949 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2953 progressPanel.add(cancel, BorderLayout.EAST);
2959 * @return true if any progress bars are still active
2962 public boolean operationInProgress()
2964 if (progressBars != null && progressBars.size() > 0)
2972 * This will return the first AlignFrame holding the given viewport instance.
2973 * It will break if there are more than one AlignFrames viewing a particular
2977 * @return alignFrame for viewport
2979 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2981 if (desktop != null)
2983 AlignmentPanel[] aps = getAlignmentPanels(
2984 viewport.getSequenceSetId());
2985 for (int panel = 0; aps != null && panel < aps.length; panel++)
2987 if (aps[panel] != null && aps[panel].av == viewport)
2989 return aps[panel].alignFrame;
2996 public VamsasApplication getVamsasApplication()
3003 * flag set if jalview GUI is being operated programmatically
3005 private boolean inBatchMode = false;
3008 * check if jalview GUI is being operated programmatically
3010 * @return inBatchMode
3012 public boolean isInBatchMode()
3018 * set flag if jalview GUI is being operated programmatically
3020 * @param inBatchMode
3022 public void setInBatchMode(boolean inBatchMode)
3024 this.inBatchMode = inBatchMode;
3027 public void startServiceDiscovery()
3029 startServiceDiscovery(false);
3032 public void startServiceDiscovery(boolean blocking)
3034 boolean alive = true;
3035 Thread t0 = null, t1 = null, t2 = null;
3036 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3039 // todo: changesupport handlers need to be transferred
3040 if (discoverer == null)
3042 discoverer = new jalview.ws.jws1.Discoverer();
3043 // register PCS handler for desktop.
3044 discoverer.addPropertyChangeListener(changeSupport);
3046 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3047 // until we phase out completely
3048 (t0 = new Thread(discoverer)).start();
3051 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3053 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3054 .startDiscoverer(changeSupport);
3058 // TODO: do rest service discovery
3067 } catch (Exception e)
3070 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3071 || (t3 != null && t3.isAlive())
3072 || (t0 != null && t0.isAlive());
3078 * called to check if the service discovery process completed successfully.
3082 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3084 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3086 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3087 .getErrorMessages();
3090 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3092 if (serviceChangedDialog == null)
3094 // only run if we aren't already displaying one of these.
3095 addDialogThread(serviceChangedDialog = new Runnable()
3102 * JalviewDialog jd =new JalviewDialog() {
3104 * @Override protected void cancelPressed() { // TODO
3105 * Auto-generated method stub
3107 * }@Override protected void okPressed() { // TODO
3108 * Auto-generated method stub
3110 * }@Override protected void raiseClosed() { // TODO
3111 * Auto-generated method stub
3113 * } }; jd.initDialogFrame(new
3114 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3115 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3116 * + " or mis-configured HTTP proxy settings.<br/>" +
3117 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3119 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3120 * ), true, true, "Web Service Configuration Problem", 450,
3123 * jd.waitForInput();
3125 JvOptionPane.showConfirmDialog(Desktop.desktop,
3126 new JLabel("<html><table width=\"450\"><tr><td>"
3127 + ermsg + "</td></tr></table>"
3128 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3129 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3130 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3131 + " Tools->Preferences dialog box to change them.</p></html>"),
3132 "Web Service Configuration Problem",
3133 JvOptionPane.DEFAULT_OPTION,
3134 JvOptionPane.ERROR_MESSAGE);
3135 serviceChangedDialog = null;
3144 "Errors reported by JABA discovery service. Check web services preferences.\n"
3151 private Runnable serviceChangedDialog = null;
3154 * start a thread to open a URL in the configured browser. Pops up a warning
3155 * dialog to the user if there is an exception when calling out to the browser
3160 public static void showUrl(final String url)
3162 showUrl(url, Desktop.instance);
3166 * Like showUrl but allows progress handler to be specified
3170 * (null) or object implementing IProgressIndicator
3172 public static void showUrl(final String url,
3173 final IProgressIndicator progress)
3175 new Thread(new Runnable()
3182 if (progress != null)
3184 progress.setProgressBar(MessageManager
3185 .formatMessage("status.opening_params", new Object[]
3186 { url }), this.hashCode());
3188 jalview.util.BrowserLauncher.openURL(url);
3189 } catch (Exception ex)
3191 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3193 .getString("label.web_browser_not_found_unix"),
3194 MessageManager.getString("label.web_browser_not_found"),
3195 JvOptionPane.WARNING_MESSAGE);
3197 ex.printStackTrace();
3199 if (progress != null)
3201 progress.setProgressBar(null, this.hashCode());
3207 public static WsParamSetManager wsparamManager = null;
3209 public static ParamManager getUserParameterStore()
3211 if (wsparamManager == null)
3213 wsparamManager = new WsParamSetManager();
3215 return wsparamManager;
3219 * static hyperlink handler proxy method for use by Jalview's internal windows
3223 public static void hyperlinkUpdate(HyperlinkEvent e)
3225 if (e.getEventType() == EventType.ACTIVATED)
3230 url = e.getURL().toString();
3231 Desktop.showUrl(url);
3232 } catch (Exception x)
3236 if (Cache.log != null)
3238 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3243 "Couldn't handle string " + url + " as a URL.");
3246 // ignore any exceptions due to dud links.
3253 * single thread that handles display of dialogs to user.
3255 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3258 * flag indicating if dialogExecutor should try to acquire a permit
3260 private volatile boolean dialogPause = true;
3265 private java.util.concurrent.Semaphore block = new Semaphore(0);
3267 private static groovy.ui.Console groovyConsole;
3270 * add another dialog thread to the queue
3274 public void addDialogThread(final Runnable prompter)
3276 dialogExecutor.submit(new Runnable()
3286 } catch (InterruptedException x)
3291 if (instance == null)
3297 SwingUtilities.invokeAndWait(prompter);
3298 } catch (Exception q)
3300 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3306 public void startDialogQueue()
3308 // set the flag so we don't pause waiting for another permit and semaphore
3309 // the current task to begin
3310 dialogPause = false;
3315 protected void snapShotWindow_actionPerformed(ActionEvent e)
3319 ImageMaker im = new jalview.util.ImageMaker(
3320 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3321 getHeight(), of = new File("Jalview_snapshot"
3322 + System.currentTimeMillis() + ".eps"),
3323 "View of desktop", null, 0, false);
3326 paintAll(im.getGraphics());
3328 } catch (Exception q)
3330 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3334 Cache.log.info("Successfully written snapshot to file "
3335 + of.getAbsolutePath());
3339 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3340 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3341 * and 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<String> files,
3508 List<DataSourceType> protocols, DropTargetDropEvent evt,
3509 Transferable t) throws Exception
3512 DataFlavor uriListFlavor = new DataFlavor(
3513 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3516 urlFlavour = new DataFlavor(
3517 "application/x-java-url; class=java.net.URL");
3518 } catch (ClassNotFoundException cfe)
3520 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3523 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3528 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3529 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3530 // means url may be null.
3533 protocols.add(DataSourceType.URL);
3534 files.add(url.toString());
3535 Cache.log.debug("Drop handled as URL dataflavor "
3536 + files.get(files.size() - 1));
3541 if (Platform.isAMac())
3544 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3548 } catch (Throwable ex)
3550 Cache.log.debug("URL drop handler failed.", ex);
3553 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3555 // Works on Windows and MacOSX
3556 Cache.log.debug("Drop handled as javaFileListFlavor");
3557 for (Object file : (List) t
3558 .getTransferData(DataFlavor.javaFileListFlavor))
3560 files.add(((File) file).toString());
3561 protocols.add(DataSourceType.FILE);
3566 // Unix like behaviour
3567 boolean added = false;
3569 if (t.isDataFlavorSupported(uriListFlavor))
3571 Cache.log.debug("Drop handled as uriListFlavor");
3572 // This is used by Unix drag system
3573 data = (String) t.getTransferData(uriListFlavor);
3577 // fallback to text: workaround - on OSX where there's a JVM bug
3578 Cache.log.debug("standard URIListFlavor failed. Trying text");
3579 // try text fallback
3580 DataFlavor textDf = new DataFlavor(
3581 "text/plain;class=java.lang.String");
3582 if (t.isDataFlavorSupported(textDf))
3584 data = (String) t.getTransferData(textDf);
3587 Cache.log.debug("Plain text drop content returned "
3588 + (data == null ? "Null - failed" : data));
3593 while (protocols.size() < files.size())
3595 Cache.log.debug("Adding missing FILE protocol for "
3596 + files.get(protocols.size()));
3597 protocols.add(DataSourceType.FILE);
3599 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3600 data, "\r\n"); st.hasMoreTokens();)
3603 String s = st.nextToken();
3604 if (s.startsWith("#"))
3606 // the line is a comment (as per the RFC 2483)
3609 java.net.URI uri = new java.net.URI(s);
3610 if (uri.getScheme().toLowerCase().startsWith("http"))
3612 protocols.add(DataSourceType.URL);
3613 files.add(uri.toString());
3617 // otherwise preserve old behaviour: catch all for file objects
3618 java.io.File file = new java.io.File(uri);
3619 protocols.add(DataSourceType.FILE);
3620 files.add(file.toString());
3625 if (Cache.log.isDebugEnabled())
3627 if (data == null || !added)
3630 if (t.getTransferDataFlavors() != null
3631 && t.getTransferDataFlavors().length > 0)
3634 "Couldn't resolve drop data. Here are the supported flavors:");
3635 for (DataFlavor fl : t.getTransferDataFlavors())
3638 "Supported transfer dataflavor: " + fl.toString());
3639 Object df = t.getTransferData(fl);
3642 Cache.log.debug("Retrieves: " + df);
3646 Cache.log.debug("Retrieved nothing");
3652 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3658 if (Platform.isWindows())
3661 Cache.log.debug("Scanning dropped content for Windows Link Files");
3663 // resolve any .lnk files in the file drop
3664 for (int f = 0; f < files.size(); f++)
3666 String source = files.get(f).toLowerCase();
3667 if (protocols.get(f).equals(DataSourceType.FILE)
3668 && (source.endsWith(".lnk") || source.endsWith(".url")
3669 || source.endsWith(".site")))
3672 File lf = new File(files.get(f));
3673 // process link file to get a URL
3674 Cache.log.debug("Found potential link file: " + lf);
3675 WindowsShortcut wscfile = new WindowsShortcut(lf);
3676 String fullname = wscfile.getRealFilename();
3677 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3678 files.set(f, fullname);
3679 Cache.log.debug("Parsed real filename " + fullname
3680 + " to extract protocol: " + protocols.get(f));
3682 catch (Exception ex)
3684 Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
3692 * Sets the Preferences property for experimental features to True or False
3693 * depending on the state of the controlling menu item
3696 protected void showExperimental_actionPerformed(boolean selected)
3698 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3702 * Answers a (possibly empty) list of any structure viewer frames (currently
3703 * for either Jmol or Chimera) which are currently open. This may optionally
3704 * be restricted to viewers of a specified class, or viewers linked to a
3705 * specified alignment panel.
3708 * if not null, only return viewers linked to this panel
3709 * @param structureViewerClass
3710 * if not null, only return viewers of this class
3713 public List<StructureViewerBase> getStructureViewers(
3714 AlignmentPanel apanel,
3715 Class<? extends StructureViewerBase> structureViewerClass)
3717 List<StructureViewerBase> result = new ArrayList<>();
3718 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3720 for (JInternalFrame frame : frames)
3722 if (frame instanceof StructureViewerBase)
3724 if (structureViewerClass == null
3725 || structureViewerClass.isInstance(frame))
3728 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3730 result.add((StructureViewerBase) frame);