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.DropTarget;
67 import java.awt.dnd.DropTargetDragEvent;
68 import java.awt.dnd.DropTargetDropEvent;
69 import java.awt.dnd.DropTargetEvent;
70 import java.awt.dnd.DropTargetListener;
71 import java.awt.event.ActionEvent;
72 import java.awt.event.ActionListener;
73 import java.awt.event.InputEvent;
74 import java.awt.event.KeyEvent;
75 import java.awt.event.MouseAdapter;
76 import java.awt.event.MouseEvent;
77 import java.awt.event.WindowAdapter;
78 import java.awt.event.WindowEvent;
79 import java.beans.PropertyChangeEvent;
80 import java.beans.PropertyChangeListener;
81 import java.io.BufferedInputStream;
83 import java.io.FileOutputStream;
84 import java.io.IOException;
86 import java.util.ArrayList;
87 import java.util.Hashtable;
88 import java.util.List;
89 import java.util.ListIterator;
90 import java.util.StringTokenizer;
91 import java.util.Vector;
92 import java.util.concurrent.ExecutorService;
93 import java.util.concurrent.Executors;
94 import java.util.concurrent.Semaphore;
96 import javax.swing.AbstractAction;
97 import javax.swing.Action;
98 import javax.swing.ActionMap;
99 import javax.swing.Box;
100 import javax.swing.BoxLayout;
101 import javax.swing.DefaultDesktopManager;
102 import javax.swing.DesktopManager;
103 import javax.swing.InputMap;
104 import javax.swing.JButton;
105 import javax.swing.JCheckBox;
106 import javax.swing.JComboBox;
107 import javax.swing.JComponent;
108 import javax.swing.JDesktopPane;
109 import javax.swing.JFileChooser;
110 import javax.swing.JFrame;
111 import javax.swing.JInternalFrame;
112 import javax.swing.JLabel;
113 import javax.swing.JMenuItem;
114 import javax.swing.JPanel;
115 import javax.swing.JPopupMenu;
116 import javax.swing.JProgressBar;
117 import javax.swing.JTextArea;
118 import javax.swing.KeyStroke;
119 import javax.swing.SwingUtilities;
120 import javax.swing.event.HyperlinkEvent;
121 import javax.swing.event.HyperlinkEvent.EventType;
122 import javax.swing.event.InternalFrameAdapter;
123 import javax.swing.event.InternalFrameEvent;
124 import javax.swing.event.MenuEvent;
125 import javax.swing.event.MenuListener;
127 import org.stackoverflowusers.file.WindowsShortcut;
134 * @version $Revision: 1.155 $
136 public class Desktop extends jalview.jbgui.GDesktop
137 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
138 jalview.api.StructureSelectionManagerProvider
140 private static int DEFAULT_MIN_WIDTH = 300;
142 private static int DEFAULT_MIN_HEIGHT = 250;
144 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
146 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
148 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
150 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
153 * news reader - null if it was never started.
155 private BlogReader jvnews = null;
157 private File projectFile;
161 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
163 public void addJalviewPropertyChangeListener(
164 PropertyChangeListener listener)
166 changeSupport.addJalviewPropertyChangeListener(listener);
170 * @param propertyName
172 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
173 * java.beans.PropertyChangeListener)
175 public void addJalviewPropertyChangeListener(String propertyName,
176 PropertyChangeListener listener)
178 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
182 * @param propertyName
184 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
185 * java.beans.PropertyChangeListener)
187 public void removeJalviewPropertyChangeListener(String propertyName,
188 PropertyChangeListener listener)
190 changeSupport.removeJalviewPropertyChangeListener(propertyName,
194 /** Singleton Desktop instance */
195 public static Desktop instance;
197 public static MyDesktopPane desktop;
199 public static MyDesktopPane getDesktop()
201 // BH 2018 could use currentThread() here as a reference to a
202 // Hashtable<Thread, MyDesktopPane> in JavaScript
206 static int openFrameCount = 0;
208 static final int xOffset = 30;
210 static final int yOffset = 30;
212 public static jalview.ws.jws1.Discoverer discoverer;
214 public static Object[] jalviewClipboard;
216 public static boolean internalCopy = false;
218 static int fileLoadingCount = 0;
220 class MyDesktopManager implements DesktopManager
223 private DesktopManager delegate;
225 public MyDesktopManager(DesktopManager delegate)
227 this.delegate = delegate;
231 public void activateFrame(JInternalFrame f)
235 delegate.activateFrame(f);
236 } catch (NullPointerException npe)
238 Point p = getMousePosition();
239 instance.showPasteMenu(p.x, p.y);
244 public void beginDraggingFrame(JComponent f)
246 delegate.beginDraggingFrame(f);
250 public void beginResizingFrame(JComponent f, int direction)
252 delegate.beginResizingFrame(f, direction);
256 public void closeFrame(JInternalFrame f)
258 delegate.closeFrame(f);
262 public void deactivateFrame(JInternalFrame f)
264 delegate.deactivateFrame(f);
268 public void deiconifyFrame(JInternalFrame f)
270 delegate.deiconifyFrame(f);
274 public void dragFrame(JComponent f, int newX, int newY)
280 delegate.dragFrame(f, newX, newY);
284 public void endDraggingFrame(JComponent f)
286 delegate.endDraggingFrame(f);
291 public void endResizingFrame(JComponent f)
293 delegate.endResizingFrame(f);
298 public void iconifyFrame(JInternalFrame f)
300 delegate.iconifyFrame(f);
304 public void maximizeFrame(JInternalFrame f)
306 delegate.maximizeFrame(f);
310 public void minimizeFrame(JInternalFrame f)
312 delegate.minimizeFrame(f);
316 public void openFrame(JInternalFrame f)
318 delegate.openFrame(f);
322 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
329 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
333 public void setBoundsForFrame(JComponent f, int newX, int newY,
334 int newWidth, int newHeight)
336 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
339 // All other methods, simply delegate
344 * Creates a new Desktop object.
349 * A note to implementors. It is ESSENTIAL that any activities that might
350 * block are spawned off as threads rather than waited for during this
354 doVamsasClientCheck();
356 doConfigureStructurePrefs();
357 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
358 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
359 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
361 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
363 desktop = new MyDesktopPane(selmemusage);
364 showMemusage.setSelected(selmemusage);
365 desktop.setBackground(Color.white);
366 getContentPane().setLayout(new BorderLayout());
367 // alternate config - have scrollbars - see notes in JAL-153
368 // JScrollPane sp = new JScrollPane();
369 // sp.getViewport().setView(desktop);
370 // getContentPane().add(sp, BorderLayout.CENTER);
371 getContentPane().add(desktop, BorderLayout.CENTER);
372 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
374 // This line prevents Windows Look&Feel resizing all new windows to maximum
375 // if previous window was maximised
376 desktop.setDesktopManager(
377 new MyDesktopManager(
378 (Platform.isWindows() ? new DefaultDesktopManager()
380 ? new AquaInternalFrameManager(
381 desktop.getDesktopManager())
382 : desktop.getDesktopManager())));
384 Rectangle dims = getLastKnownDimensions("");
391 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
392 int xPos = Math.max(5, (screenSize.width - 900) / 2);
393 int yPos = Math.max(5, (screenSize.height - 650) / 2);
394 setBounds(xPos, yPos, 900, 650);
403 jconsole = new Console(this, showjconsole);
404 // add essential build information
405 jconsole.setHeader("Jalview Version: "
406 + jalview.bin.Cache.getProperty("VERSION") + "\n"
407 + "Jalview Installation: "
408 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
409 + "\n" + "Build Date: "
410 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
411 + "Java version: " + System.getProperty("java.version") + "\n"
412 + System.getProperty("os.arch") + " "
413 + System.getProperty("os.name") + " "
414 + System.getProperty("os.version"));
416 showConsole(showjconsole);
418 showNews.setVisible(false);
420 experimentalFeatures.setSelected(showExperimental());
422 getIdentifiersOrgData();
426 // Spawn a thread that shows the splashscreen
428 SwingUtilities.invokeLater(new Runnable()
437 // Thread off a new instance of the file chooser - this reduces the time it
438 // takes to open it later on.
439 new Thread(new Runnable()
444 Cache.log.debug("Filechooser init thread started.");
445 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
446 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
448 Cache.log.debug("Filechooser init thread finished.");
451 // Add the service change listener
452 changeSupport.addJalviewPropertyChangeListener("services",
453 new PropertyChangeListener()
457 public void propertyChange(PropertyChangeEvent evt)
459 Cache.log.debug("Firing service changed event for "
460 + evt.getNewValue());
461 JalviewServicesChanged(evt);
466 } // end BH 2018 ignore
468 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
470 this.addWindowListener(new WindowAdapter()
473 public void windowClosing(WindowEvent evt)
480 this.addMouseListener(ma = new MouseAdapter()
483 public void mousePressed(MouseEvent evt)
485 if (evt.isPopupTrigger()) // Mac
487 showPasteMenu(evt.getX(), evt.getY());
492 public void mouseReleased(MouseEvent evt)
494 if (evt.isPopupTrigger()) // Windows
496 showPasteMenu(evt.getX(), evt.getY());
500 desktop.addMouseListener(ma);
505 * Answers true if user preferences to enable experimental features is True
510 public boolean showExperimental()
512 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
513 Boolean.FALSE.toString());
514 return Boolean.valueOf(experimental).booleanValue();
517 public void doConfigureStructurePrefs()
519 // configure services
520 StructureSelectionManager ssm = StructureSelectionManager
521 .getStructureSelectionManager(this);
522 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
524 ssm.setAddTempFacAnnot(jalview.bin.Cache
525 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
526 ssm.setProcessSecondaryStructure(jalview.bin.Cache
527 .getDefault(Preferences.STRUCT_FROM_PDB, true));
528 ssm.setSecStructServices(
529 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
533 ssm.setAddTempFacAnnot(false);
534 ssm.setProcessSecondaryStructure(false);
535 ssm.setSecStructServices(false);
539 public void checkForNews()
548 final Desktop me = this;
549 // Thread off the news reader, in case there are connection problems.
550 addDialogThread(new Runnable()
555 Cache.log.debug("Starting news thread.");
557 jvnews = new BlogReader(me);
558 showNews.setVisible(true);
559 Cache.log.debug("Completed news thread.");
565 public void getIdentifiersOrgData()
567 // Thread off the identifiers fetcher
568 addDialogThread(new Runnable()
573 Cache.log.debug("Downloading data from identifiers.org");
574 UrlDownloadClient client = new UrlDownloadClient();
577 client.download(IdOrgSettings.getUrl(),
578 IdOrgSettings.getDownloadLocation());
579 } catch (IOException e)
581 Cache.log.debug("Exception downloading identifiers.org data"
589 protected void showNews_actionPerformed(ActionEvent e)
591 showNews(showNews.isSelected());
594 void showNews(boolean visible)
603 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
604 showNews.setSelected(visible);
605 if (visible && !jvnews.isVisible())
607 new Thread(new Runnable()
612 long now = System.currentTimeMillis();
613 Desktop.instance.setProgressBar(
614 MessageManager.getString("status.refreshing_news"),
616 jvnews.refreshNews();
617 Desktop.instance.setProgressBar(null, now);
626 * recover the last known dimensions for a jalview window
629 * - empty string is desktop, all other windows have unique prefix
630 * @return null or last known dimensions scaled to current geometry (if last
631 * window geom was known)
633 Rectangle getLastKnownDimensions(String windowName)
635 // TODO: lock aspect ratio for scaling desktop Bug #0058199
636 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
637 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
638 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
639 String width = jalview.bin.Cache
640 .getProperty(windowName + "SCREEN_WIDTH");
641 String height = jalview.bin.Cache
642 .getProperty(windowName + "SCREEN_HEIGHT");
643 if ((x != null) && (y != null) && (width != null) && (height != null))
645 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
646 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
647 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
649 // attempt #1 - try to cope with change in screen geometry - this
650 // version doesn't preserve original jv aspect ratio.
651 // take ratio of current screen size vs original screen size.
652 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
653 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
654 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
655 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
656 // rescale the bounds depending upon the current screen geometry.
657 ix = (int) (ix * sw);
658 iw = (int) (iw * sw);
659 iy = (int) (iy * sh);
660 ih = (int) (ih * sh);
661 while (ix >= screenSize.width)
663 jalview.bin.Cache.log.debug(
664 "Window geometry location recall error: shifting horizontal to within screenbounds.");
665 ix -= screenSize.width;
667 while (iy >= screenSize.height)
669 jalview.bin.Cache.log.debug(
670 "Window geometry location recall error: shifting vertical to within screenbounds.");
671 iy -= screenSize.height;
673 jalview.bin.Cache.log.debug(
674 "Got last known dimensions for " + windowName + ": x:" + ix
675 + " y:" + iy + " width:" + iw + " height:" + ih);
677 // return dimensions for new instance
678 return new Rectangle(ix, iy, iw, ih);
683 private void doVamsasClientCheck()
685 if (/** @j2sNative false && */ // BH 2018
686 jalview.bin.Cache.vamsasJarsPresent())
688 setupVamsasDisconnectedGui();
689 VamsasMenu.setVisible(true);
690 final Desktop us = this;
691 VamsasMenu.addMenuListener(new MenuListener()
693 // this listener remembers when the menu was first selected, and
694 // doesn't rebuild the session list until it has been cleared and
696 boolean refresh = true;
699 public void menuCanceled(MenuEvent e)
705 public void menuDeselected(MenuEvent e)
711 public void menuSelected(MenuEvent e)
715 us.buildVamsasStMenu();
720 vamsasStart.setVisible(true);
724 void showPasteMenu(int x, int y)
726 JPopupMenu popup = new JPopupMenu();
727 JMenuItem item = new JMenuItem(
728 MessageManager.getString("label.paste_new_window"));
729 item.addActionListener(new ActionListener()
732 public void actionPerformed(ActionEvent evt)
739 popup.show(this, x, y);
746 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
747 Transferable contents = c.getContents(this);
749 if (contents != null)
751 String file = (String) contents
752 .getTransferData(DataFlavor.stringFlavor);
754 FileFormatI format = new IdentifyFile().identify(file,
755 DataSourceType.PASTE);
757 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
760 } catch (Exception ex)
763 "Unable to paste alignment from system clipboard:\n" + ex);
768 * Adds and opens the given frame to the desktop
779 public static synchronized void addInternalFrame(
780 final JInternalFrame frame, String title, int w, int h)
782 addInternalFrame(frame, title, true, w, h, true, false);
786 * Add an internal frame to the Jalview desktop
793 * When true, display frame immediately, otherwise, caller must call
794 * setVisible themselves.
800 public static synchronized void addInternalFrame(
801 final JInternalFrame frame, String title, boolean makeVisible,
804 addInternalFrame(frame, title, makeVisible, w, h, true, false);
808 * Add an internal frame to the Jalview desktop and make it visible
821 public static synchronized void addInternalFrame(
822 final JInternalFrame frame, String title, int w, int h,
825 addInternalFrame(frame, title, true, w, h, resizable, false);
829 * Add an internal frame to the Jalview desktop
836 * When true, display frame immediately, otherwise, caller must call
837 * setVisible themselves.
844 * @param ignoreMinSize
845 * Do not set the default minimum size for frame
847 public static synchronized void addInternalFrame(
848 final JInternalFrame frame, String title, boolean makeVisible,
849 int w, int h, boolean resizable, boolean ignoreMinSize)
852 // TODO: allow callers to determine X and Y position of frame (eg. via
854 // TODO: consider fixing method to update entries in the window submenu with
855 // the current window title
857 frame.setTitle(title);
858 if (frame.getWidth() < 1 || frame.getHeight() < 1)
862 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
863 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
864 // IF JALVIEW IS RUNNING HEADLESS
865 // ///////////////////////////////////////////////
866 if (instance == null || (System.getProperty("java.awt.headless") != null
867 && System.getProperty("java.awt.headless").equals("true")))
876 frame.setMinimumSize(
877 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
879 // Set default dimension for Alignment Frame window.
880 // The Alignment Frame window could be added from a number of places,
882 // I did this here in order not to miss out on any Alignment frame.
883 if (frame instanceof AlignFrame)
885 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
886 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
890 frame.setVisible(makeVisible);
891 frame.setClosable(true);
892 frame.setResizable(resizable);
893 frame.setMaximizable(resizable);
894 frame.setIconifiable(resizable);
895 frame.setOpaque(/** @j2sNative true || */
898 if (frame.getX() < 1 && frame.getY() < 1)
900 frame.setLocation(xOffset * openFrameCount,
901 yOffset * ((openFrameCount - 1) % 10) + yOffset);
905 * add an entry for the new frame in the Window menu
906 * (and remove it when the frame is closed)
908 final JMenuItem menuItem = new JMenuItem(title);
909 frame.addInternalFrameListener(new InternalFrameAdapter()
912 public void internalFrameActivated(InternalFrameEvent evt)
914 JInternalFrame itf = desktop.getSelectedFrame();
917 if (itf instanceof AlignFrame)
919 Jalview.setCurrentAlignFrame((AlignFrame) itf);
926 public void internalFrameClosed(InternalFrameEvent evt)
928 PaintRefresher.RemoveComponent(frame);
931 * defensive check to prevent frames being
932 * added half off the window
934 if (openFrameCount > 0)
940 * ensure no reference to alignFrame retained by menu item listener
942 if (menuItem.getActionListeners().length > 0)
944 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
946 windowMenu.remove(menuItem);
950 menuItem.addActionListener(new ActionListener()
953 public void actionPerformed(ActionEvent e)
957 frame.setSelected(true);
958 frame.setIcon(false);
959 } catch (java.beans.PropertyVetoException ex)
966 setKeyBindings(frame);
970 windowMenu.add(menuItem);
975 frame.setSelected(true);
976 frame.requestFocus();
977 } catch (java.beans.PropertyVetoException ve)
979 } catch (java.lang.ClassCastException cex)
982 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
988 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
993 private static void setKeyBindings(JInternalFrame frame)
995 @SuppressWarnings("serial")
996 final Action closeAction = new AbstractAction()
999 public void actionPerformed(ActionEvent e)
1006 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1008 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1009 InputEvent.CTRL_DOWN_MASK);
1010 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1011 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1013 InputMap inputMap = frame
1014 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1015 String ctrlW = ctrlWKey.toString();
1016 inputMap.put(ctrlWKey, ctrlW);
1017 inputMap.put(cmdWKey, ctrlW);
1019 ActionMap actionMap = frame.getActionMap();
1020 actionMap.put(ctrlW, closeAction);
1024 public void lostOwnership(Clipboard clipboard, Transferable contents)
1028 Desktop.jalviewClipboard = null;
1031 internalCopy = false;
1035 public void dragEnter(DropTargetDragEvent evt)
1040 public void dragExit(DropTargetEvent evt)
1045 public void dragOver(DropTargetDragEvent evt)
1050 public void dropActionChanged(DropTargetDragEvent evt)
1061 public void drop(DropTargetDropEvent evt)
1063 boolean success = true;
1064 // JAL-1552 - acceptDrop required before getTransferable call for
1065 // Java's Transferable for native dnd
1066 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1067 Transferable t = evt.getTransferable();
1068 List<Object> files = new ArrayList<>();
1069 List<DataSourceType> protocols = new ArrayList<>();
1073 Desktop.transferFromDropTarget(files, protocols, evt, t);
1074 } catch (Exception e)
1076 e.printStackTrace();
1084 for (int i = 0; i < files.size(); i++)
1086 // BH 2018 File or String
1087 Object file = files.get(i);
1088 String fileName = file.toString();
1089 DataSourceType protocol = (protocols == null)
1090 ? DataSourceType.FILE
1092 FileFormatI format = null;
1094 if (fileName.endsWith(".jar"))
1096 format = FileFormat.Jalview;
1101 format = new IdentifyFile().identify(file, protocol);
1104 new FileLoader().LoadFile(null, file, protocol, format);
1107 } catch (Exception ex)
1112 evt.dropComplete(success); // need this to ensure input focus is properly
1113 // transfered to any new windows created
1123 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1125 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1126 final JalviewFileChooser chooser = JalviewFileChooser
1127 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1129 chooser.setFileView(new JalviewFileView());
1130 chooser.setDialogTitle(
1131 MessageManager.getString("label.open_local_file"));
1132 chooser.setToolTipText(MessageManager.getString("action.open"));
1134 chooser.setCallback(new Runnable()
1140 File selectedFile = chooser.getSelectedFile();
1141 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1143 FileFormatI format = chooser.getSelectedFormat();
1146 * Call IdentifyFile to verify the file contains what its extension implies.
1147 * Skip this step for dynamically added file formats, because
1148 * IdentifyFile does not know how to recognise them.
1150 if (FileFormats.getInstance().isIdentifiable(format))
1154 format = new IdentifyFile().identify(selectedFile,
1155 DataSourceType.FILE);
1156 } catch (FileFormatException e)
1158 // format = null; //??
1162 new FileLoader().LoadFile(viewport, selectedFile,
1163 DataSourceType.FILE, format);
1167 int value = chooser.showOpenDialog(this);
1168 if (value == JFileChooser.APPROVE_OPTION)
1170 chooser.getCallback().run();
1182 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1184 // This construct allows us to have a wider textfield
1186 JLabel label = new JLabel(
1187 MessageManager.getString("label.input_file_url"));
1189 JComboBox history = new JComboBox();
1190 JPanel panel = new JPanel(new GridLayout(2, 1));
1193 history.setPreferredSize(new Dimension(400, 20));
1194 history.setEditable(true);
1195 history.addItem("http://www.");
1197 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1201 if (historyItems != null)
1203 st = new StringTokenizer(historyItems, "\t");
1205 while (st.hasMoreTokens())
1207 history.addItem(st.nextElement());
1211 // BH 2018 -- providing a callback for SwingJS
1212 // dialogOption is just a simple way to provide
1213 // context for the modal-like response.
1214 // The only requirement is that desktop implement
1215 // PropertyChangeListener, which is used already in Java
1216 // for changes in input value and such within the dialogs.
1218 String dialogOption = "label.input_alignment_from_url";
1219 desktop.dialogData = new Object[] { dialogOption, viewport, history };
1220 desktop.onDialogReturn(
1221 JvOptionPane.showInternalConfirmDialog(desktop, panel,
1222 MessageManager.getString(dialogOption),
1223 JvOptionPane.OK_CANCEL_OPTION));
1225 // no code may follow this, as SwingJS will not block
1226 // callback in JavaScript comes via a property change event,
1227 // thus going into desktop.onDialogReturn(int) just the same as
1234 * Opens the CutAndPaste window for the user to paste an alignment in to
1237 * - if not null, the pasted alignment is added to the current
1238 * alignment; if null, to a new alignment window
1241 public void inputTextboxMenuItem_actionPerformed(
1242 AlignmentViewPanel viewPanel)
1244 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1245 cap.setForInput(viewPanel);
1246 Desktop.addInternalFrame(cap,
1247 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1257 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1258 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1260 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1261 screen.height + "");
1262 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1263 getWidth(), getHeight()));
1265 if (jconsole != null)
1267 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1268 jconsole.stopConsole();
1272 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1275 if (dialogExecutor != null)
1277 dialogExecutor.shutdownNow();
1279 closeAll_actionPerformed(null);
1281 if (groovyConsole != null)
1283 // suppress a possible repeat prompt to save script
1284 groovyConsole.setDirty(false);
1285 groovyConsole.exit();
1290 private void storeLastKnownDimensions(String string, Rectangle jc)
1292 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1293 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1294 + " height:" + jc.height);
1296 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1297 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1298 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1299 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1309 public void aboutMenuItem_actionPerformed(ActionEvent e)
1311 // StringBuffer message = getAboutMessage(false);
1312 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1314 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1315 new Thread(new Runnable()
1320 new SplashScreen(true);
1325 public StringBuffer getAboutMessage(boolean shortv)
1327 StringBuffer message = new StringBuffer();
1328 message.append("<html>");
1331 message.append("<h1><strong>Version: "
1332 + jalview.bin.Cache.getProperty("VERSION")
1333 + "</strong></h1>");
1334 message.append("<strong>Last Updated: <em>"
1335 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1336 + "</em></strong>");
1342 message.append("<strong>Version "
1343 + jalview.bin.Cache.getProperty("VERSION")
1344 + "; last updated: "
1345 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1348 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1349 .equals("Checking"))
1351 message.append("<br>...Checking latest version...</br>");
1353 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1354 .equals(jalview.bin.Cache.getProperty("VERSION")))
1356 boolean red = false;
1357 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1358 .indexOf("automated build") == -1)
1361 // Displayed when code version and jnlp version do not match and code
1362 // version is not a development build
1363 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1366 message.append("<br>!! Version "
1367 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1369 + " is available for download from "
1370 + jalview.bin.Cache.getDefault("www.jalview.org",
1371 "http://www.jalview.org")
1375 message.append("</div>");
1378 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1380 "The Jalview Authors (See AUTHORS file for current list)")
1381 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1382 + "<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"
1383 + "<br><br>If you use Jalview, please cite:"
1384 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1385 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1386 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1398 public void documentationMenuItem_actionPerformed(ActionEvent e)
1402 Help.showHelpWindow();
1403 } catch (Exception ex)
1409 public void closeAll_actionPerformed(ActionEvent e)
1411 // TODO show a progress bar while closing?
1412 JInternalFrame[] frames = desktop.getAllFrames();
1413 for (int i = 0; i < frames.length; i++)
1417 frames[i].setClosed(true);
1418 } catch (java.beans.PropertyVetoException ex)
1422 Jalview.setCurrentAlignFrame(null);
1423 System.out.println("ALL CLOSED");
1424 if (v_client != null)
1426 // TODO clear binding to vamsas document objects on close_all
1430 * reset state of singleton objects as appropriate (clear down session state
1431 * when all windows are closed)
1433 StructureSelectionManager ssm = StructureSelectionManager
1434 .getStructureSelectionManager(this);
1442 public void raiseRelated_actionPerformed(ActionEvent e)
1444 reorderAssociatedWindows(false, false);
1448 public void minimizeAssociated_actionPerformed(ActionEvent e)
1450 reorderAssociatedWindows(true, false);
1453 void closeAssociatedWindows()
1455 reorderAssociatedWindows(false, true);
1461 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1465 protected void garbageCollect_actionPerformed(ActionEvent e)
1467 // We simply collect the garbage
1468 jalview.bin.Cache.log.debug("Collecting garbage...");
1470 jalview.bin.Cache.log.debug("Finished garbage collection.");
1477 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1481 protected void showMemusage_actionPerformed(ActionEvent e)
1483 desktop.showMemoryUsage(showMemusage.isSelected());
1490 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1494 protected void showConsole_actionPerformed(ActionEvent e)
1496 showConsole(showConsole.isSelected());
1499 Console jconsole = null;
1502 * control whether the java console is visible or not
1506 void showConsole(boolean selected)
1508 // TODO: decide if we should update properties file
1509 if (jconsole != null) // BH 2018
1511 showConsole.setSelected(selected);
1512 Cache.setProperty("SHOW_JAVA_CONSOLE",
1513 Boolean.valueOf(selected).toString());
1514 jconsole.setVisible(selected);
1518 void reorderAssociatedWindows(boolean minimize, boolean close)
1520 JInternalFrame[] frames = desktop.getAllFrames();
1521 if (frames == null || frames.length < 1)
1526 AlignmentViewport source = null, target = null;
1527 if (frames[0] instanceof AlignFrame)
1529 source = ((AlignFrame) frames[0]).getCurrentView();
1531 else if (frames[0] instanceof TreePanel)
1533 source = ((TreePanel) frames[0]).getViewPort();
1535 else if (frames[0] instanceof PCAPanel)
1537 source = ((PCAPanel) frames[0]).av;
1539 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1541 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1546 for (int i = 0; i < frames.length; i++)
1549 if (frames[i] == null)
1553 if (frames[i] instanceof AlignFrame)
1555 target = ((AlignFrame) frames[i]).getCurrentView();
1557 else if (frames[i] instanceof TreePanel)
1559 target = ((TreePanel) frames[i]).getViewPort();
1561 else if (frames[i] instanceof PCAPanel)
1563 target = ((PCAPanel) frames[i]).av;
1565 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1567 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1570 if (source == target)
1576 frames[i].setClosed(true);
1580 frames[i].setIcon(minimize);
1583 frames[i].toFront();
1587 } catch (java.beans.PropertyVetoException ex)
1602 protected void preferences_actionPerformed(ActionEvent e)
1614 public void saveState_actionPerformed(ActionEvent e)
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 JalviewFileChooser chooser = new JalviewFileChooser(
1690 Cache.getProperty("LAST_DIRECTORY"), new String[]
1693 { "Jalview Project", "Jalview Project (old)" },
1695 chooser.setFileView(new JalviewFileView());
1696 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1698 int value = chooser.showOpenDialog(this);
1700 if (value == JalviewFileChooser.APPROVE_OPTION)
1702 final File selectedFile = chooser.getSelectedFile();
1703 setProjectFile(selectedFile);
1704 final String choice = selectedFile.getAbsolutePath();
1705 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1706 new Thread(new Runnable()
1711 setProgressBar(MessageManager.formatMessage(
1712 "label.loading_jalview_project", new Object[]
1713 { choice }), choice.hashCode());
1716 new Jalview2XML().loadJalviewAlign(choice);
1717 } catch (OutOfMemoryError oom)
1719 new OOMWarning("Whilst loading project from " + choice, oom);
1720 } catch (Exception ex)
1723 "Problems whilst loading project from " + choice, ex);
1724 JvOptionPane.showMessageDialog(Desktop.desktop,
1725 MessageManager.formatMessage(
1726 "label.error_whilst_loading_project_from",
1729 MessageManager.getString("label.couldnt_load_project"),
1730 JvOptionPane.WARNING_MESSAGE);
1732 setProgressBar(null, choice.hashCode());
1739 public void inputSequence_actionPerformed(ActionEvent e)
1741 new SequenceFetcher(this);
1744 JPanel progressPanel;
1746 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1748 public void startLoading(final Object fileName)
1750 if (fileLoadingCount == 0)
1752 fileLoadingPanels.add(addProgressPanel(MessageManager
1753 .formatMessage("label.loading_file", new Object[]
1759 private JPanel addProgressPanel(String string)
1761 if (progressPanel == null)
1763 progressPanel = new JPanel(new GridLayout(1, 1));
1764 totalProgressCount = 0;
1765 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1767 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1768 JProgressBar progressBar = new JProgressBar();
1769 progressBar.setIndeterminate(true);
1771 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1773 thisprogress.add(progressBar, BorderLayout.CENTER);
1774 progressPanel.add(thisprogress);
1775 ((GridLayout) progressPanel.getLayout()).setRows(
1776 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1777 ++totalProgressCount;
1778 instance.validate();
1779 return thisprogress;
1782 int totalProgressCount = 0;
1784 private void removeProgressPanel(JPanel progbar)
1786 if (progressPanel != null)
1788 synchronized (progressPanel)
1790 progressPanel.remove(progbar);
1791 GridLayout gl = (GridLayout) progressPanel.getLayout();
1792 gl.setRows(gl.getRows() - 1);
1793 if (--totalProgressCount < 1)
1795 this.getContentPane().remove(progressPanel);
1796 progressPanel = null;
1803 public void stopLoading()
1806 if (fileLoadingCount < 1)
1808 while (fileLoadingPanels.size() > 0)
1810 removeProgressPanel(fileLoadingPanels.remove(0));
1812 fileLoadingPanels.clear();
1813 fileLoadingCount = 0;
1818 public static int getViewCount(String alignmentId)
1820 AlignmentViewport[] aps = getViewports(alignmentId);
1821 return (aps == null) ? 0 : aps.length;
1826 * @param alignmentId
1827 * - if null, all sets are returned
1828 * @return all AlignmentPanels concerning the alignmentId sequence set
1830 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1832 if (Desktop.desktop == null)
1834 // no frames created and in headless mode
1835 // TODO: verify that frames are recoverable when in headless mode
1838 List<AlignmentPanel> aps = new ArrayList<>();
1839 AlignFrame[] frames = getAlignFrames();
1844 for (AlignFrame af : frames)
1846 for (AlignmentPanel ap : af.alignPanels)
1848 if (alignmentId == null
1849 || alignmentId.equals(ap.av.getSequenceSetId()))
1855 if (aps.size() == 0)
1859 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1864 * get all the viewports on an alignment.
1866 * @param sequenceSetId
1867 * unique alignment id (may be null - all viewports returned in that
1869 * @return all viewports on the alignment bound to sequenceSetId
1871 public static AlignmentViewport[] getViewports(String sequenceSetId)
1873 List<AlignmentViewport> viewp = new ArrayList<>();
1874 if (desktop != null)
1876 AlignFrame[] frames = Desktop.getAlignFrames();
1878 for (AlignFrame afr : frames)
1880 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1881 .equals(sequenceSetId))
1883 if (afr.alignPanels != null)
1885 for (AlignmentPanel ap : afr.alignPanels)
1887 if (sequenceSetId == null
1888 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1896 viewp.add(afr.getViewport());
1900 if (viewp.size() > 0)
1902 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1909 * Explode the views in the given frame into separate AlignFrame
1913 public static void explodeViews(AlignFrame af)
1915 int size = af.alignPanels.size();
1921 for (int i = 0; i < size; i++)
1923 AlignmentPanel ap = af.alignPanels.get(i);
1924 AlignFrame newaf = new AlignFrame(ap);
1927 * Restore the view's last exploded frame geometry if known. Multiple
1928 * views from one exploded frame share and restore the same (frame)
1929 * position and size.
1931 Rectangle geometry = ap.av.getExplodedGeometry();
1932 if (geometry != null)
1934 newaf.setBounds(geometry);
1937 ap.av.setGatherViewsHere(false);
1939 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1940 AlignFrame.DEFAULT_HEIGHT);
1943 af.alignPanels.clear();
1944 af.closeMenuItem_actionPerformed(true);
1949 * Gather expanded views (separate AlignFrame's) with the same sequence set
1950 * identifier back in to this frame as additional views, and close the
1951 * expanded views. Note the expanded frames may themselves have multiple
1952 * views. We take the lot.
1956 public void gatherViews(AlignFrame source)
1958 source.viewport.setGatherViewsHere(true);
1959 source.viewport.setExplodedGeometry(source.getBounds());
1960 JInternalFrame[] frames = desktop.getAllFrames();
1961 String viewId = source.viewport.getSequenceSetId();
1963 for (int t = 0; t < frames.length; t++)
1965 if (frames[t] instanceof AlignFrame && frames[t] != source)
1967 AlignFrame af = (AlignFrame) frames[t];
1968 boolean gatherThis = false;
1969 for (int a = 0; a < af.alignPanels.size(); a++)
1971 AlignmentPanel ap = af.alignPanels.get(a);
1972 if (viewId.equals(ap.av.getSequenceSetId()))
1975 ap.av.setGatherViewsHere(false);
1976 ap.av.setExplodedGeometry(af.getBounds());
1977 source.addAlignmentPanel(ap, false);
1983 af.alignPanels.clear();
1984 af.closeMenuItem_actionPerformed(true);
1991 jalview.gui.VamsasApplication v_client = null;
1994 public void vamsasImport_actionPerformed(ActionEvent e)
1996 if (v_client == null)
1998 // Load and try to start a session.
1999 JalviewFileChooser chooser = new JalviewFileChooser(
2000 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2002 chooser.setFileView(new JalviewFileView());
2003 chooser.setDialogTitle(
2004 MessageManager.getString("label.open_saved_vamsas_session"));
2005 chooser.setToolTipText(MessageManager.getString(
2006 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2008 int value = chooser.showOpenDialog(this);
2010 if (value == JalviewFileChooser.APPROVE_OPTION)
2012 String fle = chooser.getSelectedFile().toString();
2013 if (!vamsasImport(chooser.getSelectedFile()))
2015 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2016 MessageManager.formatMessage(
2017 "label.couldnt_import_as_vamsas_session",
2021 .getString("label.vamsas_document_import_failed"),
2022 JvOptionPane.ERROR_MESSAGE);
2028 jalview.bin.Cache.log.error(
2029 "Implementation error - load session from a running session is not supported.");
2034 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2037 * @return true if import was a success and a session was started.
2039 public boolean vamsasImport(URL url)
2041 // TODO: create progress bar
2042 if (v_client != null)
2045 jalview.bin.Cache.log.error(
2046 "Implementation error - load session from a running session is not supported.");
2052 // copy the URL content to a temporary local file
2053 // TODO: be a bit cleverer here with nio (?!)
2054 File file = File.createTempFile("vdocfromurl", ".vdj");
2055 FileOutputStream fos = new FileOutputStream(file);
2056 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2057 byte[] buffer = new byte[2048];
2059 while ((ln = bis.read(buffer)) > -1)
2061 fos.write(buffer, 0, ln);
2065 v_client = new jalview.gui.VamsasApplication(this, file,
2066 url.toExternalForm());
2067 } catch (Exception ex)
2069 jalview.bin.Cache.log.error(
2070 "Failed to create new vamsas session from contents of URL "
2075 setupVamsasConnectedGui();
2076 v_client.initial_update(); // TODO: thread ?
2077 return v_client.inSession();
2081 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2084 * @return true if import was a success and a session was started.
2086 public boolean vamsasImport(File file)
2088 if (v_client != null)
2091 jalview.bin.Cache.log.error(
2092 "Implementation error - load session from a running session is not supported.");
2096 setProgressBar(MessageManager.formatMessage(
2097 "status.importing_vamsas_session_from", new Object[]
2098 { file.getName() }), file.hashCode());
2101 v_client = new jalview.gui.VamsasApplication(this, file, null);
2102 } catch (Exception ex)
2104 setProgressBar(MessageManager.formatMessage(
2105 "status.importing_vamsas_session_from", new Object[]
2106 { file.getName() }), file.hashCode());
2107 jalview.bin.Cache.log.error(
2108 "New vamsas session from existing session file failed:", ex);
2111 setupVamsasConnectedGui();
2112 v_client.initial_update(); // TODO: thread ?
2113 setProgressBar(MessageManager.formatMessage(
2114 "status.importing_vamsas_session_from", new Object[]
2115 { file.getName() }), file.hashCode());
2116 return v_client.inSession();
2119 public boolean joinVamsasSession(String mysesid)
2121 if (v_client != null)
2123 throw new Error(MessageManager
2124 .getString("error.try_join_vamsas_session_another"));
2126 if (mysesid == null)
2129 MessageManager.getString("error.invalid_vamsas_session_id"));
2131 v_client = new VamsasApplication(this, mysesid);
2132 setupVamsasConnectedGui();
2133 v_client.initial_update();
2134 return (v_client.inSession());
2138 public void vamsasStart_actionPerformed(ActionEvent e)
2140 if (v_client == null)
2143 // we just start a default session for moment.
2145 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2146 * getProperty("LAST_DIRECTORY"));
2148 * chooser.setFileView(new JalviewFileView());
2149 * chooser.setDialogTitle("Load Vamsas file");
2150 * chooser.setToolTipText("Import");
2152 * int value = chooser.showOpenDialog(this);
2154 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2155 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2157 v_client = new VamsasApplication(this);
2158 setupVamsasConnectedGui();
2159 v_client.initial_update(); // TODO: thread ?
2163 // store current data in session.
2164 v_client.push_update(); // TODO: thread
2168 protected void setupVamsasConnectedGui()
2170 vamsasStart.setText(MessageManager.getString("label.session_update"));
2171 vamsasSave.setVisible(true);
2172 vamsasStop.setVisible(true);
2173 vamsasImport.setVisible(false); // Document import to existing session is
2174 // not possible for vamsas-client-1.0.
2177 protected void setupVamsasDisconnectedGui()
2179 vamsasSave.setVisible(false);
2180 vamsasStop.setVisible(false);
2181 vamsasImport.setVisible(true);
2183 .setText(MessageManager.getString("label.new_vamsas_session"));
2187 public void vamsasStop_actionPerformed(ActionEvent e)
2189 if (v_client != null)
2191 v_client.end_session();
2193 setupVamsasDisconnectedGui();
2197 protected void buildVamsasStMenu()
2199 if (v_client == null)
2201 String[] sess = null;
2204 sess = VamsasApplication.getSessionList();
2205 } catch (Exception e)
2207 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2213 jalview.bin.Cache.log.debug(
2214 "Got current sessions list: " + sess.length + " entries.");
2215 VamsasStMenu.removeAll();
2216 for (int i = 0; i < sess.length; i++)
2218 JMenuItem sessit = new JMenuItem();
2219 sessit.setText(sess[i]);
2220 sessit.setToolTipText(MessageManager
2221 .formatMessage("label.connect_to_session", new Object[]
2223 final Desktop dsktp = this;
2224 final String mysesid = sess[i];
2225 sessit.addActionListener(new ActionListener()
2229 public void actionPerformed(ActionEvent e)
2231 if (dsktp.v_client == null)
2233 Thread rthr = new Thread(new Runnable()
2239 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2240 dsktp.setupVamsasConnectedGui();
2241 dsktp.v_client.initial_update();
2249 VamsasStMenu.add(sessit);
2251 // don't show an empty menu.
2252 VamsasStMenu.setVisible(sess.length > 0);
2257 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2258 VamsasStMenu.removeAll();
2259 VamsasStMenu.setVisible(false);
2264 // Not interested in the content. Just hide ourselves.
2265 VamsasStMenu.setVisible(false);
2270 public void vamsasSave_actionPerformed(ActionEvent e)
2272 if (v_client != null)
2274 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2275 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2278 chooser.setFileView(new JalviewFileView());
2279 chooser.setDialogTitle(MessageManager
2280 .getString("label.save_vamsas_document_archive"));
2282 int value = chooser.showSaveDialog(this);
2284 if (value == JalviewFileChooser.APPROVE_OPTION)
2286 java.io.File choice = chooser.getSelectedFile();
2287 JPanel progpanel = addProgressPanel(MessageManager
2288 .formatMessage("label.saving_vamsas_doc", new Object[]
2289 { choice.getName() }));
2290 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2291 String warnmsg = null;
2292 String warnttl = null;
2295 v_client.vclient.storeDocument(choice);
2298 warnttl = "Serious Problem saving Vamsas Document";
2299 warnmsg = ex.toString();
2300 jalview.bin.Cache.log
2301 .error("Error Whilst saving document to " + choice, ex);
2303 } catch (Exception ex)
2305 warnttl = "Problem saving Vamsas Document.";
2306 warnmsg = ex.toString();
2307 jalview.bin.Cache.log.warn(
2308 "Exception Whilst saving document to " + choice, ex);
2311 removeProgressPanel(progpanel);
2312 if (warnmsg != null)
2314 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2316 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2322 JPanel vamUpdate = null;
2325 * hide vamsas user gui bits when a vamsas document event is being handled.
2328 * true to hide gui, false to reveal gui
2330 public void setVamsasUpdate(boolean b)
2332 Cache.log.debug("Setting gui for Vamsas update "
2333 + (b ? "in progress" : "finished"));
2335 if (vamUpdate != null)
2337 this.removeProgressPanel(vamUpdate);
2341 vamUpdate = this.addProgressPanel(
2342 MessageManager.getString("label.updating_vamsas_session"));
2344 vamsasStart.setVisible(!b);
2345 vamsasStop.setVisible(!b);
2346 vamsasSave.setVisible(!b);
2349 public JInternalFrame[] getAllFrames()
2351 return desktop.getAllFrames();
2355 * Checks the given url to see if it gives a response indicating that the user
2356 * should be informed of a new questionnaire.
2360 public void checkForQuestionnaire(String url)
2362 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2363 // javax.swing.SwingUtilities.invokeLater(jvq);
2364 new Thread(jvq).start();
2367 public void checkURLLinks()
2369 // Thread off the URL link checker
2370 addDialogThread(new Runnable()
2375 if (/** @j2sNative false && */ // BH 2018
2376 Cache.getDefault("CHECKURLLINKS", true))
2378 // check what the actual links are - if it's just the default don't
2379 // bother with the warning
2380 List<String> links = Preferences.sequenceUrlLinks
2383 // only need to check links if there is one with a
2384 // SEQUENCE_ID which is not the default EMBL_EBI link
2385 ListIterator<String> li = links.listIterator();
2386 boolean check = false;
2387 List<JLabel> urls = new ArrayList<>();
2388 while (li.hasNext())
2390 String link = li.next();
2391 if (link.contains(SEQUENCE_ID)
2392 && !UrlConstants.isDefaultString(link))
2395 int barPos = link.indexOf("|");
2396 String urlMsg = barPos == -1 ? link
2397 : link.substring(0, barPos) + ": "
2398 + link.substring(barPos + 1);
2399 urls.add(new JLabel(urlMsg));
2407 // ask user to check in case URL links use old style tokens
2408 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2409 JPanel msgPanel = new JPanel();
2410 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2411 msgPanel.add(Box.createVerticalGlue());
2412 JLabel msg = new JLabel(MessageManager
2413 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2414 JLabel msg2 = new JLabel(MessageManager
2415 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2417 for (JLabel url : urls)
2423 final JCheckBox jcb = new JCheckBox(
2424 MessageManager.getString("label.do_not_display_again"));
2425 jcb.addActionListener(new ActionListener()
2428 public void actionPerformed(ActionEvent e)
2430 // update Cache settings for "don't show this again"
2431 boolean showWarningAgain = !jcb.isSelected();
2432 Cache.setProperty("CHECKURLLINKS",
2433 Boolean.valueOf(showWarningAgain).toString());
2438 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2440 .getString("label.SEQUENCE_ID_no_longer_used"),
2441 JvOptionPane.WARNING_MESSAGE);
2448 * Proxy class for JDesktopPane which optionally displays the current memory
2449 * usage and highlights the desktop area with a red bar if free memory runs
2454 public class MyDesktopPane extends JDesktopPane
2455 implements Runnable, PropertyChangeListener
2458 public Object[] dialogData;
2462 public void propertyChange(PropertyChangeEvent event)
2464 Object val = event.getNewValue();
2465 String name = event.getPropertyName();
2466 System.out.println(name);
2467 switch (event.getSource().getClass().getName())
2469 case "javax.swing.JOptionPane":
2473 onDialogReturn(val);
2476 if (val instanceof Integer)
2478 onDialogReturn(((Integer) val).intValue());
2482 onDialogReturn(val);
2487 case "javax.swing.ColorChooserDialog":
2490 case "SelectedColor":
2491 onDialogReturn(val);
2495 case "javax.swing.JFileChooser":
2498 case "SelectedFile":
2499 // in JavaScript, this File object will have a _bytes property,
2500 // because the file data has already been loaded
2501 onDialogReturn(new Object[] { (File) val });
2506 System.out.println(event.getSource().getClass().getName() + " "
2507 + event.getPropertyName() + ": " + event.getNewValue());
2510 // JSCOmponent.DialogCaller interface
2511 void onDialogReturn(Object value)
2513 switch ((String) dialogData[0])
2515 case "SelectedFile":
2517 dialogData[0] = value;
2518 ((Runnable) dialogData[1]).run();
2520 case "label.select_feature_colour":
2521 ((FeatureRenderer) dialogData[1]).processColorDialog((Color) value);
2526 // JSCOmponent.DialogCaller interface
2527 void onDialogReturn(int value)
2529 if (value != Math.floor(value))
2531 // in JavaScript, this will be NaN, oddly enough
2535 switch ((String) dialogData[0])
2538 dialogData[0] = Integer.valueOf(value);
2539 ((Runnable) dialogData[1]).run();
2541 case "label.input_alignment_from_url":
2542 // reconstruct the parameter data
2544 AlignViewport viewport = (AlignViewport) dialogData[1];
2545 JComboBox history = (JComboBox) dialogData[2];
2546 // the rest of this is unchangaed
2547 if (reply != JvOptionPane.OK_OPTION)
2552 String url = history.getSelectedItem().toString();
2554 if (url.toLowerCase().endsWith(".jar"))
2556 if (viewport != null)
2558 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2559 FileFormat.Jalview);
2563 new FileLoader().LoadFile(url, DataSourceType.URL,
2564 FileFormat.Jalview);
2569 FileFormatI format = null;
2572 format = new IdentifyFile().identify(url, DataSourceType.URL);
2573 } catch (FileFormatException e)
2575 // TODO revise error handling, distinguish between
2576 // URL not found and response not valid
2581 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2582 MessageManager.formatMessage("label.couldnt_locate",
2585 MessageManager.getString("label.url_not_found"),
2586 JvOptionPane.WARNING_MESSAGE);
2591 if (viewport != null)
2593 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2598 new FileLoader().LoadFile(url, DataSourceType.URL, format);
2607 private static final float ONE_MB = 1048576f;
2609 boolean showMemoryUsage = false;
2613 java.text.NumberFormat df;
2615 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2618 public MyDesktopPane(boolean showMemoryUsage)
2620 showMemoryUsage(showMemoryUsage);
2623 public void showMemoryUsage(boolean showMemory)
2625 this.showMemoryUsage = showMemory;
2628 Thread worker = new Thread(this);
2634 public boolean isShowMemoryUsage()
2636 return showMemoryUsage;
2642 df = java.text.NumberFormat.getNumberInstance();
2643 df.setMaximumFractionDigits(2);
2644 runtime = Runtime.getRuntime();
2646 while (showMemoryUsage)
2650 maxMemory = runtime.maxMemory() / ONE_MB;
2651 allocatedMemory = runtime.totalMemory() / ONE_MB;
2652 freeMemory = runtime.freeMemory() / ONE_MB;
2653 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2655 percentUsage = (totalFreeMemory / maxMemory) * 100;
2657 // if (percentUsage < 20)
2659 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2661 // instance.set.setBorder(border1);
2664 // sleep after showing usage
2666 } catch (Exception ex)
2668 ex.printStackTrace();
2674 public void paintComponent(Graphics g)
2676 if (showMemoryUsage && g != null && df != null)
2678 if (percentUsage < 20)
2680 g.setColor(Color.red);
2682 FontMetrics fm = g.getFontMetrics();
2685 g.drawString(MessageManager.formatMessage("label.memory_stats",
2687 { df.format(totalFreeMemory), df.format(maxMemory),
2688 df.format(percentUsage) }),
2689 10, getHeight() - fm.getHeight());
2697 * Accessor method to quickly get all the AlignmentFrames loaded.
2699 * @return an array of AlignFrame, or null if none found
2701 public static AlignFrame[] getAlignFrames()
2703 if (Jalview.isHeadlessMode())
2705 // Desktop.desktop is null in headless mode
2706 return new AlignFrame[] { Jalview.currentAlignFrame };
2709 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2715 List<AlignFrame> avp = new ArrayList<>();
2717 for (int i = frames.length - 1; i > -1; i--)
2719 if (frames[i] instanceof AlignFrame)
2721 avp.add((AlignFrame) frames[i]);
2723 else if (frames[i] instanceof SplitFrame)
2726 * Also check for a split frame containing an AlignFrame
2728 GSplitFrame sf = (GSplitFrame) frames[i];
2729 if (sf.getTopFrame() instanceof AlignFrame)
2731 avp.add((AlignFrame) sf.getTopFrame());
2733 if (sf.getBottomFrame() instanceof AlignFrame)
2735 avp.add((AlignFrame) sf.getBottomFrame());
2739 if (avp.size() == 0)
2743 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2748 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2752 public GStructureViewer[] getJmols()
2754 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2760 List<GStructureViewer> avp = new ArrayList<>();
2762 for (int i = frames.length - 1; i > -1; i--)
2764 if (frames[i] instanceof AppJmol)
2766 GStructureViewer af = (GStructureViewer) frames[i];
2770 if (avp.size() == 0)
2774 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2779 * Add Groovy Support to Jalview
2782 public void groovyShell_actionPerformed()
2786 openGroovyConsole();
2787 } catch (Exception ex)
2789 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2790 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2792 MessageManager.getString("label.couldnt_create_groovy_shell"),
2793 MessageManager.getString("label.groovy_support_failed"),
2794 JvOptionPane.ERROR_MESSAGE);
2799 * Open the Groovy console
2801 void openGroovyConsole()
2803 if (groovyConsole == null)
2805 groovyConsole = new groovy.ui.Console();
2806 groovyConsole.setVariable("Jalview", this);
2807 groovyConsole.run();
2810 * We allow only one console at a time, so that AlignFrame menu option
2811 * 'Calculate | Run Groovy script' is unambiguous.
2812 * Disable 'Groovy Console', and enable 'Run script', when the console is
2813 * opened, and the reverse when it is closed
2815 Window window = (Window) groovyConsole.getFrame();
2816 window.addWindowListener(new WindowAdapter()
2819 public void windowClosed(WindowEvent e)
2822 * rebind CMD-Q from Groovy Console to Jalview Quit
2825 enableExecuteGroovy(false);
2831 * show Groovy console window (after close and reopen)
2833 ((Window) groovyConsole.getFrame()).setVisible(true);
2836 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2837 * and disable opening a second console
2839 enableExecuteGroovy(true);
2843 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2844 * binding when opened
2846 protected void addQuitHandler()
2848 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2849 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2850 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2852 getRootPane().getActionMap().put("Quit", new AbstractAction()
2855 public void actionPerformed(ActionEvent e)
2863 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2866 * true if Groovy console is open
2868 public void enableExecuteGroovy(boolean enabled)
2871 * disable opening a second Groovy console
2872 * (or re-enable when the console is closed)
2874 groovyShell.setEnabled(!enabled);
2876 AlignFrame[] alignFrames = getAlignFrames();
2877 if (alignFrames != null)
2879 for (AlignFrame af : alignFrames)
2881 af.setGroovyEnabled(enabled);
2887 * Progress bars managed by the IProgressIndicator method.
2889 private Hashtable<Long, JPanel> progressBars;
2891 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2896 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2899 public void setProgressBar(String message, long id)
2901 if (progressBars == null)
2903 progressBars = new Hashtable<>();
2904 progressBarHandlers = new Hashtable<>();
2907 if (progressBars.get(new Long(id)) != null)
2909 JPanel panel = progressBars.remove(new Long(id));
2910 if (progressBarHandlers.contains(new Long(id)))
2912 progressBarHandlers.remove(new Long(id));
2914 removeProgressPanel(panel);
2918 progressBars.put(new Long(id), addProgressPanel(message));
2925 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2926 * jalview.gui.IProgressIndicatorHandler)
2929 public void registerHandler(final long id,
2930 final IProgressIndicatorHandler handler)
2932 if (progressBarHandlers == null
2933 || !progressBars.containsKey(new Long(id)))
2935 throw new Error(MessageManager.getString(
2936 "error.call_setprogressbar_before_registering_handler"));
2938 progressBarHandlers.put(new Long(id), handler);
2939 final JPanel progressPanel = progressBars.get(new Long(id));
2940 if (handler.canCancel())
2942 JButton cancel = new JButton(
2943 MessageManager.getString("action.cancel"));
2944 final IProgressIndicator us = this;
2945 cancel.addActionListener(new ActionListener()
2949 public void actionPerformed(ActionEvent e)
2951 handler.cancelActivity(id);
2952 us.setProgressBar(MessageManager
2953 .formatMessage("label.cancelled_params", new Object[]
2954 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2958 progressPanel.add(cancel, BorderLayout.EAST);
2964 * @return true if any progress bars are still active
2967 public boolean operationInProgress()
2969 if (progressBars != null && progressBars.size() > 0)
2977 * This will return the first AlignFrame holding the given viewport instance.
2978 * It will break if there are more than one AlignFrames viewing a particular
2982 * @return alignFrame for viewport
2984 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2986 if (desktop != null)
2988 AlignmentPanel[] aps = getAlignmentPanels(
2989 viewport.getSequenceSetId());
2990 for (int panel = 0; aps != null && panel < aps.length; panel++)
2992 if (aps[panel] != null && aps[panel].av == viewport)
2994 return aps[panel].alignFrame;
3001 public VamsasApplication getVamsasApplication()
3008 * flag set if jalview GUI is being operated programmatically
3010 private boolean inBatchMode = false;
3013 * check if jalview GUI is being operated programmatically
3015 * @return inBatchMode
3017 public boolean isInBatchMode()
3023 * set flag if jalview GUI is being operated programmatically
3025 * @param inBatchMode
3027 public void setInBatchMode(boolean inBatchMode)
3029 this.inBatchMode = inBatchMode;
3032 public void startServiceDiscovery()
3034 startServiceDiscovery(false);
3037 public void startServiceDiscovery(boolean blocking)
3039 boolean alive = true;
3040 Thread t0 = null, t1 = null, t2 = null;
3041 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3044 // todo: changesupport handlers need to be transferred
3045 if (discoverer == null)
3047 discoverer = new jalview.ws.jws1.Discoverer();
3048 // register PCS handler for desktop.
3049 discoverer.addPropertyChangeListener(changeSupport);
3051 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3052 // until we phase out completely
3053 (t0 = new Thread(discoverer)).start();
3056 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3058 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3059 .startDiscoverer(changeSupport);
3063 // TODO: do rest service discovery
3072 } catch (Exception e)
3075 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3076 || (t3 != null && t3.isAlive())
3077 || (t0 != null && t0.isAlive());
3083 * called to check if the service discovery process completed successfully.
3087 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3089 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3091 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3092 .getErrorMessages();
3095 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3097 if (serviceChangedDialog == null)
3099 // only run if we aren't already displaying one of these.
3100 addDialogThread(serviceChangedDialog = new Runnable()
3107 * JalviewDialog jd =new JalviewDialog() {
3109 * @Override protected void cancelPressed() { // TODO
3110 * Auto-generated method stub
3112 * }@Override protected void okPressed() { // TODO
3113 * Auto-generated method stub
3115 * }@Override protected void raiseClosed() { // TODO
3116 * Auto-generated method stub
3118 * } }; jd.initDialogFrame(new
3119 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3120 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3121 * + " or mis-configured HTTP proxy settings.<br/>" +
3122 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3124 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3125 * ), true, true, "Web Service Configuration Problem", 450,
3128 * jd.waitForInput();
3130 JvOptionPane.showConfirmDialog(Desktop.desktop,
3131 new JLabel("<html><table width=\"450\"><tr><td>"
3132 + ermsg + "</td></tr></table>"
3133 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3134 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3135 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3136 + " Tools->Preferences dialog box to change them.</p></html>"),
3137 "Web Service Configuration Problem",
3138 JvOptionPane.DEFAULT_OPTION,
3139 JvOptionPane.ERROR_MESSAGE);
3140 serviceChangedDialog = null;
3149 "Errors reported by JABA discovery service. Check web services preferences.\n"
3156 private Runnable serviceChangedDialog = null;
3159 * start a thread to open a URL in the configured browser. Pops up a warning
3160 * dialog to the user if there is an exception when calling out to the browser
3165 public static void showUrl(final String url)
3167 showUrl(url, Desktop.instance);
3171 * Like showUrl but allows progress handler to be specified
3175 * (null) or object implementing IProgressIndicator
3177 public static void showUrl(final String url,
3178 final IProgressIndicator progress)
3180 new Thread(new Runnable()
3187 if (progress != null)
3189 progress.setProgressBar(MessageManager
3190 .formatMessage("status.opening_params", new Object[]
3191 { url }), this.hashCode());
3193 jalview.util.BrowserLauncher.openURL(url);
3194 } catch (Exception ex)
3196 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3198 .getString("label.web_browser_not_found_unix"),
3199 MessageManager.getString("label.web_browser_not_found"),
3200 JvOptionPane.WARNING_MESSAGE);
3202 ex.printStackTrace();
3204 if (progress != null)
3206 progress.setProgressBar(null, this.hashCode());
3212 public static WsParamSetManager wsparamManager = null;
3214 public static ParamManager getUserParameterStore()
3216 if (wsparamManager == null)
3218 wsparamManager = new WsParamSetManager();
3220 return wsparamManager;
3224 * static hyperlink handler proxy method for use by Jalview's internal windows
3228 public static void hyperlinkUpdate(HyperlinkEvent e)
3230 if (e.getEventType() == EventType.ACTIVATED)
3235 url = e.getURL().toString();
3236 Desktop.showUrl(url);
3237 } catch (Exception x)
3241 if (Cache.log != null)
3243 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3248 "Couldn't handle string " + url + " as a URL.");
3251 // ignore any exceptions due to dud links.
3258 * single thread that handles display of dialogs to user.
3260 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3263 * flag indicating if dialogExecutor should try to acquire a permit
3265 private volatile boolean dialogPause = true;
3270 private java.util.concurrent.Semaphore block = new Semaphore(0);
3272 private static groovy.ui.Console groovyConsole;
3275 * add another dialog thread to the queue
3279 public void addDialogThread(final Runnable prompter)
3281 dialogExecutor.submit(new Runnable()
3291 } catch (InterruptedException x)
3296 if (instance == null)
3302 SwingUtilities.invokeAndWait(prompter);
3303 } catch (Exception q)
3305 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3311 public void startDialogQueue()
3313 // set the flag so we don't pause waiting for another permit and semaphore
3314 // the current task to begin
3315 dialogPause = false;
3320 protected void snapShotWindow_actionPerformed(ActionEvent e)
3324 ImageMaker im = new jalview.util.ImageMaker(
3325 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3326 getHeight(), of = new File("Jalview_snapshot"
3327 + System.currentTimeMillis() + ".eps"),
3328 "View of desktop", null, 0, false);
3331 paintAll(im.getGraphics());
3333 } catch (Exception q)
3335 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3339 Cache.log.info("Successfully written snapshot to file "
3340 + of.getAbsolutePath());
3344 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3345 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3346 * and location last time the view was expanded (if any). However it does not
3347 * remember the split pane divider location - this is set to match the
3348 * 'exploding' frame.
3352 public void explodeViews(SplitFrame sf)
3354 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3355 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3356 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3358 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3360 int viewCount = topPanels.size();
3367 * Processing in reverse order works, forwards order leaves the first panels
3368 * not visible. I don't know why!
3370 for (int i = viewCount - 1; i >= 0; i--)
3373 * Make new top and bottom frames. These take over the respective
3374 * AlignmentPanel objects, including their AlignmentViewports, so the
3375 * cdna/protein relationships between the viewports is carried over to the
3378 * explodedGeometry holds the (x, y) position of the previously exploded
3379 * SplitFrame, and the (width, height) of the AlignFrame component
3381 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3382 AlignFrame newTopFrame = new AlignFrame(topPanel);
3383 newTopFrame.setSize(oldTopFrame.getSize());
3384 newTopFrame.setVisible(true);
3385 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3386 .getExplodedGeometry();
3387 if (geometry != null)
3389 newTopFrame.setSize(geometry.getSize());
3392 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3393 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3394 newBottomFrame.setSize(oldBottomFrame.getSize());
3395 newBottomFrame.setVisible(true);
3396 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3397 .getExplodedGeometry();
3398 if (geometry != null)
3400 newBottomFrame.setSize(geometry.getSize());
3403 topPanel.av.setGatherViewsHere(false);
3404 bottomPanel.av.setGatherViewsHere(false);
3405 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3407 if (geometry != null)
3409 splitFrame.setLocation(geometry.getLocation());
3411 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3415 * Clear references to the panels (now relocated in the new SplitFrames)
3416 * before closing the old SplitFrame.
3419 bottomPanels.clear();
3424 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3425 * back into the given SplitFrame as additional views. Note that the gathered
3426 * frames may themselves have multiple views.
3430 public void gatherViews(GSplitFrame source)
3433 * special handling of explodedGeometry for a view within a SplitFrame: - it
3434 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3435 * height) of the AlignFrame component
3437 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3438 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3439 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3440 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3441 myBottomFrame.viewport
3442 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3443 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3444 myTopFrame.viewport.setGatherViewsHere(true);
3445 myBottomFrame.viewport.setGatherViewsHere(true);
3446 String topViewId = myTopFrame.viewport.getSequenceSetId();
3447 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3449 JInternalFrame[] frames = desktop.getAllFrames();
3450 for (JInternalFrame frame : frames)
3452 if (frame instanceof SplitFrame && frame != source)
3454 SplitFrame sf = (SplitFrame) frame;
3455 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3456 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3457 boolean gatherThis = false;
3458 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3460 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3461 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3462 if (topViewId.equals(topPanel.av.getSequenceSetId())
3463 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3466 topPanel.av.setGatherViewsHere(false);
3467 bottomPanel.av.setGatherViewsHere(false);
3468 topPanel.av.setExplodedGeometry(
3469 new Rectangle(sf.getLocation(), topFrame.getSize()));
3470 bottomPanel.av.setExplodedGeometry(
3471 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3472 myTopFrame.addAlignmentPanel(topPanel, false);
3473 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3479 topFrame.getAlignPanels().clear();
3480 bottomFrame.getAlignPanels().clear();
3487 * The dust settles...give focus to the tab we did this from.
3489 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3492 public static groovy.ui.Console getGroovyConsole()
3494 return groovyConsole;
3498 * handles the payload of a drag and drop event.
3500 * TODO refactor to desktop utilities class
3503 * - Data source strings extracted from the drop event
3505 * - protocol for each data source extracted from the drop event
3509 * - the payload from the drop event
3512 public static void transferFromDropTarget(List<Object> files,
3513 List<DataSourceType> protocols, DropTargetDropEvent evt,
3514 Transferable t) throws Exception
3517 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3519 // DataFlavor[] flavors = t.getTransferDataFlavors();
3520 // for (int i = 0; i < flavors.length; i++) {
3521 // if (flavors[i].isFlavorJavaFileListType()) {
3522 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3523 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3524 // for (int j = 0; j < list.size(); j++) {
3525 // File file = (File) list.get(j);
3526 // byte[] data = getDroppedFileBytes(file);
3527 // fileName.setText(file.getName() + " - " + data.length + " " + evt.getLocation());
3528 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3529 // target.setText(new String(data));
3531 // dtde.dropComplete(true);
3536 DataFlavor uriListFlavor = new DataFlavor(
3537 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3540 urlFlavour = new DataFlavor(
3541 "application/x-java-url; class=java.net.URL");
3542 } catch (ClassNotFoundException cfe)
3544 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3547 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3552 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3553 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3554 // means url may be null.
3557 protocols.add(DataSourceType.URL);
3558 files.add(url.toString());
3559 Cache.log.debug("Drop handled as URL dataflavor "
3560 + files.get(files.size() - 1));
3565 if (Platform.isAMac())
3568 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3572 } catch (Throwable ex)
3574 Cache.log.debug("URL drop handler failed.", ex);
3577 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3579 // Works on Windows and MacOSX
3580 Cache.log.debug("Drop handled as javaFileListFlavor");
3581 for (Object file : (List) t
3582 .getTransferData(DataFlavor.javaFileListFlavor))
3585 protocols.add(DataSourceType.FILE);
3590 // Unix like behaviour
3591 boolean added = false;
3593 if (t.isDataFlavorSupported(uriListFlavor))
3595 Cache.log.debug("Drop handled as uriListFlavor");
3596 // This is used by Unix drag system
3597 data = (String) t.getTransferData(uriListFlavor);
3601 // fallback to text: workaround - on OSX where there's a JVM bug
3602 Cache.log.debug("standard URIListFlavor failed. Trying text");
3603 // try text fallback
3604 DataFlavor textDf = new DataFlavor(
3605 "text/plain;class=java.lang.String");
3606 if (t.isDataFlavorSupported(textDf))
3608 data = (String) t.getTransferData(textDf);
3611 Cache.log.debug("Plain text drop content returned "
3612 + (data == null ? "Null - failed" : data));
3617 while (protocols.size() < files.size())
3619 Cache.log.debug("Adding missing FILE protocol for "
3620 + files.get(protocols.size()));
3621 protocols.add(DataSourceType.FILE);
3623 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3624 data, "\r\n"); st.hasMoreTokens();)
3627 String s = st.nextToken();
3628 if (s.startsWith("#"))
3630 // the line is a comment (as per the RFC 2483)
3633 java.net.URI uri = new java.net.URI(s);
3634 if (uri.getScheme().toLowerCase().startsWith("http"))
3636 protocols.add(DataSourceType.URL);
3637 files.add(uri.toString());
3641 // otherwise preserve old behaviour: catch all for file objects
3642 java.io.File file = new java.io.File(uri);
3643 protocols.add(DataSourceType.FILE);
3644 files.add(file.toString());
3649 if (Cache.log.isDebugEnabled())
3651 if (data == null || !added)
3654 if (t.getTransferDataFlavors() != null
3655 && t.getTransferDataFlavors().length > 0)
3658 "Couldn't resolve drop data. Here are the supported flavors:");
3659 for (DataFlavor fl : t.getTransferDataFlavors())
3662 "Supported transfer dataflavor: " + fl.toString());
3663 Object df = t.getTransferData(fl);
3666 Cache.log.debug("Retrieves: " + df);
3670 Cache.log.debug("Retrieved nothing");
3676 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3682 if (Platform.isWindows())
3685 Cache.log.debug("Scanning dropped content for Windows Link Files");
3687 // resolve any .lnk files in the file drop
3688 for (int f = 0; f < files.size(); f++)
3690 String source = files.get(f).toString().toLowerCase();
3691 if (protocols.get(f).equals(DataSourceType.FILE)
3692 && (source.endsWith(".lnk") || source.endsWith(".url")
3693 || source.endsWith(".site")))
3696 Object obj = files.get(f);
3697 File lf = (obj instanceof File ? (File) obj : new File((String) obj));
3698 // process link file to get a URL
3699 Cache.log.debug("Found potential link file: " + lf);
3700 WindowsShortcut wscfile = new WindowsShortcut(lf);
3701 String fullname = wscfile.getRealFilename();
3702 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3703 files.set(f, fullname);
3704 Cache.log.debug("Parsed real filename " + fullname
3705 + " to extract protocol: " + protocols.get(f));
3707 catch (Exception ex)
3709 Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
3717 * Sets the Preferences property for experimental features to True or False
3718 * depending on the state of the controlling menu item
3721 protected void showExperimental_actionPerformed(boolean selected)
3723 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3727 * Answers a (possibly empty) list of any structure viewer frames (currently
3728 * for either Jmol or Chimera) which are currently open. This may optionally
3729 * be restricted to viewers of a specified class, or viewers linked to a
3730 * specified alignment panel.
3733 * if not null, only return viewers linked to this panel
3734 * @param structureViewerClass
3735 * if not null, only return viewers of this class
3738 public List<StructureViewerBase> getStructureViewers(
3739 AlignmentPanel apanel,
3740 Class<? extends StructureViewerBase> structureViewerClass)
3742 List<StructureViewerBase> result = new ArrayList<>();
3743 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3745 for (JInternalFrame frame : frames)
3747 if (frame instanceof StructureViewerBase)
3749 if (structureViewerClass == null
3750 || structureViewerClass.isInstance(frame))
3753 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3755 result.add((StructureViewerBase) frame);